简而言之:
删除addslashes($data)
。这里是多余的。
双重转义..两次
$data=fread($p,filesize($fi));
$data=addslashes($data);
$dat= pg_escape_bytea($data);
您需要读取数据,并将其转义为字符串文字,然后将其转换为bytea八进制或十六进制转义。即使 pg_escape_bytea
是正常的,它也永远无法以这种方式运行。
PHP 的 pg_escape_bytea
似乎会对输出进行双重转义,以便将其插入字符串文字中。这非常丑陋,但貌似没有其他方法可以避免这种双重转义,因此在 PHP 中似乎不能使用参数化语句来处理 bytea。但是对于其他一切,您仍然应该这样做。
在这种情况下,只需删除从文件中读取的数据的 addslashes
行即可。
测试用例显示 pg_escape_bytea
双重转义(并始终使用旧的低效八进制转义):
<?php
print pg_escape_bytea("Blah binary\x00\x01\x02\x03\x04 blah");
?>
运行:
php oh-the-horror.php
结果:
Blah binary\\000\\001\\002\\003\\004 blah
看到了双反斜杠吗?这是因为它假定你将其作为字符串插入到 SQL 中进行插值,这非常浪费内存、丑陋,并且是一种非常不好的习惯。但似乎没有其他选择。
除此之外,这意味着:
pg_unescape_bytea(pg_escape_bytea("\x01\x02\x03"));
由于pg_unescape_bytea
实际上并不是pg_escape_bytea
的反向操作,因此会产生错误的结果。这也使得将pg_escape_bytea
的输出作为参数传递给pg_query_params
变得不可能,你必须对其进行插值。
解码
如果您正在使用现代的PostgreSQL,它可能默认将bytea_output
设置为hex
。这意味着,如果我将数据写入bytea
字段,然后再获取它,它看起来会像这样:
craig=> CREATE TABLE byteademo(x bytea);
CREATE TABLE
craig=> INSERT INTO byteademo(x) VALUES ('Blah binary\\000\\001\\002\\003\\004 blah');
INSERT 0 1
craig=> SELECT * FROM byteademo ;
x
\x426c61682062696e6172795c3030305c3030315c3030325c3030335c30303420626c6168
(1 row)
"嗯,什么?" 你可能会说。没关系,这只是PostgreSQL更紧凑的十六进制表示法bytea
。如果你有现代的PHP和libpq
,pg_unescape_bytea
将正确处理它,并产生相同的原始字节作为输出......在旧版本上,你将得到垃圾,并需要将bytea_output
设置为escape
才能让pg_unescape_bytea
处理它。
相反应该做什么
使用PDO。
它对bytea
提供了合理的支持。
$sth = $pdo->prepare('INSERT INTO mytable(somecol, byteacol) VALUES (:somecol, :byteacol)');
$sth->bindParam(':somecol', 'bork bork bork');
$sth->bindParam(':byteacol', $thebytes, PDO::PARAM_LOB);
$sth->execute();
请参考以下链接:
您还可以研究一下 PostgreSQL 的 lob (large object) 支持,它提供了一个流式、可寻址的接口,仍然完全符合事务性。
现在,我要说几句话
如果 PHP 对 "字节字符串" 和 "文本字符串" 类型有真正的区分,那么您甚至不需要 pg_escape_bytea
,因为数据库驱动程序可以为您完成这个工作。没有任何丑陋的东西是必需的。不幸的是,PHP 中没有单独的字符串和字节类型。
请尽可能使用带参数的 PDO 语句。
在不能使用 PDO 的情况下,请至少使用 pg_query_params
和带参数的语句。PHP 的 addslashes
不是一种替代方案,它效率低下、丑陋,并且不理解数据库特定的转义规则。如果由于历史原因而不使用 PDO,则仍然必须手动转义 bytea
,但其他所有内容都应通过参数化语句进行处理。
有关 pg_query_params
的指南:
fsync()
等效率要高得多。在小规模备份时更容易(但在大规模时更难)。就像任何其他事物一样,这是一个权衡,有时可能很好,有时可能很糟糕,大多数情况下它只是还好。 - Craig Ringer