7

Just a quick question regarding PDO's ATTR_EMULATE_PREPARES attribute- simply put, while left on default (true) everything works fine and dandy. Disable it however and, well, I don't even get a PHP error message, just a browser warning telling me that "the connection was reset".

For reference here is a sample of the code I was using

<?php
include_once("config.php");

try {
  $dbh = new PDO
  (
    "mysql:host=". DB_SERVER .";dbname=" . DB_NAME,
    DB_USER,
    DB_PASS,
    array
    (
      PDO::ATTR_PERSISTENT => true,
      PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
      PDO::ATTR_EMULATE_PREPARES => true
    )
  );
} catch(PDOException $e) {
  echo "<pre>";
  print_r("Error: " . $e);
  echo "</pre>";
  die();
}

$idNum = "1";

$sth = $dbh->prepare("SELECT * FROM `table` WHERE `id` = ?;");
$sth->bindParam(1,$idNum);
$sth->execute();
$res = $sth->fetch();
?>

<pre>
<?=print_r($res); ?>
</pre>

Which nicely returns the query from my lovely test table...

Array
(
    [id] => 1
    [field1] => q12w3e4r5t6y7u8i9
    [field2] => kijhgbfvcdoikujyh
)

However were I to have the temerity to set the value of PDO::ATTR_EMULATE_PREPARES to false it would simply fail, and fail again until I return it to its original value. Is there anything I can do to find out what is causing this or have I missed something really simple?

My PHP version is currently 5.4.3 and MySQL is 5.5.24

Lucas
  • 1,476
  • 13
  • 20
  • it shouldn't make a difference, but have you tried using a named parameter rather than the question mark syntax in the query? – Spudley Nov 16 '12 at 07:43
  • another thing to try - have you tried using bindValue() instead of bindParam()? For a query like this, bindValue() would be more appropriate. – Spudley Nov 16 '12 at 07:47
  • No difference at all I'm afraid, using 'named' or 'question marked' parameters, still produces the same unavailable webpage. Simply querying "Select * FROM table" causes this. That said, I have found a *solution* to get it working, however that solution is to make no queries at all, then the rest of the script runs fine! grrrrr – Lucas Nov 16 '12 at 07:50
  • It doesn't matter what you're doing, the first step when developing php code is always "turn on/up error reporting". Always. – goat Nov 17 '12 at 19:22
  • Thanks for posting this, as I get more or less the same thing on two different serves (one run by a university and my own iMac). Same exact PDO_Mysql driver version, nearly the same PHP and MySQL versions, and they are almost the same as yours. Emulation on ==> all OK; emulation off (native) ==> no web page produced, error from Chrome browser, looking at source shows partially emitted web page. Seems to die inside PDO::prepare() with no exception (exceptions on), no error message. (Using named parameters; values passed in to execute as array.) – Marc Rochkind Jan 07 '13 at 16:49

4 Answers4

6

This looks to be a bug in certain PHP versions:

https://bugs.php.net/bug.php?id=61411

It seems there is a problem running both

PDO::ATTR_PERSISTENT => true

and

PDO::ATTR_EMULATE_PREPARES => true

Which you have in your PDO attributes/options array.

spitfire
  • 181
  • 1
  • 4
  • Great find, for reasons unrelated I no longer use MySQL to test this but I will mark it as solved. – Lucas Sep 03 '14 at 08:58
0

Hi I figured out how to solve your (and mine as well) problem.

Experienced the same issue, just failure of the connection, no errors. For some reason it doesn't work because you added the ATTR_EMULATE_PREPARES option in the PDO-configuration array when you call the constructor of the PDO database-handler, somehow this is making PDO crash.

When you initiate the PDO database-handler without the ATTR_EMULATE_PREPARES option and then use setAttribute to disable emulation, it will work. Thus like this:

// Configure PDO to really prepare statements and to not emulate them
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

For people just reading this and wondering why turn off ATTR_EMULATE_PREPARES if possible, read: how safe are PDO prepared statements

Community
  • 1
  • 1
  • Hi Your Common Sense, thanks just added that for people for the extra and interesting read.. But if you don't think that someone explaining that -quote- "There's never an opportunity for SQL injection (provided PDO::ATTR_EMULATE_PREPARES is false)." -unquote- is interesting yeah.. then give a minus.. :S –  Sep 10 '13 at 12:19
  • I don't like the solution too. No offense, but it looks rather like a magical chant: "Do it this way and there will be no error". There is no explanation in your answer. So, it can be only coincidence. Do you experience this error yourself? What is your PHP version/system setup? – Your Common Sense Sep 10 '13 at 12:36
  • oke no problem, hopefully it will help people who actually have this issue. Further, i mentioned that i experienced this same "connection was reset" error from the browser, so the answer to your question if i experienced this, yes. note, the reason that i was a bit irritated by your response as well is the fact that you minus the post, and therefore people might overlook this solution. Exact reason why this works and not when you add it to the constructor-parameter of the PDO database-handler i don't know, then i will need to debug the PDO-module.. be my guest to try that for me. –  Sep 10 '13 at 12:54
0

I had the same problem and found two reasons this can occur when ATTR_EMULATE_PREPARES = false:

  1. If a Select statement contains both the AND/OR operands, the query may fail. I had to separate these into different queries.

  2. If an Insert contains bindValue holders, ATTR_EMULATE_PREPARES = false is more strict about making these holder names match exactly.

guest
  • 1
-2

PHP`s MYSQL driver does not really support prepared statements, it has very poor performance. Lots of errors can emerge from disabling emulated statements for mysql.

I`ve just hit my head on this issue a couple of days ago.

Have this:

public at grik dot net 07-Mar-2012 04:23

With PDO_MYSQL you need to remember about the PDO::ATTR_EMULATE_PREPARES option.

The default value is TRUE, like $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES,true);

This means that no prepared statement is created with $dbh->prepare() call. With exec() call PDO replaces the placeholders with values itself and sends MySQL a generic query string.

The first consequence is that the call $dbh->prepare('garbage'); reports no error. You will get an SQL error during the $dbh->exec() call. The second one is the SQL injection risk in special cases, like using a placeholder for the table name.

The reason for emulation is a poor performance of MySQL with prepared statements. Emulation works significantly faster.

Source: user contributed note.

Álvaro González
  • 142,137
  • 41
  • 261
  • 360
ro0ter
  • 439
  • 2
  • 11
  • 1
    The situation with emulate prepares is more complicated than you say. See [this answer](http://stackoverflow.com/a/10455228/1002469) – Francis Avila Nov 17 '12 at 19:55
  • Right I see, the reason I wanted this is because it would presumably speed up multiple inserts if they were of the same type, rather than processing individual queries over and over. I tried this on a linux machine (I was running apache on windows) and it worked perfectly so I can only assume that there is a driver error or some other incompatability. Still it would be nice to have gotten an error to say what had actually happened ;) – Lucas Nov 18 '12 at 13:23
  • Interesting info, but it didn't answer the question. (I have the same problem and posted a comment above.) Lucas is not asking why he got an error. He is saying that he got no output at all other than an error message that the connection was reset (which did not come from PHP). Lucas: You should not have accepted this answer. – Marc Rochkind Jan 07 '13 at 17:02