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();
Related
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
I am trying to replace all ' matched in one string in php but I dont understabnd why it is not working this. I am newer in php.
the instruction is :
$val = "Hello I'm newer in PHP.";
$val = str_replace("'", "''", $val);
I tried to set backslah before and it is not working too
Could you help me please?
What you want is to make your string "db-safe". You have several options here:
Use mysql_real_escape_string if you're using the "old-school" mysql drivers (mysql_connect):
$str = mysql_real_escape_string("I'm newer to PHP");
Use PDO::quote() if your are using PDO:
$conn = new PDO(....);
$str = $conn->quote("I'm newer to PHP");
use prepared statements to insert / update tables (see http://php.net/manual/de/mysqli.quickstart.prepared-statements.php).
Personally I would prefer prepared statements, as it would also speed up your queries if you do multiple inserts/updates, and is the safest way.
Apart from a missing semicolon at the end of your first line, there's nothing wrong with the code you've written:
$val = "Hello I'm newer in PHP.";
$val = str_replace("'", "''", $val);
echo $val; // Hello I''m newer in PHP.
I am working on a project that uses OSCommerce with MySQL and I'm confused as to when I should use tep_db_input() or tep_db_prepare_input(). I'd assume I should use tep_db_input() around any strings that are being inserted/updated, but then when should the other function be used?
For example, if I were to SELECT some data from the database, and use the result to then INSERT a row into another table, do I need to prepare the input at some point? Or just use tep_db_input again?
$width = '3"'; // 3 inches
$new_height = '3\' 5"'; // 3 feet 5 inches
$result = tep_db_query(
"SELECT height
FROM measurements
WHERE width = '".tep_db_input($width)."'"
);
while ($row = tep_db_fetch_array($result)) {
tep_db_query(
"INSERT INTO measurement_history (
field,
old_value,
new_value
) VALUES (
'height',
'".tep_db_input($row['height'])."',
'".tep_db_input($new_height)."'
)"
);
}
Is this correct?
Edit:: In case anyone isn't familiar with those functions, here are their definitions:
function tep_sanitize_string($string) {
$patterns = array ('/ +/','/[<>]/');
$replace = array (' ', '_');
return preg_replace($patterns, $replace, trim($string));
}
function tep_db_input($string, $link = 'db_link') {
global $$link;
if (function_exists('mysql_real_escape_string')) {
return mysql_real_escape_string($string, $$link);
} elseif (function_exists('mysql_escape_string')) {
return mysql_escape_string($string);
}
return addslashes($string);
}
function tep_db_prepare_input($string) {
if (is_string($string)) {
return trim(tep_sanitize_string(stripslashes($string)));
} elseif (is_array($string)) {
reset($string);
while (list($key, $value) = each($string)) {
$string[$key] = tep_db_prepare_input($value);
}
return $string;
} else {
return $string;
}
}
tep_db_input uses mysql_real_escape_string or mysql_escape_string and that's a recommended way to prepare your database input.
(And I guess this function will use mysqli_real_escape_string() or similiar in a later release since mysql_real_escape_string will be deprecated starting with PHP 5.5.0. )
Where tep_db_input with mysql_real_escape_string just does escaping:
mysql_real_escape_string() calls MySQL's library function mysql_real_escape_string,
which prepends backslashes to the following characters: \x00, \n, \r, \, ', " and \x1a.
tep_db_prepare_input does different things like trimming whitespaces and replacing brackets and unquoting(!) by calling stripslashes.
So my advice would be: always use tep_db_input. And if you use tep_db_prepare_input to get rid of whitespace etc. use tep_db_input afterwards, too.
This is a bit weird, but you use both. Doing it this way will prevent attacks from malicious users, as well as unintended problems from unusual inputs.
Use tep_db_prepare input on any input data from the HTML form. This clears up issues with HTML, magic quotes, and script injections. Do not use this on text retrieved from the database.
Then you use tep_db_input before writing it to the database. This will escape the MySQL characters to prevent SQL injection attacks and other such problems.
Here's a code sample that shows it:
$clean = tep_db_prepare_input($_POST['name']);
$query_text = tep_db_query("select * from " . TABLE_NAME . " where name='" . tep_db_input($clean) . "'");
So I've created a simple PHP function to 'UPDATE' my MySQL row just by updating the array that is received by PHP.
function db_updateproduct(array $new, array $old = array()) {
$diff = array_diff($new, $old);
return 'INSERT INTO table (`'.mysql_real_escape_string(implode(array_keys($diff), '`,`')).'`) VALUES \''.mysql_real_escape_string(implode(array_values($diff), '\',\'')).'\'';
}
...
Update (with Accepted answer)
function db_updateproduct(array $new, array $old = array()) {
$diff = array_diff($new, $old);
return 'INSERT INTO `Product` (`'.implode(array_keys($diff), '`,`').'`) VALUES (\''
.implode(array_map('mysql_real_escape_string', array_values($diff)), '\', \'').'\')';
}
Now...
echo db_updateproduct(array('a' => 'on\'e', 'b' => 'two', 'c' => 'three'));
returns:
INSERT INTO `Product` (`a`,`b`,`c`) VALUES ('on\'e', 'two', 'three')
(As expected/wanted!)
You can run the escape function on the keys and values with array_map():
$escaped_keys = array_map('mysql_real_escape_string', array_keys($diff));
$escaped_values = array_map('mysql_real_escape_string', array_values($diff));
Then you can do your implode() magic on these two arrays.
UPDATE: As #YourCommonSense correctly pointed it out, it does not really make sense to run mysql_real_escape_string() on values that will be used in the query as field names/table names/etc. It correctly escapes \x00, \n, \r, \, ', " and \x1a, but it does NOT escape the backtick, so the query is still vulnerable to attacks.
You should validate the field names (so only the expected names can be used) or even better, use prepared queries (I recommend PDO).
Suggested reading:
Are mysql_real_escape_string() and mysql_escape_string() sufficient for app security?
As a matter of fact, doing mysql_real_escape_string on the array keys is an example of absolutely useless action.
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.