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

发布于 2024-08-12 08:39:45 字数 84 浏览 4 评论 0原文

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

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

In PHP, when accessing MySQL database with PDO with parametrized query, how can you check the final query (after having replaced all tokens)?

Is there a way to check what gets really executed by the database?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

ぽ尐不点ル 2024-08-19 08:39:45

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

简短回答

正如本·詹姆斯所说:

PHP端不存在完整的SQL查询,因为query-with-tokens和参数是分开发送到数据库的。
仅在数据库端存在完整查询。

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

解决方法

这是我详细阐述 Kailash Badu 的答案的地方。
通过记录所有 SQL 查询,我们可以看到服务器上实际运行的内容。
对于 mySQL,这可以通过更新 my.cnf(或在我的 Wamp 服务器的情况下为 my.ini)并添加如下行来完成:

log=[REPLACE_BY_PATH]/[REPLACE_BY_FILE_NAME]

Just do not run this in production!!!

So I think I'll finally answer my own question in order to have a full solution for the record. But have to thank Ben James and Kailash Badu which provided the clues for this.

Short Answer

As mentioned by Ben James: NO.

The full SQL query does not exist on the PHP side, because the query-with-tokens and the parameters are sent separately to the database.
Only on the database side the full query exists.

Even trying to create a function to replace tokens on the PHP side would not guarantee the replacement process is the same as the SQL one (tricky stuff like token-type, bindValue vs bindParam, ...)

Workaround

This is where I elaborate on Kailash Badu's answer.
By logging all SQL queries, we can see what is really run on the server.
With mySQL, this can be done by updating the my.cnf (or my.ini in my case with Wamp server), and adding a line like:

log=[REPLACE_BY_PATH]/[REPLACE_BY_FILE_NAME]

Just do not run this in production!!!

末骤雨初歇 2024-08-19 08:39:45

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

You might be able to use PDOStatement->debugDumpParams. See the PHP documentation .

执妄 2024-08-19 08:39:45

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

因此,发送到数据库的内容可能是 PREPARE ...,然后是 SET ...,最后是 EXECUTE ...

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

Using prepared statements with parametrised values is not simply another way to dynamically create a string of SQL. You create a prepared statement at the database, and then send the parameter values alone.

So what is probably sent to the database will be a PREPARE ..., then SET ... and finally EXECUTE ....

You won't be able to get some SQL string like SELECT * FROM ..., even if it would produce equivalent results, because no such query was ever actually sent to the database.

绅刃 2024-08-19 08:39:45

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

I check Query Log to see the exact query that was executed as prepared statement.

怂人 2024-08-19 08:39:45

我最初避免打开日志记录来监视 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";

get

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

当你完成执行时:

SET GLOBAL general_log = 'OFF';

否则你的日志将会变得巨大。

I initially avoided turning on logging to monitor PDO because I thought that it would be a hassle but it is not hard at all. You don't need to reboot MySQL (after 5.1.9):

Execute this SQL in phpMyAdmin or any other environment where you may have high db privileges:

SET GLOBAL general_log = 'ON';

In a terminal, tail your log file. Mine was here:

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

You can search for your mysql files with this terminal command:

>ps auxww|grep [m]ysqld

I found that PDO escapes everything, so you can't write

$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();

Because it creates:

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

Which did not create an error, just an empty result. Instead I needed to use

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

to get

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

When you are done execute:

SET GLOBAL general_log = 'OFF';

or else your logs will get huge.

初见 2024-08-19 08:39:45

我打印实际查询的方法有点复杂,但它有效:)

在将变量分配给我的语句的方法中,我有另一个变量,看起来有点像这样:

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

其中:
$column 是我的令牌
$param 是分配给 token 的实际值
$this->fullStmt 是我仅打印的带有替换标记的语句,

它的作用是在真正的 PDO 分配发生时用值简单地替换标记。

我希望我没有让你感到困惑,至少为你指明了正确的方向。

What I did to print that actual query is a bit complicated but it works :)

In method that assigns variables to my statement I have another variable that looks a bit like this:

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

Where:
$column is my token
$param is the actual value being assigned to token
$this->fullStmt is my print only statement with replaced tokens

What it does is a simply replace tokens with values when the real PDO assignment happens.

I hope I did not confuse you and at least pointed you in right direction.

苍风燃霜 2024-08-19 08:39:45

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

这里有一个很好的解释:

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

The easiest way it can be done is by reading mysql execution log file and you can do that in runtime.

There is a nice explanation here:

How to show the last queries executed on MySQL?

草莓酥 2024-08-19 08:39:45

我不相信你能做到,尽管我希望有人能证明我错了。

我知道你可以打印查询,它的 toString 方法将向你显示没有替换的 sql。如果您正在构建复杂的查询字符串,这会很方便,但它不会为您提供带有值的完整查询。

I don't believe you can, though I hope that someone will prove me wrong.

I know you can print the query and its toString method will show you the sql without the replacements. That can be handy if you're building complex query strings, but it doesn't give you the full query with values.

哆兒滾 2024-08-19 08:39:45

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

I think easiest way to see final query text when you use pdo is to make special error and look error message. I don't know how to do that, but when i make sql error in yii framework that use pdo i could see query text

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文