50

I am modifying my code from using mysql_* to PDO. In my code I had mysql_real_escape_string(). What is the equivalent of this in PDO?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
REJOLA
  • 573
  • 1
  • 4
  • 7

7 Answers7

73

Well No, there is none!

Technically there is PDO::quote() but it is rarely ever used and is not the equivalent of mysql_real_escape_string()

That's right! If you are already using PDO the proper way as documented using prepared statements, then it will protect you from MySQL injection.


# Example:

Below is an example of a safe database query using prepared statements (pdo)

  try {
     // first connect to database with the PDO object. 
     $db = new \PDO("mysql:host=localhost;dbname=xxx;charset=utf8", "xxx", "xxx", [
       PDO::ATTR_EMULATE_PREPARES => false, 
       PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
     ]); 
 } catch(\PDOException $e){
     // if connection fails, show PDO error. 
   echo "Error connecting to mysql: " . $e->getMessage();
 }

And, now assuming the connection is established, you can execute your query like this.

if($_POST && isset($_POST['color'])){ 

    // preparing a statement
    $stmt = $db->prepare("SELECT id, name, color FROM Cars WHERE color = ?");

    // execute/run the statement. 
    $stmt->execute(array($_POST['color']));

    // fetch the result. 
    $cars = $stmt->fetchAll(\PDO::FETCH_ASSOC); 
    var_dump($cars); 
 }

Now, as you can probably tell, I haven't used anything to escape/sanitize the value of $_POST["color"]. And this code is secure from myql-injection thanks to PDO and the power of prepared statements.


It is worth noting that you should pass a charset=utf8 as attribute, in your DSN as seen above, for security reasons, and always enable PDO to show errors in the form of exceptions.

PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION

so errors from you database queries won't reveal sensitive data like your directory structure, database username etc.

Last but not least, there are moments when you should not trust PDO 100%, and will be bound to take some extra measures to prevent sql injection, one of those cases is, if you are using an outdated versions of mysql [ mysql =< 5.3.6 ] as described in this answer

But, using prepared statements as shown above will always be safer, than using any of the functions that start with mysql_

Good reads

PDO Tutorial for MySQL Developers

samayo
  • 16,163
  • 12
  • 91
  • 106
  • 7
    @PeeHaa埽 there is not. While PDO::quote() does the complete formatting, escaping **and** quoting, and thus can be used safely, mysql_real_escape_string does *incomplete* formatting, and shouldn't be used as a protection measure. – Your Common Sense May 20 '13 at 12:21
  • 1
    Wow really your answer is just 1 security breach. There is no need to escape input anymore??? What about xss attacks... You should always sanitize user input.. – andy Mar 18 '15 at 11:50
  • 4
    @andy What the hell are you talking about? This question is about escaping for sql. Not about password hashing, CSRF prevention, XSS prevention or fire hazard prevention – PeeHaa May 09 '15 at 11:34
  • 1
    @PeeHaa I understand, but I think it is misleading to say there is no more "need" te sanitize your input. Because you stil have to.. Maybe there is no more need for sql escaping, but there is still need for all the other attacks. – andy Jul 02 '15 at 11:22
  • 5
    There absolutely IS something close to - but not exactly - equivalent to mysql_real_escape_string(), as other people here have mentioned. It is important to explain exactly why one should understand the philosophy of prepared statements, but there's no reason to LIE to people just to get them to adopt the correct practice. I found myself needing PDO::quote() for compatibility purposes, otherwise big portions of our codebase needed to be changed overnight. – Andz Oct 10 '15 at 07:43
  • @andy A note about sanitizing: You always sanitize *when you generate a program from within another program*, an SQL query is a program, an HTML document is a program, a JavaScript program is... well, you get it. Whenever you generate values to be used in another language, you need to sanitize those values to ensure that you don't hit that language's special characters. It's not even about security, it's about correctness. If my name is Madara O'connor, I'm not trying to attack you with an SQL injection, my name just has a quote in it. – Madara's Ghost Jul 01 '16 at 19:33
  • I have thousands of query's using a home grown mysql wrapper from way before pdo became standard. The wrapper uses the old mysql functions and now needs to be ported as part of an effort to move this codebase to php7. Prepared statements simply will not do because of typing issues. Why is it 'pedantic' to mention PDO::quote while it is the answer to the question being asked? – Douwe Jan 16 '17 at 15:27
  • @Douwe What you are talking about is migration and/or integration related, whereas the answer and the question are focused on security. So the context is different here. OP is asking an alternative to mysql_real_escape_string as to a way to avoid SQL injection – samayo Jan 19 '17 at 15:32
  • @samayo What if you need to dynamically set the table name? I don't think you can do that with PDO? – Dan W. Dec 24 '18 at 17:52
  • @Dan W. Yes you can do it, otherwise the use for PDO would be severely limited. Use the same query as you would for mysql, just be careful not to use raw input to create a db/table dynamically. I am on mobile so I can't do much, but google "pdo create table" – samayo Dec 24 '18 at 18:13
  • @samayo That's for creating a table if I understand you correctly. But if I want to SELECT from a dynamic tablename it throws an error. – Dan W. Dec 24 '18 at 18:20
  • Have you checkes this answer? https://stackoverflow.com/a/182353/1640606 i remeber being able to select dynamically a table, but you have to build a string query first, then use that to select the table – samayo Dec 24 '18 at 18:25
29

There is none*! The object of PDO is that you don’t have to escape anything; you just send it as data. For example:

$query = $link->prepare('SELECT * FROM users WHERE username = :name LIMIT 1;');
$query->execute([':name' => $username]); # No need to escape it!

As opposed to:

$safe_username = mysql_real_escape_string($username);
mysql_query("SELECT * FROM users WHERE username = '$safe_username' LIMIT 1;");

* Well, there is one, as Michael Berkowski said! But there are better ways.

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • 13
    Technically there's [`PDO::quote()`](http://php.net/manual/en/pdo.quote.php) but this is _the right answer_ and it isn't a direct equivalent of `mysql_real_escape_string()`. – Michael Berkowski Dec 23 '12 at 16:35
  • 1
    Why won't you use double quotes for query? You wouldn't have to escape – Dharman Dec 23 '12 at 16:36
  • 2
    @Dharman: I like exaggerating difficulty with deprecated stuff =) Okay, okay, I changed it. – Ry- Dec 23 '12 at 16:37
  • Alez's answer is working for me because it uses $conn->prepare rather than $conn->query (which gave me an error) and then executes. – Nitsan Baleli Feb 01 '14 at 10:59
  • @MichaelBerkowski I'm curious. Why is that *the right answer*? – samayo Jun 30 '16 at 09:43
  • 1
    @samayo I don't know why I chose the words I did 4 years ago, but `prepare()/execute()` has always been the _preferred_ method. `PDO::quote()` is hardly ever used in practice and isn't exactly equivalent to `mysql_real_escape_string()`. – Michael Berkowski Jun 30 '16 at 10:32
7
$v = '"'.mysql_real_escape_string($v).'"'; 

is the equivalent of $v = $this->db->quote($v); be sure you have a PDO instance in $this->db so you can call the pdo method quote()

Ram Sharma
  • 8,676
  • 7
  • 43
  • 56
Simo
  • 155
  • 3
  • 12
  • What exactly do you want to show here? this question has already well accepted answer. – tod Dec 14 '14 at 14:07
  • 4
    I wanted to show the equivalent PDO method to the function mysql_real_escape_string, in one instruction, wich is the method "quote()". – Simo Dec 16 '14 at 22:39
4

There is no need of mysql_real_escape_string in PDO.

PDO itself adjust special character in mysql query ,you only need to pass anonymous parameter and bind it run time.like this Suppose you have user table with attribute name,email and password and you have to insert into this use prepare statement like this you can pass name as => $name="Rajes'h ";

it should execute there is no need of equivalent of mysql_real_escape_string

$stmt="INSERT into user(name,email,password) VALUES(:name,:email,:password)";
try{
   $pstmt=$dbh->prepare($stmt);//$dbh database handler for executing mysql query
   $pstmt->bindParam(':name',$name,PDO::PARAM_STR);
   $pstmt->bindParam(':email',$email,PDO::PARAM_STR);
   $pstmt->bindParam(':password',$password,PDO::PARAM_STR);
   $status=$pstmt->execute();
   if($status){
    //next line of code 
   }


}catch(PDOException $pdo){
     echo $pdo->getMessage();
}
1

The simplest solution I've found for porting to PDO is the replacement for mysql_real_escape_string() given at https://www.php.net/manual/en/mysqli.real-escape-string.php#121402. This is by no means perfect, but it gets legacy code running with PDO quickly.

@samayo pointed out that PDO::quote() is similar but not equivalent to mysql_real_escape_string(), and I thought it might be preferred to a self-maintained escape function, but because quote() adds quotes around the string it is not a drop in replacement for mysql_real_escape_string(); using it would require more extensive changes.

Roger Dueck
  • 615
  • 7
  • 16
-1

In response to a lot of people's comments on here, but I can't comment directly yet (not reached 50 points), there ARE ACTUALLY needs to use the $dbh->quote($value) EVEN when using PDO and they are perfectly justifiable reasons...

  1. If you are looping through many records building a "BULK INSERT" command, (I usually restart on 1000 records) due to exploiting InnoDb tables in MySQL/Maria Db. Creating individual insert commands using prepared statements is neat, but highly inefficient when doing bulk tasks!
  2. PDO can't yet deal with dynamic IN(...) structures, so when you are building a list of IN strings from a list of user variables, YOU WILL NEED TO $dbh->quote($value) each value in the list!

So yes, there is a need for $dbh->quote($value) when using PDO and is probably WHY the command is available in the first place.

PS, you still don't need to put quotes around the command, the $dbh->quote($value) command also does that for you.

Out.

  • 2
    No. I disagree. You should never ever put data into SQL query. No matter what it is or how uncomfortable it is. PDO actually is making it much easier for you to do `IN()` clauses thanks to bind-in-execute. – Dharman Sep 04 '19 at 10:04
  • 1
    It wouldn't be in the available function set if there was no need for it. So how would you perform your bulk insert using PDO? Care to show an example of the bind-in-execute with a variable length list of user IN elements? – Andrew Foster Sep 04 '19 at 10:39
  • There are so many more functions, which have very limited use case in PHP. The problem is not that they exists, but because people abuse them, Your example is abusing it. Prepared statements are easier, safer and better than manually putting quoted data into SQL queries. – Dharman Sep 04 '19 at 10:41
  • AND SLOWER. WAY SLOWER. – Andrew Foster Sep 04 '19 at 10:42
  • 1
    Just use prepared statements and you'd never need neither quoting or escap8ng – Your Common Sense Sep 04 '19 at 10:42
  • One of the benefits of prepared statements is that they are actually faster. I do not know how you are using them, but even if you are preparing a new query each time, you should not see much of a performance impact. – Dharman Sep 04 '19 at 10:46
  • The performance is on the Db. Doing 7000 individual inserts takes way longer than doing a bulk insert, so you have to build up your SQL string first. – Andrew Foster Sep 04 '19 at 10:47
  • "Way slower" is a bit of exaggeration. In case your innodb is configured in paranoid mode, just wrap your inserts in a transaction. That's the only case known to me that could justify such a definition – Your Common Sense Sep 04 '19 at 10:51
  • 1
    So if quote() should NEVER be used. Why is it in the function set? PS: Thanks for the IN() example. – Andrew Foster Sep 04 '19 at 11:15
  • As I said PHP has functions which are almost never used. This is a very good example of it. Even the PHP manual suggest [`quote`](https://www.php.net/manual/en/pdo.quote.php) should not be used. Just forget this function even exists. – Dharman Sep 04 '19 at 11:54
-3

If to answer the original question, then this is the PDO equivalent for mysql_real_escape_string:

function my_real_escape_string($value, $connection) {
    /* 
    // this fails on: value="hello'";
    return trim ($connection->quote($value), "'");
    */
    return substr($connection->quote($value), 1, -1);       
}

btw, the mysqli equivalent is:

function my_real_escape_string($value, $connection) {
    return mysqli_real_escape_string($connection, $value);
}
IT goldman
  • 14,885
  • 2
  • 14
  • 28