【问题标题】:Disabling PDO::ATTR_EMULATE_PREPARES causing 'unknown' issue禁用 PDO::ATTR_EMULATE_PREPARES 导致“未知”问题
【发布时间】:2012-11-04 21:49:57
【问题描述】:

只是一个关于 PDO 的 ATTR_EMULATE_PREPARES 属性的快速问题 - 简单地说,当保持默认 (true) 时,一切正常且花花公子。但是禁用它,好吧,我什至没有收到 PHP 错误消息,只是一个浏览器警告告诉我“连接已重置”。

这里是我使用的代码示例供参考

<?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>

这很好地从我可爱的测试表中返回查询...

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

但是,如果我冒昧地将 PDO::ATTR_EMULATE_PREPARES 的值设置为 false,它只会失败,然后再次失败,直到我将其恢复为原始值。 我能做些什么来找出造成这种情况的原因还是我错过了一些非常简单的事情?

我的 PHP 版本目前是 5.4.3,MySQL 是 5.5.24

【问题讨论】:

  • 应该没什么区别,但是您是否尝试过在查询中使用命名参数而不是问号语法?
  • 要尝试的另一件事 - 您是否尝试过使用 bindValue() 而不是 bindParam()?对于这样的查询,bindValue() 会更合适。
  • 恐怕完全没有区别,使用“命名”或“问题标记”参数,仍然会产生相同的不可用网页。只需查询“Select * FROM table”就会导致这种情况。也就是说,我找到了一个 solution 让它工作,但是该解决方案是根本不进行任何查询,然后脚本的其余部分运行良好!呸呸呸
  • 不管你在做什么,开发php代码的第一步总是“打开/打开错误报告”。总是。
  • 感谢您发布此信息,因为我在两个不同的服务(一个由大学和我自己的 iMac 运行)上得到或多或少相同的东西。完全相同的 PDO_Mysql 驱动程序版本,几乎相同的 PHP 和 MySQL 版本,它们与您的几乎相同。模拟 ==> 一切正常;仿真关闭(本机)==> 未生成网页,Chrome 浏览器出错,查看源代码显示部分发出的网页。似乎死在 PDO::prepare() 内,没有例外(例外),没有错误消息。 (使用命名参数;传入的值作为数组执行。)

标签: php mysql pdo


【解决方案1】:

这似乎是某些 PHP 版本中的错误:

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

似乎两者都运行有问题

PDO::ATTR_PERSISTENT => true

PDO::ATTR_EMULATE_PREPARES => true

您的 PDO 属性/选项数组中有哪些。

【讨论】:

  • 很好的发现,由于不相关的原因,我不再使用 MySQL 进行测试,但我会将其标记为已解决。
【解决方案2】:

您好,我想出了如何解决您(以及我的)问题。

遇到同样的问题,只是连接失败,没有错误。由于某种原因它不起作用,因为当您调用 PDO 数据库处理程序的构造函数时,您在 PDO 配置数组中添加了 ATTR_EMULATE_PREPARES 选项,不知何故这会导致 PDO 崩溃。

当您在没有 ATTR_EMULATE_PREPARES 选项的情况下启动 PDO 数据库处理程序,然后使用 setAttribute 禁用仿真时,它将起作用。因此像这样:

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

对于刚刚阅读本文并想知道为什么要尽可能关闭 ATTR_EMULATE_PREPARES 的人,请阅读: how safe are PDO prepared statements

【讨论】:

  • 嗨,你的常识,感谢刚刚添加的人们的额外和有趣的阅读。但如果你不认为有人解释-quote-“从来没有机会进行SQL注入(前提是 PDO::ATTR_EMULATE_PREPARES 为假)。” -unquote- 很有趣是啊.. 然后给一个减号.. :S
  • 我也不喜欢这个解决方案。没有冒犯,但它看起来很像一个神奇的圣歌:“这样做,就不会出错”。您的回答中没有任何解释。所以,这只能是巧合。您自己是否遇到此错误?您的 PHP 版本/系统设置是什么?
  • ok 没问题,希望它能帮助那些真正有这个问题的人。此外,我提到我在浏览器中遇到了同样的“连接已重置”错误,所以如果我遇到这种情况,请回答你的问题,是的。请注意,我对您的回复也有点恼火的原因是您减去了帖子,因此人们可能会忽略此解决方案。这个工作的确切原因而不是当你将它添加到我不知道的 PDO 数据库处理程序的构造函数参数时,然后我将需要调试 PDO 模块.. 成为我的客人为我尝试。
【解决方案3】:

我遇到了同样的问题,发现当 ATTR_EMULATE_PREPARES = false 时会发生这种情况的两个原因:

  1. 如果 Select 语句同时包含 AND/OR 操作数,则查询可能会失败。我不得不将它们分成不同的查询。

  2. 如果 Insert 包含 bindValue 持有者,ATTR_EMULATE_PREPARES = false 更严格地使这些持有者名称完全匹配。

【讨论】:

    【解决方案4】:

    PHP 的 MYSQL 驱动程序并不真正支持prepared statements,它的性能很差。禁用 mysql 的模拟语句可能会出现很多错误。

    几天前我刚刚在这个问题上遇到了麻烦。

    有这个:

    在 grik dot net 07-Mar-2012 04:23 公开

    对于 PDO_MYSQL,您需要记住 PDO::ATTR_EMULATE_PREPARES 选项。

    默认值为 TRUE,如 $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES,true);

    这意味着没有使用 $dbh->prepare() 创建准备好的语句 称呼。使用 exec() 调用 PDO 将占位符替换为值 本身并向 MySQL 发送一个通用查询字符串。

    第一个后果是调用 $dbh->prepare('garbage'); 报告没有错误。您将在 $dbh->exec() 期间收到 SQL 错误 称呼。第二个是特殊情况下的SQL注入风险,比如 使用占位符作为表名。

    仿真的原因是 MySQL 的性能很差 陈述。仿真的工作速度明显加快。

    来源:user contributed note

    【讨论】:

    • emulate prepare 的情况比你说的要复杂。见this answer
    • 对,我明白了,我想要这个的原因是因为如果它们是相同类型的,它可能会加速多个插入,而不是一遍又一遍地处理单个查询。我在linux机器上试过这个(我在windows上运行apache),它运行得很好,所以我只能假设存在驱动程序错误或其他一些不兼容问题。不过,如果说实际发生的事情出错了,那就太好了;)
    • 有趣的信息,但它没有回答问题。 (我有同样的问题并在上面发表了评论。)卢卡斯没有问他为什么会出错。他说除了连接已重置的错误消息(不是来自 PHP)之外,他根本没有得到任何输出。卢卡斯:你不应该接受这个答案。
    猜你喜欢
    • 2013-11-13
    • 2012-04-24
    • 2013-02-24
    • 2014-06-19
    • 2015-09-09
    • 1970-01-01
    相关资源
    最近更新 更多