我在理解PHP如何使用postgreSQL绑定处理ByteA时遇到了问题。
对于日志记录和归档目的,我存储在我用PHP / Apache服务器提供的ByteA
列文件中。为了存储,我使用gzencode()
压缩数据,然后在使用pg_escape_bytea()
存储之前转义字符串:
// Compress:
if($compress) {
$data = gzencode($data, 9);
}
// PostgreSQL ByteA Escaping:
$data = pg_escape_bytea($data);
我还有一个允许用户检索以前提供的文件的页面。但我不能成功压缩,我找不到原因:
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
/*
$dbCur = $webConn->prepare("SET bytea_output = 'escape';");
$dbCur->execute();
//print_r($dbCur->errorinfo());
*/
$dbCur = $webConn->prepare("SELECT * FROM logs.webservice WHERE Id=?;");
$dbCur->bindParam(1, $id);
$dbCur->execute();
//print_r($dbCur->errorinfo());
$row = $dbCur->fetch(PDO::FETCH_ASSOC);
$data = stream_get_contents($row['binarydata']);
$data = pg_unescape_bytea($data);
if($row['gzip']) {
$data = gzdecode($data);
}
header("Content-type: ".$row['mimetype']."; charset=".$row['charset']);
echo $data;
我必须使用PDO对象,我发现的所有示例(甚至在PHP网站上)都基于专用的DBMS API。其次,ByteA
列作为资源返回,然后我必须使用stream_getcontents()
来获取字符串。当我存储未压缩的文件时,我可以轻松地从中恢复,我使用或不使用SET bytea_output = 'escape';
查询和/或pg_unescape_bytea()
功能。所有组合都允许我获取文件。
当我使用压缩数据时,pg_unescape_bytea()
会大大减少几乎所有字节。无论如何,在所有组合中,gzdecode()
都无法工作。看来,我的二进制字符串中缺少或错误的字符在纯文本模式下没有阻塞。无论如何,这件事在互联网上没有很好的记录,我没有任何线索。
如何使用PHP PDO对象恢复存储在PostgreSQL ByteA中的gzcompressed字符串?
答案 0 :(得分:1)
仅解决检索问题,假设插入有效
二进制内容使用以下代码进入$data
后:
$data = stream_get_contents($row['binarydata']);
它们已根据需要采用原始二进制格式,因此您不能再使用它来解码:
$data = pg_unescape_bytea($data);
删除那个虚假的unescaping。当$data
仅包含ASCII字符时,您没有注意到问题的原因是pg_unescape_bytea
将这些字符转换为自身(给定bytea_output
设置为转义)。
但是当二进制流确实包含256个可能字节的全部范围时,例如在gzip压缩内容中,那么保证pg_unescape_bytea
将在该上下文中产生损坏的结果。
pg_unescape_bytea
只应用于直接来自数据库的字符串,如bytea-encoded-as-text。
PDO通常如何完成
实际上,对于PDO,我们不应该使用pg_[un]escape_bytea
函数,甚至不能使用以pg_*
开头的任何函数,因为PDO与数据库无关,其目的是允许代码这适用于不同的数据库。
应按照http://php.net/manual/en/pdo.lobs.php中的说明进行插入,使用PDO::PARAM_LOB
限定二进制参数。在执行此操作时,PDO将使用适当的方法为二进制传输编码数据,用于连接到的数据库类型。
当使用pg_escape_bytea()
进行显式转义时,它会生成一个字符串,PDO可以将其视为文本内容并按此传输。这是一种传输二进制“PDO后面”的方法,但这样做没有多大意义。
什么都行不通的是混合两种:转义(生成文本)和告诉PDO它是二进制文件。