User Contributed Notes 34 notes

Just a little function which mimics the original mysql_real_escape_string but which doesn't need an active mysql connection. Could be implemented as a static function in a database class. Hope it helps someone.

Note that mysql_real_escape_string doesn't prepend backslashes to \x00, \n, \r, and and \x1a as mentionned in the documentation, but actually replaces the character with a MySQL acceptable representation for queries (e.g. \n is replaced with the '\n' litteral). (\, ', and " are escaped as documented) This doesn't change how you should use this function, but I think it's good to know.

Following is a recursive function that makes all the strings it finds safe for data entry. If the underlying value is an array, it will loop through that array as well, to inifity. So any array depth is allowed. This might come in handy when dealing with sessions, posts, gets or whatnot arrays, where you immediately want to make use of the data without having to filter the data first.

<?php/* * Created by: Stefan van Beusekom * Created on: 31-01-2011 * Description: A method that ensures safe data entry, and accepts either strings or arrays. If the array is multidimensional, * it will recursively loop through the array and make all points of data safe for entry. * parameters: string or array; * return: string or array; */public function filterParameters($array) {

// Check if the parameter is an arrayif(is_array($array)) {// Loop through the initial dimensionforeach($array as $key => $value) {// Check if any nodes are arrays themselvesif(is_array($array[$key]))// If they are, let the function call itself over that particular node$array[$key] = $this->filterParameters($array[$key]);

// Check if the nodes are stringsif(is_string($array[$key]))// If they are, perform the real escape function over the selected node$array[$key] = mysql_real_escape_string($array[$key]); } }// Check if the parameter is a stringif(is_string($array))// If it is, perform a mysql_real_escape_string on the parameter$array = mysql_real_escape_string($array);

No discussion of escaping is complete without telling everyone that you should basically never use external input to generate interpreted code. This goes for SQL statements, or anything you would call any sort of "eval" function on.

So, instead of using this terribly broken function, use parametric prepared statements instead.

Honestly, using user provided data to compose SQL statements should be considered professional negligence and you should be held accountable by your employer or client for not using parametric prepared statements.

NB: This doesn't mean you should never generate dynamic SQL statements. What it means is that you should never use user-provided data to generate those statements. Any user-provided data should be passed through as parameters to the statement after it has been prepared.

So, for example, if you are building up a little framework and want to do an insert to a table based on the request URI, it's in your best interest to not take the $_SERVER['REQUEST_URI'] value (or any part of it) and directly concatenate that with your query. Instead, you should parse out the portion of the $_SERVER['REQUEST_URI'] value that you want, and map that through some kind of function or associative array to a non-user provided value. If the mapping produces no value, you know that something is wrong with the user provided data.

Failing to follow this has been the cause of a number of SQL-injection problems in the Ruby On Rails framework, even though it uses parametric prepared statements. This is how GitHub was hacked at one point. So, no language is immune to this problem. That's why this is a general best practice and not something specific to PHP and why you should REALLY adopt it.

Also, you should still do some kind of validation of the data provided by users, even when using parametric prepared statements. This is because that user-provided data will often become part of some generated HTML, and you want to ensure that the user provided data isn't going to cause security problems in the browser.

The function mysql_real_escape_string helps the developer to insert data without having troubles in the process or having risks of SQL Injection.You can develop a similar function :<?phpfunction escape($str) {$search=array("\\","\0","\n","\r","\x1a","'",'"');$replace=array("\\\\","\\0","\\n","\\r","\Z","\'",'\"'); return str_replace($search,$replace,$str); }?>

There's an interesting quirk in the example #2 about SQL injection: AND takes priority over OR, so the injected query actually executes as WHERE (user='aidan' AND password='') OR ''='', so instead of returning a database record corresponding to an arbitrary username (in this case 'aidan'), it would actually return ALL database records. In no particular order. So an attacker might be able to log in as any account, but not necessarily with any control over which account it is.

Of course a potential attacker could simply modify their parameters to target specific users of interest:

// The query sent to MySQL would read:// SELECT * FROM users WHERE user='' AND password='' OR user='administrator' AND ''='';// which would allow anyone to gain access to the account named 'administrator'

I use the following code in my database connection include file (which is of course called at the start of every page that needs to do some SQL)...
Therefore, all POST and GET vars are automatically escaped before being used anywhere in SQL statements.

I had wanted to see the merits of dynamically and "automatically" applying mysql_real_escape_string() to $_GET and $_POST as arrays rather than manually each time I would type up a query. I used array_walk_recursive() to call my function "mysql_safe" to apply mysql_real_escape_string() to each key of the $_GET and $_POST arrays.

My function is part of a class, and it is called each time I connect to the database to perform a query:

However, after using this function, I find that it does indeed work, it also creates new $_GET and $_POST values in which $item and $key are swapped. So I end up with $_GET[$item] = $key, as well as $_GET[$key] = $item. I have not yet determined if this is due to the actual coding itself, or my particular method of implementation.

[EDIT BY danbrown AT php DOT net: Contains a bugfix by "Anonymous" on 13-JUL-09 to reorder the user function parameters.]

It seems to me that you could avoid many hassels by loading valid database values into an array at the beginning of the script, then instead of using user input to query the database directly, use it to query the array you've created. For example:

<?php//you still have to query safely, so always use cleanup functions like eric256's$categories = sql_query("select catName from categories where pageID = ?",$_GET['pageID']);while ($cts = @mysql_fetch_row($categories)) {//making $cts both the name and the value of the array variable makes it easier to check for in the future. //obviously, this naming system wouldn't work for a multidimensional array$cat_ar[$cts[0]] = $cts[0];}...

//user selects sorting criteria//this would be from a query string like '?cats[]=cha&cats[]=fah&cats[]=lah&cats[]=badValue...', etc.$cats = $_GET['cats'];

//verify that values exist in database before building sorting queryforeach($cats as $c) { if ($cat_ar[$c]) { //instead of in_array(); maybe I'm just lazy... (see above note)$cats1[] = "'".mysql_real_escape_string($c)."'"; }}$cats = $cats1;//$cats now contains the filtered and escaped values of the query string

$cat_query = '&& (category_name = \''.implode(' || category_name = \'',$cats).'\')';//build a sql query insert//$cat_query is now "&& (category_name = 'cha' || category_name = 'fah' || category_name = 'lah')" - badValue has been removed//since all values have already been verified and escaped, you can simply use them in a query//however, since $pageID hasn't been cleaned for this query, you still have to use your cleaning function$items = sql_query("SELECT * FROM items i, categories c WHERE i.catID = c.catID && pageID = ? $cat_query", $pageID);

calling this function twice, or on a string for which quotes have already been escaped, causes the quotes to be escaped twice.An example is where we have to check for magic_quotes_gpc before calling mysql_escape_string to sanitize the inputs.

The following function can be used to escape singe and double quotes in a string with out the risk of escaping quotes twice.This function escapes a quote, only if it hasn't already been escaped.

Automatically adds quotes (unless $quotes is false), but only for strings. Null values are converted to mysql keyword "null", booleans are converted to 1 or 0, and numbers are left alone. Also can escape a single variable or recursively escape an array of unlimited depth.

This function won't help you when inserting binary data, to me it will get mallformed into the database. Probably UTF-8 combinations will be translated by this function or somewhere else when inserting data when running mysql in UTF-8 mode.

A better way to insert binary data is to transfer it to hexadecimal notation like this example: