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

时间:2016-10-13 11:38:55

标签: php postgresql pdo gz bytea

我在理解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字符串?

1 个答案:

答案 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它是二进制文件。