当Mysqli发送准备好的查询时,PDO向MySQL发送原始查询,两者都产生相同的结果

3 php mysql mysqli pdo

我开始知道在使用MySQLi和PDO时预备语句是如何工作的,第一步,我启用了MySQL查询监控,如下所述:我如何查看实时MySQL查询?.然后我创建了以下测试:

使用mysqli:

$stmt = $mysqli->prepare("SELECT * FROM users WHERE username =?")) {
$stmt->bind_param("i", $user);
$user = "''1''";
Run Code Online (Sandbox Code Playgroud)

服务器日志:

  130802 23:39:39   175 Connect   ****@localhost on testdb
    175 Prepare   SELECT * FROM users WHERE username =?
    175 Execute   SELECT * FROM users WHERE username =0
    175 Quit
Run Code Online (Sandbox Code Playgroud)

使用PDO:

  $user = "''1''";
  $sql = 'SELECT * FROM user WHERE uid =?';
  $sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
  $sth->bindParam(1, $user, PDO::PARAM_INT);
Run Code Online (Sandbox Code Playgroud)

服务器日志:

  130802 23:41:42   176 Connect   ****@localhost on testdb
    176 Query SELECT * FROM user WHERE uid ='\'\'1\'\''
    176 Quit
Run Code Online (Sandbox Code Playgroud)

但是,两者都提供相同的结果:

uid: 0
username: admin
role: admin
Run Code Online (Sandbox Code Playgroud)

注意:uid = 0是正确的,因为intval("''1''") = 0

这里有什么重要的:

PDO查询在向MySQL发送不同查询时如何获得相同的结果?

SELECT * FROM user WHERE uid ='\'\'1\'\''

我发现PHP手册中只有一个指示:http://www.php.net/manual/en/pdo.prepare.php

注意:

模拟的预准备语句不与数据库服务器通信,因此PDO :: prepare()不检查语句.

但我不确定MySQL如何处理此查询并替换'\'\'1\'\''0.在这种情况下,如果使用PDO,监控查询将不准确,同时,使用PDO更好地了解发送到MySQL而不是MySQLi的确切查询.

更新: 将参数类型frm integer更改为string后:

MySQLi日志:

    188 Prepare   SELECT * FROM awa_user WHERE username =?
    188 Execute   SELECT * FROM awa_user WHERE username ='\'\'1\'\''
    188 Quit
Run Code Online (Sandbox Code Playgroud)

PDO日志:

    189 Query SELECT * FROM awa_user WHERE userame ='\'\'1\'\''
    189 Quit
Run Code Online (Sandbox Code Playgroud)

这意味着MySQLi和PDO在使用字符串发送到MySQL之前转义数据,而对于整数,mysqli在发送查询之前应用intval()或类似的东西,Bill也回答这是正确的.

Bil*_*win 6

您的PDO配置为模拟准备好的查询,而mysqli使用真正准备的查询.

准备好的查询将字符串绑定''1''为整数参数值.PHP使用类似的东西将它强制转换为整数intval().任何带有非数字前导字符的字符串都被PHP解释为0,因此 prepare 之后发送的参数值是值0.

伪造的查询使用字符串插值(而不是绑定) MySQL解析之前将字符串添加''1''到SQL查询中.但结果是类似的,因为SQL还将整数上下文中带有非数字前导字符的字符串视为值0.

唯一的区别是当参数在准备之前与准备之后绑定时,一般查询日志中会出现什么.

您还可以使PDO使用真正准备好的查询,因此在这种情况下它应该像mysqli一样:

$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
Run Code Online (Sandbox Code Playgroud)

PS:这可能是一个很好的理由,为什么习惯将id值设置为1而不是0.