Using strcmp() in my cgi code, for an html webpage, is causing a server error - html

I am making an html webpage that uses cgi to access a table/database in mysql. I input a .csv file containing info on my class schedule and the html displays it in the usual schedule table.
My problem is that I can't seem to use strcmp in my parsing cgi as it causes a server error. here is an excerpt of my code where I uses strcmp.
void parse2(char *queu)
{
//---------------------------------------------------------------
char *saveptr[1024];
char *subtoken;
char *Subject;
char *Day;
char *Start;
char *End;
char *Room;
char *Teacher;
int check = 1;
//---------------------------------------------------------------
subtoken = strtok_r(queu, ",", saveptr);
check = strcmp(subtoken, "\0");
printf("%d<br>", check);
if(check == 0){
printf("Error!");
} else {
Subject = subtoken;
Day = strtok_r(NULL, ",", saveptr);
Start = strtok_r(NULL, ",", saveptr);
End = strtok_r(NULL, ",", saveptr);
Room = strtok_r(NULL, ",", saveptr);
Teacher = strtok_r(NULL, ",", saveptr);
printf("%s\n<br/>%s\n<br/>%s\n<br/>%s\n<br/>%s\n<br/>%s\n", Subject, Day, Start, End, Room, Teacher);
//inputsql(Subject, Day, Start, End, Room, Teacher);
}
//---------------------------------------------------------------
}
Note that, I have tested this code and it works fine without me calling strcmp().
I am using strcmp() to prevent a line of unwanted characters, generated after the info when retrieved using POST method, from being entered into my database.
As you can see from the above code, I used strtok() to parse the line of info. Since the line of unwanted characters do not contain a comma (which is my delimiter) it should return a NULL value. correct?
Can anyone help me out? I welcome suggestions to use a different way on solving the problem I chose to solve using strcmp().

I think you should be checking subtoken == NULL, not strcmp(subtoken, "\0") == 0.
"\0" is a string containing a NUL byte, then another NUL (the terminator), so the standard library's string functions will just see an empty string. That's different to a NULL pointer (i.e. a pointer with value zero).
From STRTOK(3):
Each call to strtok() returns a pointer to a null-terminated string
containing the next token. This string does not include the
delimiting byte. If no more tokens are found, strtok() returns NULL.

Related

Trying to copy char pointer to "QUERY_STRING" to a char[] variable, getting wrong result

I am working with FastCgi, trying to generate a dynamic html webpage.
I am able to get the QUERY_STRING easily enough, but I am having trouble trying to copy it into a char array.
If there is even a shorter way of just getting the value from QUERY_STRING, please advise because I am a little over my head.
char *queryString = getenv(ENV_VARS[7]);
char newDeviceName[64];
strncpy( newDeviceName, *queryString, sizeof(*queryString) -1);
printf("------- %c ------------", newDeviceName);
This compiles with only warnings, but once i try to load the webpage, the characters are some weird Chinese looking characters. -> �ፙ�
Thank you in advance.
EDIT: More of my code
const char *ENV_VARS[] = {
"DOCUMENT_ROOT",
"HTTP_COOKIE",
"HTTP_HOST",
"HTTP_REFERER",
"HTTP_USER_AGENT",
"HTTPS",
"PATH",
"QUERY_STRING",
"REMOTE_ADDR",
"REMOTE_HOST",
"REMOTE_PORT",
"REMOTE_USER",
"REQUEST_METHOD",
"REQUEST_URI",
"SCRIPT_FILENAME",
"SCRIPT_NAME",
"SERVER_ADMIN",
"SERVER_NAME",
"SERVER_PORT",
"SERVER_SOFTWARE"
};
int main(void)
{
char deviceName[]=ADAPTERNAME;
time_t t;
/* Intializes random number generator */
srand((unsigned) time(&t));
while (FCGI_Accept() >= 0) {
printf("Content-type: text/html \r\n\r\n");
printf("");
printf("<html>\n");
printf("<script src=\"/js/scripts.js\"></script>");
/* CODE CODE CODE */
printf("<p> hi </p>");
printf("<p> hi </p>");
char *queryString = getenv(ENV_VARS[7]);
char newDeviceName[64];
if (queryString == NULL)
printf("<p> +++++ERROR++++++ </p>");
else {
strcpy( newDeviceName, queryString);
newDeviceName[sizeof(newDeviceName) - 1] = 0;
printf("<p> ------- %s ------------ </p> ", newDeviceName);
}
SOLVED: Amateur mistake, for some reason none of my new edits went into effect until after i restart my lighttpd server.
Your program has undefined behavior. Read those warnings issued by the compiler. They're important.
Don't dereference the pointer when you're passing the string to strncpy(). When you do that, you're now passing a single char. That's converted to a pointer when it's given to strncpy() (which is where you probably get your warning, i.e. passing a char to a function that expects a char*).
You also can't get the size of an array that has decayed to a pointer using sizeof. You're just getting the size of the pointer (which is probably either 8 or 4 bytes depending on your system). Since you don't know the length of the string anyway, it might even be better to just use strcpy() instead of strncpy().
Here's what your code probably should look like:
char *queryString = getenv(ENV_VARS[7]);
char newDeviceName[64];
strcpy( newDeviceName, queryString);
printf("------- %s ------------", newDeviceName); /* use %s to print strings */
The length on your strncpy is wrong [too short], the second argument is wrong, and the format string is incorrect.
Try this:
strncpy( newDeviceName, queryString, sizeof(newDeviceName) - 1);
newDeviceName[sizeof(newDeviceName) - 1] = 0;
printf("------- %s ------------", newDeviceName);
In the call to strncpy, it expects a char * for the second argument, but you pass it a char.
Also, the size is not correct. *queryString is a char and has size 1. Using sizeof(queryString) is not correct either because it will return the size of a pointer. What you actually want is the size of the detination buffer.
In the printf call the %c format specifier expects a char but you pass it a char *. You should instead use %s which expects a char * pointing to a null terminated string.
So what you want to do is this:
strncpy( newDeviceName, queryString, sizeof(newDeviceName) -1);
newDeviceName[sizeof(newDeviceName) - 1] = 0;
printf("------- %s ------------", newDeviceName);
What you want is
strncpy(newDeviceName, queryString, sizeof(newDeviceName)-1);
newDeviceName[63] = '\0'; // Guarantee NUL terminator
printf("----- %s -----", newDeviceName);
So multiple problems:
*queryString just gets you the first character, which strncpy tries to treat as a pointer.
sizeof(*queryString) is the size of a char (i.e. 1)
%c prints a single character, not the string

MySQL query based on user input in c

how to take input from user in c and use this input in where clause of mysql statement
int main(){
char *input;
scanf("%s",input);
mysql_quer(con,"select * from < tablename > where < column > = input ");
}
char *input;
scanf("%s",input);
This is a problem. input is just a pointer to somewhere, it's not an actual buffer that can store input, and it's not automatically pointing anywhere meaningful. You should set aside a buffer to store your input:
#define BUFFER_SIZE 20 // or however big you need your buffer to be
...
char input[BUFFER_SIZE + 1];
if ( fgets( input, sizeof input, stdin ) )
{
/**
* fgets doesn't strip the trailing newline
*/
char *newline = strchr( input, '\n' );
if ( newline )
*newline = 0;
// use input
}
else
{
// error or EOF on input
}
scanf is not a great tool for interactive input, and the %s conversion specifier opens the same security hole that gets used to - if the user types in more characters than the buffer is sized to hold, then C will happily store those extra characters to the memory following the buffer, potentially clobbering something important.
If your heart is set on using scanf, then you need to provide an explicit maximum input size as part of the %s specifier, like %20s. Unfortunately, such maximum input sizes must be hardcoded in the format; scanf doesn't have a way for you to provide it as an argument the way printf does. You can use the following nonsense to work around it:
#define BUFFER_SIZE 20
#define STR(x) #x
#define FMT(len) "%" STR(len) "s"
...
scanf( FMT(BUFFER_SIZE), input );
It's just easier to use fgets (and fgets allows for blank spaces in the input, whereas the %s conversion specifier will stop reading after the first whitespace character). Tradeoff is that you have to handle the trailing newline.
mysql_quer(con,"select * from where = input ");
You never want to pass user input directly to a SQL statement; see the parable of little Bobby Tables for why. You'll want to do some sanity checking on your inputs (make sure there are no ';' or ''' characters at least). Although it's a bit of work, you'd probably want to use a prepared statement - here's an example.
Use sprintf() to insert the input variable into the SQL string. And the value has to be in quotes if it's a string. Also, you never allocated space for input.
char input[BUFSIZ];
char sql[BUFSIZ];
scanf("%s", input);
sprintf(sql, "select * from tablename where column = '%s' ", input);
mysql_query(con, sql);

Escape characters getting inserted into database

I am inserting arbitrary binary data into a mysql database MEDIUMBLOB using the below code. I am writing the same data to a file, from the same program. I then create a file from the DB contents:
select data from table where tag=95 order by date, time into outfile "dbout";
I then compare the output written directly to the file to the output in dbout. There are escape (0x5c, '\') characters before some bytes in the dbout file (e.g. before 0x00). This garbles the output from the database. My understanding was that by using a MEDIUMBLOB and prepared statements, I could avoid this problem. Initially I was using mysql_real_escape_string with a regular INSERT, and having the problem. Nothing seems to be fixing this.
void
insertdb(int16_t *data, size_t size, size_t nmemb)
{
int16_t *fwbuf; // I have also tried this as char *fwbuf
unsigned long i;
struct tm *info;
time_t rawtime;
char dbuf[12];
char tbuf[12];
if(fwinitialized==0){
fwbuf = malloc(CHUNK_SZ);
fwinitialized = 1;
}
if(fwindex + (nmemb*size) + 1 >= CHUNK_SZ || do_exit == 1){
MYSQL_STMT *stmt = mysql_stmt_init(con);
MYSQL_BIND param[1];
time(&rawtime);
info = localtime(&rawtime);
snprintf(dbuf, 16, "%d-%02d-%02d", 1900+info->tm_year, 1+info->tm_mon, info->tm_mday);
snprintf(tbuf, 16, "%02d:%02d:%02d", info->tm_hour, info->tm_min, info->tm_sec);
char *tmp = "INSERT INTO %s (date, time, tag, data) VALUES ('%s', '%s', %d, ?)";
int len = strlen(tmp)+strlen(db_mon_table)+strlen(dbuf)+strlen(tbuf)+MAX_TAG_LEN+1;
char *sql = (char *) malloc(len);
int sqllen = snprintf(sql, len, tmp, db_mon_table, dbuf, tbuf, tag);
if(mysql_stmt_prepare(stmt, sql, strlen(sql)) != 0){
printf("Unable to create session: mysql_stmt_prepare()\n");
exit(1);
}
memset(param, 0, sizeof(param));
param[0].buffer_type = MYSQL_TYPE_MEDIUM_BLOB;
param[0].buffer = fwbuf;
param[0].is_unsigned = 0;
param[0].is_null = 0;
param[0].length = &fwindex;
if(mysql_stmt_bind_param(stmt, param) != 0){
printf("Unable to create session: mysql_stmt_bind_param()\n");
exit(1);
}
if(mysql_stmt_execute(stmt) != 0){
printf("Unabel to execute session: mysql_stmt_execute()\n");
exit(1);
}
printf("closing\n");
mysql_stmt_close(stmt);
free(sql);
fwindex = 0;
} else {
memcpy((void *) fwbuf+fwindex, (void *) data, nmemb*size);
fwindex += (nmemb*size);
}
}
So, why the escape characters in the database? I have tried a couple of combinations of hex/unhex in the program and when creating the file from msyql. That didn't seem to help either. Isn't inserting arbitrary binary data into a database be a common thing with a well-defined solution?
P.S. - Is it ok to have prepared statements that open, insert, and close like this, or are prepared statements generally for looping and inserting a bunch of data before closing?
PPS - Maybe this is important to the problem: When I try to use UNHEX like this:
select unhex(data) from table where tag=95 order by date, time into outfile "dbout";
the output is very short (less than a dozen bytes, truncated for some reason).
As MEDIUMBLOB can contain any character (even an ASCII NUL) MySQL normally escapes the output so you can tell when fields end. You can control this using ESCAPED BY. The documentation is here. Below is an excerpt. According to the last paragraph below (which I've put in bold), you can entirely disable escaping. I have never tried that, for the reason in the last sentence.
FIELDS ESCAPED BY controls how to write special characters. If the FIELDS ESCAPED BY character is not empty, it is used when necessary to avoid ambiguity as a prefix that precedes following characters on output:
The FIELDS ESCAPED BY character
The FIELDS [OPTIONALLY] ENCLOSED BY character
The first character of the FIELDS TERMINATED BY and LINES TERMINATED BY values
ASCII NUL (the zero-valued byte; what is actually written following the escape character is ASCII "0", not a zero-valued byte)
The FIELDS TERMINATED BY, ENCLOSED BY, ESCAPED BY, or LINES TERMINATED BY characters must be escaped so that you can read the file back in reliably. ASCII NUL is escaped to make it easier to view with some pagers.
The resulting file does not have to conform to SQL syntax, so nothing else need be escaped.
If the FIELDS ESCAPED BY character is empty, no characters are escaped and NULL is output as NULL, not \N. It is probably not a good idea to specify an empty escape character, particularly if field values in your data contain any of the characters in the list just given.
A better strategy (if you only need one blob in the output file) is SELECT INTO ... DUMPFILE, documented on the same page, per the below:
If you use INTO DUMPFILE instead of INTO OUTFILE, MySQL writes only one row into the file, without any column or line termination and without performing any escape processing. This is useful if you want to store a BLOB value in a file.

Inserting variable in mysql with visual studio CLR / C

I used mysql connector and extract data from Database in visual studio 2010. Also inserted data successfully as value. But was fail to insert data with variable. Need a help, please.
this one worked.
mysql_query(connect,"INSERT INTO input VALUES(111,'Bangladesh','Khulna','Male','Muhammad Ashikuzzaman KUET','b+')");
But this are not working.
str="Muhammad Ashikuzzaman KUET";
mysql_query(connect,"INSERT INTO input VALUES(111,'Bangladesh','Khulna','Male','#str','b+')");
or
mysql_query(connect,"INSERT INTO input VALUES(111,'Bangladesh','Khulna','Male',#str,'b+')");
Please suggest a solution.
You have to create the string before calling mysql_query():
char statement[512], *str = "Muhammad Ashikuzzaman KUET";
snprintf(statement, sizeof statement, "INSERT INTO input VALUES(111,'Bangladesh','Khulna','Male','%s','b+')", str);
mysql_query(connect, statement);
Also, be careful when creating those query strings. Don't use functions like sprintf() if you cannot be sure how long the resulting string is. Don't write over the boundaries of the memory segment.
Edit
For precaution, You can use mysql_real_escape_string() additionally if the string usually comes from arbitrary sources:
int insertData(MYSQL *connect, char *str, int str_len) {
if (str_len < 0) {
str_len = strlen(str);
}
char esc[2 * str_len + 1];
unsigned long esclen = mysql_real_escape_string(connect, esc, str, str_len);
char statement[512];
snprintf(statement, sizeof statement, "INSERT INTO input VALUES(111,'Bangladesh','Khulna','Male','%s','b+')", esc);
return mysql_query(connect, statement);
}
Also here I've assumed your input string is small enough to fit into 512 characters string. Practically, it won't work. So declare statement length variable according to input string length plus some extra length to fit with the query string together.

libxml split text nodes at spaces

I am using libxml's HTML parser to create a dom tree of html documents. libxml gives text content of each node as a monolithic string (node), but my requirement is to further split each text node at spaces and create as many as word nodes. thus far I haven't found any options from libxml so I created a cpu expensive logic to split text nodes. Below is the part of recursive method that works.
void parse(xmlNodePtr cur, El*& parent) {
if (!cur) {
return;
}
string tagName = (const char*) cur->name;
string content = node_text(cur); // function defined below
Element* el = new Element(tagName, content);
parent->childs.push_back(el);
size_t pos;
string text;
cur = cur->children;
while (cur != NULL) {
if (xmlNodeIsText(cur) && (pos = node_text_find(cur, text, " ")) != string::npos) {
string first = text.substr(0, pos);
string second = text.substr(pos + 1);
El *el1 = new Element("text", first);
el->childs.push_back(el1);
El *el2 = new Element("text", " ");
el->childs.push_back(el2);
xmlNodeSetContent(cur, BAD_CAST second.c_str());
continue;
}
parse(cur, el);
cur = cur->next;
}
}
string node_text(xmlNodePtr cur) {
string content;
if (xmlNodeIsText(cur)) {
xmlChar *buf = xmlNodeGetContent(cur);
content = (const char*) buf;
}
return content;
}
size_t node_text_find(xmlNodePtr cur, string& text, string what){
text = node_text(cur);
return text.find_first_of(what);
}
The problem with above code is it didnt work for some UTF string like chinese language and moreover this code adds up time in overall parsing process.
Can anyone suggest a better way of doing this, thank you in advance !
I don't have a complete answer but I did see you doing explicit casts of xmlChar to char. That is a bad sign and probably why it doesn't work on Unicode.
If you're dealing with Unicode, which xmlChar probably is, you need to be using Unicode text processing libraries. Not std::string.
You actually have two choices. Find a library which processes in UTF-8 or convert UTF-8 into wchar (wide characters). If you convert to wchar then you can use wstring and its functions to process Unicode.
libxml2 xmlChar * to std::wstring looks like a useful answer.
As for speed, do my eyes deceive me or are you splitting on one space and creating a new element which you then split again? This is not the way to performance. I think it would go better if you remove the text node, split all of the words out and add the new nodes as you go.
The slowdown is most likely in the repeated creation, copying and destruction of objects. Work to minimize that. For example, if Element had a constructor form that accepted a begin/end iterator pair, or a start, length pair, that would be more efficient than creating a substring (copy!) and creating an Element (copy!) and then destroying the substrings.
The repeated calling of xmlNodeSetContent with the (probably large) second half of the text string, is giving you O2 performance. Not good.