Automatic Escaping of SQL Parameters
Escaping of SQL parameters in PHP is an needlessly tedious and error-prone process. Calling the right escaping function for every parameter that might be dangerous is a difficult task in a big project. This is just dangerous and calls for SQL-Injection-Attacks.
It’s obvious we need a uniform query function that automatically does the escaping for us. Perl-style parameter binding seems to be just the right choice. You can write your query, insert placeholders in the form of :n and pass the parameters to our function. The function automatically detects the datatype of the parameter for us and escapes it if needed.
query(
'SELECT posts
FROM blog
WHERE
status = :2
AND created = :1',
POST_STATUS_ACTIVE,
'2007-08-02'
);
Ok, we need two things to get this working:
- a function that replaces every placeholder in our query and submits it to the database
- another function to handle the parameter escaping for us
function query( $q, $params = array() ) { $params = array_slice( func_get_args(), 1 ); if( !empty( $params ) ) { $q = preg_replace('/:(\d+)/e', 'quote($params[$1 - 1])', $q ); } return mysql_query( $q ); } function quote( $s ) { if( $s === true ) { return 1; } else if( $s === false ) { return 0; } else if( is_int($s) || is_float($s) ) { return $s; } else { return "'".mysql_real_escape_string( $s )."'"; } }
The query function scans our SQL statement for placeholders, and calls the quote function in a regexp-callback for each one it finds. It is save to use placeholders in the parameters themself – they won’t be processed, as the regexp scans our string only once. So doing something like this is perfectly valid:
$searchString = "%ZOMFG :1 'asdf' :2%"; query( 'SELECT * FROM posts WHERE content LIKE :1', $searchString );
The final SQL-statement, that will be submitted to the database, looks like this:
SELECT * FROM posts WHERE content LIKE '%ZOMFG :1 ''asdf'' :2%'
Complete MySQL Class for PHP
If you’re interested, here’s the static MySQL class I use in my projects:
Static MySQL Class for PHP
This Class is lazy, which means it only connects to the database if it has to – e.g. the first time query() is called. It also returns results as associative arrays, rather than MySQL result resources.
4 Comments:
php.net/pdo for a nice abstraction layer to numerous db backends including prepared statements. needs php5.1 though.
Confused as to what the $1 is doing in the
$q = preg_replace('/:(\d+)/e', 'quote($params[$1 - 1])', $q );
Also the subject parameter $q is unassigned?
$1 is the number matched with (\d+). $q is the function parameter for the sql statement.
SQL db is the best one out there i wish someday i understand it all well but hey i am in learning process hoping for the best to understand php and sql all well :)