sprintf and % signs in text - php

A problem I recently ran into was that when trying to update a field in my database using this code would not work. I traced it back to having a % sign in the text being updated ($note, then $note_escaped)... Inserting it with sprintf worked fine though.
Should I not be using sprintf for updates, or should it be formed differently?
I did some searching but couldn't come up with anything.
$id = mysql_real_escape_string($id);
$note_escaped = mysql_real_escape_string($note);
$editedby = mysql_real_escape_string($author);
$editdate = mysql_real_escape_string($date);
//insert info from form into database
$query= sprintf("UPDATE notes_$suffix SET note='$note_escaped', editedby='$editedby', editdate='$editdate' WHERE id='$id' LIMIT 1");

You are using sprintf totally wrong. Removing the function call in your code would still do the same thing. It should be:
sprintf("UPDATE notes_%s SET note='%s', editedby='%s', editdate='%s' WHERE id=%d LIMIT 1", $suffix, $note_escaped, $editedby, $editdate, $id);
You should read the manual.

first of all you should be using prepared statements instead of a sprintf-call
but if you absolutely have to do it this way you have to use:
$id = mysql_real_escape_string($id);
$note_escaped = mysql_real_escape_string($note);
$editedby = mysql_real_escape_string($author);
$editdate = mysql_real_escape_string($date);
//insert info from form into database
$query= sprintf("
UPDATE notes_%s /* this is still open for injection, and cannot be properly escaped with mysql_real_escape_string */
SET note='%s',
editedby='%s',
editdate='%s'
WHERE id='%d'
LIMIT 1",
$suffix,
$note_escaped, $editedby, $editdate, $id);

You can escape the % in the source text by replacing it with \% in mysql.

sprintf() is not used much in PHP, unless you need to format data somehow. These two statements work identically in PHP:
$num = 42;
$char = 'q';
$text = sprintf('The number is %d and the character is %s', $num, $char);
$text = "The number is $num and the character is $char";
sprintf's used more in C for "printing" variable data into a string. But PHP can already do that with double-quoted strings, so unless you need to use sprintf's special formatting functions (e.g. %0.2f for a 2-decimal-place float), it's easier to use the regular string method.

From http://php.net/manual/en/function.mysql-real-escape-string.php:
Note: mysql_real_escape_string() does not escape % and _. These are wildcards in MySQL if combined with LIKE, GRANT, or REVOKE.
You need to manually escape the % and _ if any with \% and _. I don't recommend using sprintf, but just improving your escape function.

Related

Inserting Data to MySQL, Double Quotes Added to Fields

I've got a script that imports data to a MySQL table and when inserting, VARCHAR and TEXT fields have double quotes on the beginning and end. I am using addslashes because some of the fields are supposed to have single quotes, double quotes, commas, and semi-colons. Here's my code:
$csvfile = fopen($csv_file, 'r');
$theData = fgets($csvfile);
$i = 0;
$imports = array();
while (!feof($csvfile))
{
$csv_data[] = fgets($csvfile, 1024);
$data = explode(",", $csv_data[$i]);
$insert_csv = array();
$insert_csv['id'] = md5($EventID.$PerformerID);
$insert_csv['EventID'] = addslashes($data[0]);
$insert_csv['Event'] = addslashes($data[1]);
$insert_csv['PerformerID'] = addslashes($data[2]);
$insert_csv['Performer'] = addslashes($data[3]);
$insert_csv['Venue'] = addslashes($data[4]);
$insert_csv['VenueID'] = addslashes($data[5]);
$insert_csv['VenueStreetAddress'] = addslashes($data[6]);
$insert_csv['DateTime'] = addslashes($data[7]);
$insert_csv['PCatID'] = addslashes($data[8]);
$insert_csv['PCat'] = addslashes($data[9]);
$insert_csv['CCatID'] = addslashes($data[10]);
$insert_csv['CCat'] = addslashes($data[11]);
$insert_csv['GCatID'] = addslashes($data[12]);
$insert_csv['GCat'] = addslashes($data[13]);
$insert_csv['City'] = addslashes($data[14]);
$insert_csv['State'] = addslashes($data[15]);
$insert_csv['StateID'] = addslashes($data[16]);
$insert_csv['Country'] = addslashes($data[17]);
$insert_csv['CountryID'] = addslashes($data[18]);
$insert_csv['Zip'] = addslashes($data[19]);
$insert_csv['TicketsYN'] = addslashes($data[20]);
$insert_csv['IMAGEURL'] = addslashes($data[23]);
$query = "INSERT IGNORE INTO table_name(`id`, `EventID`, `Event`, `PerformerID`, `Performer`, `Venue`, `VenueID`, `VenueStreetAddress`, `DateTime`, `PCatID`, `PCat`, `CCatID`, `CCat`, `GCatID`, `GCat`, `City`, `State`, `StateID`, `Country`, `CountryID`, `Zip`, `TicketsYN`, `IMAGEURL`)
VALUES('{$insert_csv['id']}','{$insert_csv['EventID']}','{$insert_csv['Event']}','{$insert_csv['PerformerID']}','{$insert_csv['Performer']}','{$insert_csv['Venue']}','{$insert_csv['VenueID']}','{$insert_csv['VenueStreetAddress']}','{$insert_csv['DateTime']}','{$insert_csv['PCatID']}','{$insert_csv['PCat']}','{$insert_csv['CCatID']}','{$insert_csv['CCat']}','{$insert_csv['GCatID']}','{$insert_csv['GCat']}','{$insert_csv['City']}','{$insert_csv['State']}','{$insert_csv['StateID']}','{$insert_csv['Country']}','{$insert_csv['CountryID']}','{$insert_csv['Zip']}','{$insert_csv['TicketsYN']}','{$insert_csv['IMAGEURL']}')";
$n = mysql_query($query);
if(!mysql_query($query)){
die("error: ".mysql_error());
}
$i++;
What is causing the double quotes and how can I remove them when inserting the rows? I have also tried stripslashes on the VALUES part of the query but it causes an error due to fields that have single quotes, double quotes, or other delimiters.
Its possible your csv file contains fields that are delimited by double quotes. You can remove the double quotes from the fields by using the trim function. for example:
$insert_csv['EventID'] = trim(addslashes($data[0]), '"');
The above code will remove the double quote from the start and end of the $data[0] string.
TLDR: Instead of using addslashes() use a DB-specific escape function like mysqli_real_escape_string()
What addslashes() does is that it returns a string with backslashes before characters that need to be escaped.
I was going to write the whole explanation, but I think the php.net does a better job of explaining:
Returns a string with backslashes before characters that need to be
escaped. These characters are single quote ('), double quote ("),
backslash () and NUL (the NULL byte).
An example use of addslashes() is when you're entering data into
string that is evaluated by PHP. For example, O'Reilly is stored in
$str, you need to escape $str. (e.g. eval("echo
'".addslashes($str)."';"); )
To escape database parameters, DBMS specific escape function (e.g.
mysqli_real_escape_string() for MySQL or pg_escape_literal(),
pg_escape_string() for PostgreSQL) should be used for security
reasons. DBMSes have differect escape specification for identifiers
(e.g. Table name, field name) than parameters. Some DBMS such as
PostgreSQL provides identifier escape function,
pg_escape_identifier(), but not all DBMS provides identifier escape
API. If this is the case, refer to your database system manual for
proper escaping method.
If your DBMS doesn't have an escape function and the DBMS uses \ to
escape special chars, you might be able to use this function only when
this escape method is adequate for your database. Please note that use
of addslashes() for database parameter escaping can be cause of
security issues on most databases.
Looks like you have a csv file. I recommend using php's in-build fgetcsv() to read the file. This way, you will get an array for every row and then can use that array to insert into the database.
Also, you can directly import csv into mysql if you want it that way:
LOAD DATA INFILE 'D:/myfile.csv'
INTO TABLE my_table
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 ROWS

PHP query not working with variable

In my page I have this code with echo's.
<?php
include("../config.php");
$q = mysql_query("SELECT propertyaddress FROM propertydetail WHERE active='yes' and leasedatefrom='".date("m-d-Y", strtotime('+1 months'))."'");
$res = mysql_fetch_array($q);
echo "<br/>pdetail=".$pdetail=trim($res['propertyaddress']);
echo $query="SELECT * FROM tenantmaster WHERE propertyaddress like '".$pdetail."'";
//echo $query="SELECT * FROM tenantmaster ";
//echo $query="SELECT * FROM tenantmaster WHERE propertyaddress = '1934 Heron Ave Unit D Schaumburg IL 60193'";
$resultdb = mysql_query($query);
if (!$resultdb) {
die('Invalid query: ' . mysql_error());
}
else{
echo "<br/>right query";
}
echo "<br/>num of row===".mysql_num_rows($resultdb);
$rowt = mysql_fetch_array($resultdb);
echo "<br/>row===".$rowt['name'];
exit;
?>
config.php
<?php
$mysql_hostname = "localhost";
$mysql_user = "root";
$mysql_password = "";
$mysql_database = "gms_estate";
/*
$mysql_hostname = "localhost";
$mysql_user = "root";
$mysql_password = "";
$mysql_database = "gms_estate";
*/
$bd = mysql_connect($mysql_hostname, $mysql_user, $mysql_password)
or die("Opps some thing went wrong");
mysql_select_db($mysql_database, $bd) or die("Opps some thing went wrong");
?>
And problem is my first query $q is working but query $query is also working but mysql_num_rows($resultdb) is not working and display 0 rows but, when I run echo query to database it's displaying 1 row. Why?
I tried $res['propertyaddress'] variable with trim() but not any success.
But when I use 1934 Heron Ave Unit D Schaumburg IL 60193 (that's my variable value) instead of $res['propertyaddress'] then it's working.
So, when I give value of variable directly then it's working but when I give variable then not. Why?
A common problem with comparing text entry from multi-line fields is that you probably have a "newline" or "tab" in the results from the first query, but that is not in the second query. (Other gotchas are "non-breaking space").
As you are echoing in HTML you won't see those in the output (so copying and pasting works), but they will be used in the query (so direct input fails). Try "View Source" (which shows newlines) or run in command line as that might give you more clues.
For now, strip out anything other than alpha numeric and spaces using preg_replace
$pdetail = trim( preg_replace("/[^0-9a-zA-Z ]/", "", $res['propertyaddress']) );
Eventually you'll want to adjust that to cover all your use cases, or of you find it's a "newline" just remove those - but you need to find what's different.
And, as per comments: check out mysqli / PDO parameterized queries. If the original address contained a single quote mark, that would also fail (with unknown results). It's a pain first off, but it'll save you a lot later on, makes your code easier to read and also will get more help here on SO (as your code is easier to read).
http://php.net/manual/en/pdo.prepared-statements.php
<?php
include("../config.php");
$connect = new PDO("mysql:host=$mysql_hostname;dbname=$mysql_database", $mysql_user, $mysql_password);
$q = "SELECT propertyaddress FROM propertydetail WHERE active='yes' and leasedatefrom='".date("m-d-Y", strtotime('+1 months'))."'";
$result = $connect->prepare($q);
$status = $result->execute();
$res = $result->fetch(PDO::FETCH_ASSOC);
$pdetail = $res["propertyaddress"];
$q = "SELECT * FROM tenantmaster WHERE propertyaddress = ".$connect->quote($pdetail);
/* or
$q = "SELECT * FROM tenantmaster WHERE propertyaddress like ".$connect->quote($pdetail);
*/
$result = $connect->prepare($q);
$status = $result->execute();
echo "<br/>num of row===".$result->rowCount();
if (($status) && ($result->rowCount() > 0))
{
$res = $result->fetch(PDO::FETCH_ASSOC);
echo "<br/>row===".$res['name'];
}
$connect = null;
?>
First of all it is recommended to use the mysqli along with prepared statement since it will avoid the SQL Injections that will occur. Now your code is purely injectable and it can be rectified with the help of mysqli along with prepared statements or with the help of PDO.
Mysqli with Prepared Statement: http://php.net/manual/en/mysqli.prepare.php
PDO: http://php.net/manual/en/book.pdo.php
PDO with Prepared: http://php.net/manual/en/pdo.prepare.php
Explanations
As per the usage of trim() in your variable you will be getting the strategy as per this alone.
trim- Strip whitespace (or other characters) from the beginning and end of a string
Description: This function returns a string with whitespace stripped from the beginning and end of str. Without the second parameter, trim() will strip these characters:
" " (ASCII 32 (0x20)), an ordinary space.
"\t" (ASCII 9 (0x09)), a tab.
"\n" (ASCII 10 (0x0A)), a new line (line feed).
"\r" (ASCII 13 (0x0D)), a carriage return.
"\0" (ASCII 0 (0x00)), the NUL-byte.
"\x0B" (ASCII 11 (0x0B)), a vertical tab.
Note:
But trim() does not remove the white space which is present at the middle of the string that is given.
Example:
trim() trims characters from the beginning and end of a string, it may be confusing when characters are (or are not) removed from the middle. trim('abc', 'bad') removes both 'a' and 'b' because it trims 'a' thus moving 'b' to the beginning to also be trimmed. So, this is why it "works" whereas trim('abc', 'b') seemingly does not.
Scenario: Hence in order to remove all teh white space that is present in the string you have to use the following.
You have to first remove all the character other that alpha numeric and white spaces with the help of preg_replace() function.
After replacing all the above mentioned items you have to then trim upon the variable so that it will remove all the white spaces that has been present and hence your string will look as the string which you give in hard code or directly.
3. You can directly adopt the method by strong the trimmed value into a variable and then echo it.
preg_match - Perform a regular expression match
Description: Searches subject for a match to the regular expression given in pattern.
Return Values: preg_match() returns 1 if the pattern matches given subject, 0 if it does not, or FALSE if an error occurred.
Solution to your Problem
But when I use 1934 Heron Ave Unit D Schaumburg IL 60193 (that's my variable value) instead of $res['propertyaddress'] then it's working.
Reason: This Error occurs when you printing the values directly from the Database.
If you have used any editor it will store the content directly to the DB as HTML tags alone.
Hence in order remove the HTML tags you have first store the DB value into a variable by replacing all the values and then you have to display it.
If you echo it directly you will not be seeing the HTML tags but if you view it by using CTRL+U you will be seeing it in the seeing it and it is not recommended. Hence you have to remove or strip of the parameters and then trim it.
Query:
preg_replace("/(\W)+/", "", $word_to_undergo);
Note: \W - Anything that isn't a letter, number or underscore.
So, in terms of Unicode character classes, \W is equivalent to every character that are not in the L or N character classes and that aren't the underscore character.
Alternative Solution:
To remove just put a plain space into your character class:
Query:
$needed_text = preg_replace("/[^A-Za-z0-9 ]/", "", $word_to_undergo);
Along with the above Solution you have to preform the trim so that it produces a perfect string as per your choice and it will match up with the query and produce the result.
As per Suggestion One: It should be
$final_value = preg_replace("/(\W)+/", "", $word_to_undergo);
$final_value = preg_replace("/(\W)+/", "", $res['propertyaddress']);
As per Suggestion Two: It should be
$final_value = preg_replace("/[^A-Za-z0-9 ]/", "", $word_to_undergo);
$final_value = preg_replace("/[^A-Za-z0-9 ]/", "", $res['propertyaddress']);
Addition to the above solution you can try using like this to.
<?php
$display=trim($res['propertyaddress']);
echo $display;
?>
Instead
echo "<br/>pdetail=".$pdetail=trim($res['propertyaddress']);
Use
$pdetail=trim($res['propertyaddress']);
echo "<br/><pre>pdetail='".$pdetail."'</pre>";
And you will can see real variable value
Change your query from
echo $query="SELECT * FROM tenantmaster WHERE propertyaddress like '".$pdetail."'";
To
echo $query="SELECT * FROM tenantmaster WHERE propertyaddress like '%".$pdetail."'%";
Please try with this query. It will be helpful for getting your result
$query='SELECT * FROM tenantmaster WHERE propertyaddress like "'.$pdetail.'";
You are missing mysql_free_result($q); and mysql_free_result($query) to announce that you are finished with the query.
And do change to mysqli (or PDO).

User inputted string, when containing certain special characters, does not match database string though they appear to be equivalent strings

I have searched for similar questions and have found this
but it has not helped for my situation. On my site, a user inputs an answer. The string is sent via an ajax call to a php file. The string may or may not contain special characters, so I use
encodeURIComponent()
before the string is sent to the php file.
The user-inputted string is compared in the php file with a string that represents the "correct answer", and if the strings are found to be equivalent strings after processing, the user-inputted answer is "correct". I have not had a problem with any strings lately until today. Until today, strings with letters, special characters (parentheses, minus sign, plus sign) and numbers have worked fine using the following processing in php:
<?php include 'connect.php';
$UserInput = trim($_GET['userinput']);
$QID = mysqli_real_escape_string($cxn, $_GET['qid']);
$sqlIQ = mysqli_fetch_assoc(mysqli_query($cxn, "SELECT answer FROM IndexQuestions WHERE sampqid = $QID"));
$StrReplaceArray = array("<i>", "</i>", "</sup>", " ");
$CorrectAnswer1 = str_replace($StrReplaceArray, "", $sqlIQ['answer']);
$CorrectAnswer2 = str_replace("<sup>", "^", $CorrectAnswer1);
$UserAnswer1 = str_replace(" ", "", $UserInput);
$UserAnswer2 = str_replace("+-", "-", $UserAnswer1);
if (strcasecmp($UserAnswer2, $CorrectAnswer2) == 0) {
$CorrectOrNot = 'Correct';
} else {
$CorrectOrNot = 'Incorrect';
}
However, the latest string is not working. The user-inputted string is -2 ± √3 which is sent to the php file as -2 ± √3 (with or without the whitespace). The "correct answer" saved in another table is -2 ± √3. I have echoed the following:
echo $UserAnswer2 . " " . $CorrectAnswer2; //after str_replace processing shown above
and the html output for each variable looks identical to me. I have also tried the following for comparative purposes (instead of strcasecmp):
if ($UserAnswer2 == htmlentities($CorrectAnswer2)) { //etc.
but still the same.
When I check a separate table (which stores the user's answer), the answer is stored the way I want it to be:
$unixtime = time();
$AnswerID = substr(md5(rand(0, 1000000)), 0, 10).$unixtime;
$sqlIQStats = mysqli_query($cxn, "INSERT INTO IQStats (answer_id, useranswer) VALUES ('$AnswerID', '".htmlentities($UserAnswer2)."')");
and appears in the database as -2 ± √3.
The html charset the site uses is charset=utf-8.
var_dump gives the following (with no spaces for user answer): $UserInput and $UserAnswer2 both give string(8) "-2±√3" whereas $CorrectAnswer2 gives string(18) "-2±√3"
Does anyone have any ideas as to why the strings, after string-processing and comparison in the php file, are found to be inequivalent strings?
OK...solved it by changing $UserInput to:
$UserInput = htmlentities(trim($_GET['userinput']));

Sql injection mysql_real_escape_string

I have a dilemma how should I mysql_real_escape_string() my variables without inserting them into the database \n, \r, \x00 when someone uses " ' or <br> on my comment field, I tried with preg_replace instead of mysql_real_escape_string, but seems I don't know exactly how to allow all the chars and signs I want.
mysql_real_escape_string only escapes values so that your queries don't break, it also protects against SQL injection if used correctly.
If you don't want certain characters you will need to use additional functions to strip them before you apply mysql_real_escape_string.
[insert obligatory "use prepared statements" comment]
Ex:
$string = "My name is
John";
$filtered_string = str_replace("\n", " ", $string); // filter
$escaped = mysql_real_escape_string($filtered_string); // sql escape
mysql_query("INSERT INTO `messages` SET `message` = '" . $escaped . "'");
You should be able to use str_replace to help with this:
mysql_real_escape_string(str_replace(array("\n", "\r\n", "\x00", '"', '\''), '', $input));
Having said that, it is a good idea to switch to mysqli or PDO for database read / write. Both of these allow prepared statements, which reduce the risk of SQL injections.
Here's an example of PDO:
$stmt = $PDOConnection->prepare('INSERT INTO example_table (input_field) VALUES (:input_field)');
$stmt->bindParam(':input_field', $input);
$stmt->execute();

Single quote with variable value in a double quote string

I have a string that looks like this:
"count( IF (my_id = 'mykey',value,100)) mykey"
However, the value 'mykey' that goes right after my_id is in a variable called $which_value;
I fail to see how I can put the $which_value so that it mantains the single quote around it.
Just add the variable inside your string:
"count( IF (my_id = '$which_value',value,100)) mykey"
You should, however, escape the value properly or use prepared statements:
$stmt = $db->prepare("SELECT count(IF (my_id = :my_value, value, 100)) mykey...");
$stmt->execute(array(
':my_value' => $which_value,
));
Or, using plain ol' mysql_ functions:
$sql = sprintf("SELECT count(IF(my_id = '%s', value, 100)) mykey...",
mysql_real_escape_string($which_value)
);
mysql_query($sql);
To include a variable in a string you can do
"count( IF(my_id = '" . $which_value . "',value,100)) mykey"
Its quite hard to make out what exactly you are looking for but this should point you in the right direction (I hope)
You can always use your variable in a double-quoted string like this
"count( IF (my_id = '{$mykey}',value,100)) {$mykey}"
Inside of double quotes variables will be parsed. There is a convenient simple method just using the variable like this:
"count( IF (my_id = '$which_value',value,100)) mykey"
More complex expressions can be wrapped in curly braces like this:
"count( IF (my_id = '{$an_array[3]}',value,100)) mykey"
You may also want to consider escaping the variable string so that it does not break or open up to exploit, the string you are creating. If your id is an integer you can either typecast the variable as an integer:
"count( IF (my_id = '" . (int)$which_value . ',value,100)) mykey"
Or use the sprintf function to insert the variable into the string:
sprintf("count( IF (my_id = '%d',value,100)) mykey", $which_value)
If you need to escape text strings then you'll want to look at escape functions specific to the database you are constructing the query for.

Categories