在PHP中使用PDO,如何检查最终的SQL参数化查询?

JB *_*aux 139 php mysql pdo sql-parametrized-query

在PHP中,当使用带有参数化查询的PDO访问MySQL数据库时,如何检查最终查询(在替换所有令牌之后)?

有没有办法检查数据库真正执行的是什么?

JB *_*aux 55

所以我想我最终会回答我自己的问题,以便为记录提供完整的解决方案.但不得不感谢Ben James和Kailash Badu为此提供了线索.

简短答案
正如本詹姆斯所说:.
PHP端不存在完整的SQL查询,因为带有forkens的查询和参数是分别发送到数据库的.仅在数据库端存在完整查询.

即使尝试在PHP端创建替换令牌的函数也不能保证替换过程与SQL版本相同(令牌类型,bindValue和bindParam等棘手的东西)

解决方法
这是我详细阐述Kailash Badu的答案.通过记录所有SQL查询,我们可以看到服务器上真正运行的是什么.使用mySQL,可以通过更新my.cnf(或者我的情况下使用Wamp服务器的my.ini)并添加如下行来完成:

log=[REPLACE_BY_PATH]/[REPLACE_BY_FILE_NAME]
Run Code Online (Sandbox Code Playgroud)

只是不要在生产中运行!!!

  • 自 PHP 版本 . `7.2` 可以通过 `$stmt->debugDumpParams();` 来实现 (2认同)

Ben*_*mes 27

使用带参数值的预准备语句不仅仅是动态创建SQL字符串的另一种方法.您在数据库中创建预准备语句,然后单独发送参数值.

那么可能发送到数据库的将是a PREPARE ...,then SET ...和finally EXECUTE ....

您将无法获得某些SQL字符串SELECT * FROM ...,即使它会产生相同的结果,因为实际上并没有将这样的查询发送到数据库.

  • 有没有办法可以看到实际执行的sql语句的"流"?也许它仍然可以提供一些帮助,总比没有好. (2认同)
  • `$stmt->debugDumpParams();` 应该很接近。 (2认同)

小智 26

你也许可以使用PDOStatement->debugDumpParams.请参阅PHP文档.

  • 很好的答案,但要显示参数值[您可能需要一个补丁](http://stackoverflow.com/a/3656529/819417). (3认同)
  • +1 这可能应该被接受为答案。它允许将 SQL 与来自 PHP 的其他调试跟踪混合在一起,而不必查看多个地方。 (2认同)

小智 9

我检查查询日志以查看作为预准备语句执行的确切查询.


Chr*_*ams 5

最初,我避免打开日志记录来监视PDO,因为我认为这很麻烦,但一点也不难。您不需要重新启动MySQL(在5.1.9之后):

在phpMyAdmin或您可能具有较高数据库特权的任何其他环境中执行此SQL:

SET GLOBAL general_log = 'ON';
Run Code Online (Sandbox Code Playgroud)

在终端中,尾随日志文件。我的在这里:

>sudo tail -f /usr/local/mysql/data/myMacComputerName.log
Run Code Online (Sandbox Code Playgroud)

您可以使用以下终端命令搜索mysql文件:

>ps auxww|grep [m]ysqld
Run Code Online (Sandbox Code Playgroud)

我发现PDO可以逃避一切,所以您不能写

$dynamicField = 'userName';
$sql = "SELECT * FROM `example` WHERE `:field` = :value";
$this->statement = $this->db->prepare($sql);
$this->statement->bindValue(':field', $dynamicField);
$this->statement->bindValue(':value', 'mick');
$this->statement->execute();
Run Code Online (Sandbox Code Playgroud)

因为它创建:

SELECT * FROM `example` WHERE `'userName'` = 'mick' ;
Run Code Online (Sandbox Code Playgroud)

其中没有产生错误,只是一个空的结果。相反,我需要使用

$sql = "SELECT * FROM `example` WHERE `$dynamicField` = :value";
Run Code Online (Sandbox Code Playgroud)

要得到

SELECT * FROM `example` WHERE `userName` = 'mick' ;
Run Code Online (Sandbox Code Playgroud)

完成后,执行:

SET GLOBAL general_log = 'OFF';
Run Code Online (Sandbox Code Playgroud)

否则您的日志将变得庞大。

  • 其实没有,首先,pdo没有任何办法以这种方式设置动态列。这是最好的方法。其次,以这种方式动态设置字段:'dynamicField ='userName'`不留任何注入空间。只要您根据白名单验证您的列名,就不可能注入这种构建sql的方法。 (4认同)
  • 因此,您向SQL注入开放了您的查询,恭喜:) (3认同)