我偶然发现了(imho相当糟糕的文档)事实,默认情况下,PHP PDO为其MySQL驱动程序启用了标志MYSQL_ATTR_DIRECT_QUERY
。
这意味着它不是实际使用预准备语句,而是模拟预准备语句的行为。这意味着它使用转义值替换占位符客户端,并按原样将完整查询发送到数据库。
曾经有一个很好的理由这样做,因为在早期版本的MySQL预编译语句中会绕过查询缓存。但现在情况已经不是这样了。还有一点性能优势,因为它减少了从应用程序到数据库的往返次数,但我不确定这是值得的吗?
使用这种方法的明显缺点是我们仍然依赖于客户端转义,这通常是一个坏主意。我在过去遇到了mysqli_real_escape_string
的奇怪问题,由于某些字符集配置错误,允许无效字符进入查询。我宁愿不再有类似的事情再次发生。
我只是在这个问题上找到了半真半假和肤浅的评论(例如'是的,你可以启用'或'它会导致“问题”')。寻找一个真正的原因,为什么我不打开它?在MySQL / PDO中使用实际准备好的语句无论如何都与模拟的预处理语句不兼容?
我问的部分原因是因为我们使用PHPActiverecord,它依赖于PDO。它不附带测试,我不希望它突然中断生产,因为关闭模拟的预处理语句会巧妙地改变某些边缘情况下的行为。
(作为旁注,在任何人提出之前:检查PDO::ATTR_EMULATE_PREPARES
将无效,因为它实际上没有(完全)为MySQL驱动程序实现,您必须检查PDO::MYSQL_ATTR_DIRECT_QUERY
。是的,那个人花了我一段时间。)
澄清:我想知道是否有充分理由 NOT 关闭此行为。不是我不应该首先关心的原因。
答案 0 :(得分:4)
问题基于一个无效的假设:模拟准备不完全支持。 (他们完全支持)。
实际上,MYSQL_ATTR_DIRECT_QUERY只不过是ATTR_EMULATE_PREPARES的别名。
源代码中的证明:connection handling和Attribute Getter Code以及Attribute Setter Code。
setter代码是最有说服力的。即:
390 case PDO_MYSQL_ATTR_DIRECT_QUERY:
391 case PDO_ATTR_EMULATE_PREPARES:
392 ((pdo_mysql_db_handle *)dbh->driver_data)->emulate_prepare = Z_BVAL_P(val);
393 PDO_DBG_RETURN(1);
有关绝对应该关闭模拟准备的详细信息,请参阅this answer。