1

我在理解 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';查询和/或pg_unescape_bytea()功能。所有组合都允许我获取文件。

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

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

4

1 回答 1

1

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

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

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

它们已经根据需要采用原始二进制格式,因此您不能使用以下方法再次对其进行解码:

$data = pg_unescape_bytea($data);

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

但是,当二进制流真正包含 256 个可能字节的全部范围时,例如在 gzip 压缩的内容中,则可以保证pg_unescape_bytea在该上下文中会产生损坏的结果。

pg_unescape_bytea应该只用于直接来自数据库的字符串作为字节编码的文本。

通常如何使用 PDO 完成

实际上,对于 PDO,我们不应该使用这些pg_[un]escape_bytea函数,甚至不应该使用任何以 PDO 开头的函数,pg_*因为 PDO 是独立于数据库的,它的目的是允许跨不同数据库工作的代码。

应按照http://php.net/manual/en/pdo.lobs.php中的说明进行插入,用 . 限定二进制参数PDO::PARAM_LOB。执行此操作时,PDO 将自己对数据进行编码以进行二进制传输,并使用与其连接的数据库类型相应的方法。

当使用 进行显式转义时pg_escape_bytea(),它会生成一个字符串,PDO 可以将其视为文本内容并以此方式传输。这是一种“在 PDO 背后”传输二进制文件的方法,但这样做并没有多大意义。

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

于 2016-10-13T18:29:57.937 回答