Why is PDO better for escaping MySQL queries/querystrings than mysql_real_escape_string? Why is PDO better for escaping MySQL queries/querystrings than mysql_real_escape_string? php php

Why is PDO better for escaping MySQL queries/querystrings than mysql_real_escape_string?


As the current answers go into details while your question is more aimed at a general overview, I'll give it a try:

The PDO classes aim to encapsulate all the functionality needed to interact with a database. They do this by defining 'methods' (OO parlor for functions) and 'properties' (OO parlor for variables). You'd use them as a complete replacement for all the 'standard' functions you are using now for talking to a database.

So instead of calling a series of the 'mysql_doSomething()' functions, storing their results in your own variables, you would 'instantiate' an object from the PDO class ('class' = abstract definition, 'object' = concrete, usable instance of a class) and call methods on that object to do the same.

As an example, without PDO, you'd do something like this:

// Get a db connection$connection = mysql_connect('someHost/someDB', 'userName', 'password');// Prepare a query$query = "SELECT * FROM someTable WHERE something = " . mysql_real_escape_string($comparison) . "'";// Issue a query$db_result = mysql_query($query);// Fetch the results$results = array();while ($row = mysql_fetch_array($db_result)) {  $results[] = $row;}

while this would be the equivalent using PDO:

// Instantiate new PDO object (will create connection on the fly)$db = new PDO('mysql:dbname=someDB;host=someHost');// Prepare a query (will escape on the fly)$statement = $db->prepare('SELECT * FROM someTable WHERE something = :comparison');// $statement is now a PDOStatement object, with its own methods to use it, e.g.// execute the query, passing in the parameters to replace$statement->execute(array(':comparison' => $comparison));// fetch results as array$results = $statement->fetchAll();

So on first glance, there is not much difference, except in syntax. But the PDO version has some advantages, the biggest one being database independence:

If you need to talk to a PostgreSQL database instead, you'd only change mysql:to pgsql: in the instantiating call new PDO(). With the old method, you'd have to go through all your code, replacing all 'mysql_doSomething()' functions with their 'pg_doSomthing()' counterpart (always checking for potential differences in parameter handling). The same would be the case for many other supported database engines.

So to get back to your question, PDO basically just gives you a different way to achieve the same things, while offering some shortcuts/improvements/advantages. For example, escaping would happen automatically in the proper way needed for the database engine you are using. Also parameter substitution (prevents SQL Injections, not shown in example) is much easier, making it less error prone.

You should read up on some OOP basics to get an idea of other advantages.


I'm not super familiar with PDO, but there is a distinction between "prepared statements" and escaped strings. Escaping is about removing disallowed character strings from the query, but prepared statements are about telling the database what kind of query to expect.

A query has multiple parts

Think of it this way: when you give a query to the database, you're telling it several separate things. One thing might be, for example, "I want you to do a select." Another might be "limit it to rows WHERE the user name is the following value."

If you build up a query as a string and hand it to the database, it doesn't know about either part until it gets the completed string. You might do this:

'SELECT * FROM transactions WHERE username=$username'

When it gets that string, it has to parse it and decide "this is a SELECT with a WHERE".

Getting the parts mixed up

Suppose a malicious user inputs their user name as billysmith OR 1=1. If you're not careful, you might put that into your string, resulting in:

'SELECT * FROM transactions WHERE username=billysmith OR 1=1'

...which would return all the transactions for all users, because 1 always equals 1. Whoops, you've been hacked!

See what happened? The database didn't know what parts to expect in your query, so it just parsed the string. It wasn't surprised that the WHERE had an OR, with two conditions that could satisfy it.

Keeping the parts straight

If only it had known what to expect, namely, a SELECT whose WHERE had only one condition, the malicious user couldn't have tricked it.

With a prepared statement, you can give it that correct expectation. You you can tell the database "I'm about to send you a SELECT, and it's going to be limited to rows WHERE username = a string that I'm about to give you. That's all - there are no other parts to the query. Are you ready? OK, here comes the string to compare to the username."

With that expectation, the database wouldn't be fooled: it would only return rows where the username column contains the actual string 'billysmith OR 1=1.' If nobody has that user name, it would return nothing.

Other benefits of prepared statements

In addition to security benefits, prepared statements have a couple of speed benefits:

  • They can be reused with different parameters, which should be faster than building a new query from scratch, because the database already knows basically what you're about to ask for. It has already built its "query plan".
  • Some databases (Postgres is one, I think) will start making a query plan as soon as they get the prepared statement - before you've actually sent the parameters to use with it. So you may see a speedup even on the first query.

For another explanation, see Theo's answer here.


Unlike mysql_real_escape_string, PDO allows you to enforce a datatype.

<?php/* Execute a prepared statement by binding PHP variables */$calories = 150;$colour = 'red';$sth = $dbh->prepare('SELECT name, colour, calories    FROM fruit    WHERE calories < :calories AND colour = :colour');$sth->bindParam(':calories', $calories, PDO::PARAM_INT);$sth->bindParam(':colour', $colour, PDO::PARAM_STR, 12);$sth->execute();?>

Note that in the example above, the first parameter, calories, is required to be an integer (PDO::PARAM_INT).

Second, to me, PDO parameterized queries are easier to read. I'd rather read:

SELECT name FROM user WHERE id = ? AND admin = ? 

than

SELECT name FROM user WHERE id = mysql_real_escape_string($id) AND admin = mysql_real_escape_string($admin);

Third, you don't have to make sure you quote parameters properly. PDO takes care of that. For example, mysql_real_query_string:

SELECT * FROM user WHERE name = 'mysql_real_escape_string($name)' //note quotes around param

vs

SELECT * FROM user WHERE name = ?

Finally, PDO allows you to port your app to a different db without changing your PHP data calls.