【发布时间】:2017-09-07 15:47:06
【问题描述】:
我正在尝试使用 pdo_sqlsrv 将 ASCII NUL 字符(\0 aka U+0000)从 PHP 插入 SQL Server 数据库。这是处理 PHP 序列化字符串的要求,其中包含 NUL 字符来表示私有/受保护的变量。
但是,PDO::quote() 有一些东西会破坏字符串。
要重现的代码(将DBNAME、USERNAME 和PASSWORD 替换为适当的值):
<?php
try {
$dsn = 'sqlsrv:Server=.\SQLEXPRESS;Database=DBNAME';
$user = 'USERNAME';
$pass = 'PASSWORD';
$connection = new PDO($dsn, $user, $pass);
} catch (PDOException $e) {
die("Connection error: " . $e->getMessage());
}
$str = "XX\0XX";
header("Content-Type: text/plain");
print("Original: " . str_replace("\0", "{NUL}", $str) . "\n");
$str = $connection->quote($str);
print("Quoted: " . str_replace("\0", "{NUL}", $str) . "\n");
?>
预期输出:
Original: XX{NUL}XX
Quoted: 'XX{NUL}XX'
实际输出:
Original: XX{NUL}XX
Quoted: 'XX'{NUL}{NUL}a
谁能解释这种奇怪的行为,更重要的是解释如何解决它?
更新
看起来最后一个字符是随机的,因为在随后的运行中它是一个e。这意味着某种形式的内存访问错误,例如读到字符串的末尾。可能是 pdo_sqlsrv 实现中的错误?
【问题讨论】:
-
如果使用prepared statements,是不是就不用
PDO::quote了? -
准备好的声明可能会也可能不会解决问题。我还没有测试过,但我想这取决于问题发生在哪个级别。无论哪种方式,在这种情况下,它们都不是解决方案,因为 DBAL 的实现(顺便说一句,如果
quote()按预期工作,则保证正确转义)。 -
str_replace()是一个单字节函数。如果您使用的是 UTF-8,它实际上可能会进行诊断。var_dump(bin2hex($str))有什么用? -
我的测试用例中没有多字节字符。只是字母
X和 ASCII NUL 字符。
标签: php sql-server pdo sqlsrv