У меня есть проблема в понимании того, как PHP обрабатывает ByteA с привязкой postgreSQL.
Для целей ведения журнала и архивирования я храню в 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), основаны на выделенном API СУБД. Во-вторых, ByteA
столбцы возвращаются как ресурсы, тогда мне пришлось использовать stream_getcontents()
чтобы получить строку. Когда я храню несжатые файлы, я могу легко восстановить их, что бы я ни использовал или нет SET bytea_output = 'escape';
запрос и / или pg_unescape_bytea()
функция. Все комбинации позволяют мне получить файл.
Когда я использую сжатые данные, pg_unescape_bytea()
резко съедает почти все мои байты. Во всяком случае, во всех комбинациях, gzdecode()
не работает Кажется, в моей двоичной строке отсутствуют или неправильные символы, которые не блокируются в режиме обычного текста. Во всяком случае, эта вещь плохо документирована в Интернете, и я застрял без какой-либо подсказки.
Как мне восстановить сжатую gz-строку, хранящуюся в PostgreSQL ByteA, используя PHP PDO Object?
Решение только проблемы поиска, при условии, что вставка работает
Как только двоичное содержимое попадает в $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
следует использовать только для строк, которые поступают непосредственно из базы данных как 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, что это двоичный файл.
Других решений пока нет …