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

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

有没有办法检查数据库到底执行了什么?

155755 次浏览

我不相信你可以,尽管我希望有人能证明我是错的。

我知道你可以打印查询,它的 toString 方法会显示 sql,而不需要替身计画。如果您正在构建复杂的查询字符串,但是它不能提供带有值的完整查询,那么这将非常方便。

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

所以可能发送到数据库的是 PREPARE ...,然后是 SET ...,最后是 EXECUTE ...

您将无法获得像 SELECT * FROM ...这样的 SQL 字符串,即使它会产生等效的结果,因为实际上从未向数据库发送过这样的查询。

我所做的打印实际查询是有点复杂,但它的工作:)

在为语句赋值变量的方法中,我有另一个变量,看起来有点像这样:

$this->fullStmt = str_replace($column, '\'' . str_replace('\'', '\\\'', $param) . '\'', $this->fullStmt);

地点:
$column是我的代币
$param是分配给标记的实际值
$this->fullStmt是带有替换标记的仅打印语句

它所做的只是在实际的 PDO 分配发生时用值替换标记。

希望我没有把你搞糊涂至少给你指了个正确的方向。

我检查 QueryLog 以查看作为准备语句执行的确切查询。

所以我想我最终会回答我自己的问题,以便有一个记录在案的完整的解决方案。但我们要感谢 Ben James 和 Kailash Badu 他们为此提供了线索。

简短的回答
正如本 · 詹姆斯提到的: 没有
在 PHP 端不存在完整的 SQL 查询,因为带标记的查询和参数分别发送到数据库。 只有在数据库端才存在完整的查询。

即使尝试在 PHP 端创建一个函数来替换令牌,也不能保证替换过程与 SQL 过程相同(比如令牌类型、 bindValue vs bindParam 等棘手的东西)

解决办法
这就是我详细阐述 Kailash Badu 的答案的地方。 通过记录所有 SQL 查询,我们可以看到服务器上真正运行的是什么。 对于 mySQL,这可以通过更新 my.cnf (在我的例子中是使用 Wamp 服务器的 my.ini)来完成,并添加如下代码行:

log=[REPLACE_BY_PATH]/[REPLACE_BY_FILE_NAME]

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

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

我最初避免打开日志来监视 PDO,因为我认为这将是一个麻烦,但它一点也不难。你不需要重启 MySQL (在5.1.9之后) :

在 phpMyAdmin 或任何其他您可能拥有高数据库权限的环境中执行这个 SQL:

SET GLOBAL general_log = 'ON';

在终端里,跟踪你的日志文件,我的在这里:

>sudo tail -f /usr/local/mysql/data/myMacComputerName.log

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

>ps auxww|grep [m]ysqld

我发现 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();

因为它创造了:

SELECT * FROM `example` WHERE `'userName'` = 'mick' ;

它没有创建一个错误,只是一个空结果

$sql = "SELECT * FROM `example` WHERE `$dynamicField` = :value";

得到

SELECT * FROM `example` WHERE `userName` = 'mick' ;

完成后执行:

SET GLOBAL general_log = 'OFF';

否则你的日志会变得很大。

我认为在使用 pdo 时查看最终查询文本的最简单方法是制造特殊错误并查看错误消息。我不知道如何做到这一点,但当我使用 pdo 在 yii 框架中出现 sql 错误时,我可以看到查询文本

最简单的方法是读取 mysql 执行日志文件,您可以在运行时这样做。

这里有一个很好的解释:

如何显示在 MySQL 上执行的最后一个查询?