当字段名称和值包含单引号时,PDO插入失败(42000/1064)

时间:2018-03-28 16:25:16

标签: php pdo prepared-statement

当一个PDO for MySQL prepared语句有:

  • 参数(v = ''
  • 名称中包含单引号(f'f
  • 的字段
  • VALUES部分参数后跟一个值 单引号(''

然后它出现异常:

SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ':v,'')' at line 1

要重现的一些代码:

function query($sql) {
   $pdo = new PDO('mysql:host=...', 'u', 'p', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ]);
   $pdo->prepare($sql)->execute(['v' => '']);
}

query("INSERT INTO `t` (`f'f`,`f`) VALUES ('',:v)"); // ok
query("INSERT INTO `t` (`f`,`f'f`) VALUES ('',:v)"); // ok
query("INSERT INTO `t` (`f'f`,`f`) VALUES (:v,'')"); // exception
query("INSERT INTO `t` (`f`,`f'f`) VALUES (:v,'')"); // exception

query("INSERT INTO `t` (`f'f`,`f`) VALUES (null,:v)"); // ok
query("INSERT INTO `t` (`f`,`f'f`) VALUES (null,:v)"); // ok
query("INSERT INTO `t` (`f'f`,`f`) VALUES (:v,null)"); // ok
query("INSERT INTO `t` (`f`,`f'f`) VALUES (:v,null)"); // ok

PHP Version 5.5.9-1ubuntu4.24,mysqlnd 5.0.11

这是一个错误还是我错过了什么?

更新

试用PHP版本7.1.15-1,mysqlnd 5.0.12:没有变化。

尝试使用位置参数:无变化。

1 个答案:

答案 0 :(得分:2)

引用的列名称对MySQL来说不是问题。我可以使用MySQL客户端成功测试(完全没有PHP):

mysql> set @v = '';

mysql> set @sql = "INSERT INTO `t` (`f'f`,`f`) VALUES (?,'')";

mysql> create table t (f int, `f'f` int);

mysql> prepare stmt from @sql;

mysql> execute stmt using @v;
Query OK, 1 row affected, 2 warnings (0.01 sec)

mysql> select * from t;
+------+------+
| f    | f'f  |
+------+------+
|    0 |    0 |
+------+------+

错误来自MySQL,它看到命名参数占位符:v是一个问题。 MySQL本身不支持命名参数占位符,因此PDO应该用?替换位置参数。

所以,如果有错误,那就是PDO。我怀疑PDO对列名中的单引号感到困惑,因为它试图解析参数占位符的SQL字符串。

我建议您在使用PDO时不要使用包含单引号的列名。

PHP 5.5很老了,它已经out of support for almost two years(我在2018年3月写这篇文章)。这些天,至少应该使用PHP 7.1。

我建议您使用PHP 7.1重复测试,看看PDO中的错误是否已修复。还可以尝试使用位置参数进行测试(使用?占位符)以查看是否可以解决问题。