如何使用 PHP PDO 对象恢复存储在 PostgreSQL ByteA 中的 gz 压缩字符串?

How to recover a gzcompressed string stored in PostgreSQL ByteA using PHP PDO Object?

我无法理解 PHP 如何使用 postgreSQL 绑定处理 ByteA。

出于日志记录和存档目的,我将文件存储在 ByteA 列中,这些文件与我的 PHP/Apache 服务器一起提供。为了存储,我使用 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'; 查询 and/or pg_unescape_bytea() 功能。所有组合都允许我获取文件。

当我使用压缩数据时,pg_unescape_bytea() 显着耗尽了我几乎所有的字节。无论如何,在所有组合中,gzdecode() 都不起作用。看来,我的二进制字符串中缺少或错误的字符不会在纯文本模式下阻塞。无论如何,这件事在互联网上没有很好的记录,我没有任何线索。

我应该如何使用 PHP PDO 对象恢复存储在 PostgreSQL ByteA 中的 gz 压缩字符串?

只解决检索问题,假设插入有效

一旦二进制内容进入$data,代码如下:

$data = stream_get_contents($row['binarydata']);

它们已经是需要的原始二进制格式,所以你不能用这个再次解码它:

<s>$data = pg_unescape_bytea($data);</s>

只需删除那个虚假的转义。当 $data 只有 ASCII 字符时你没有注意到问题的原因是 pg_unescape_bytea 将这些字符转换为它们自己(假定 bytea_output 设置为转义)。

但是当二进制流确实包含 256 个可能字节的全部范围时,例如在压缩内容中,那么可以保证 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 可以将其视为文本内容并按原样传输。这是一种传输二进制文件的方法"behind PDO's back",但这样做没有多大意义。

混合使用两者绝对行不通:转义(生成文本) 告诉 PDO 它是二进制的。