Uncompress gzip сжатый HTTP-ответ
Я использую функцию php file_get_contents()
для выполнения запроса HTTP. Чтобы сохранить пропускную способность, я решил добавить заголовок "Accept-Encoding: gzip"
, используя stream_context_create()
.
Очевидно, что file_get_contents()
выводит строку с кодировкой gzip, поэтому я использую gzuncompress()
для декодирования закодированной строки, но получаю сообщение об ошибке с данными, переданными как аргумент.
[...] PHP Warning: gzuncompress(): data error in /path/to/phpscript.php on line 26
Я знаю, что есть еще одна функция, способная распаковывать данные gzipped gzdecode()
, но она не включена в мою версию PHP (возможно, она доступна только в SVN).
Я знаю, что cUrl декодирует gzip-поток "на лету" (без каких-либо проблем), но кто-то предложил мне использовать file_get_contents()
вместо cUrl.
Знаете ли вы какой-либо другой способ распаковать gzip-данные на PHP или почему gzuncompress()
выводит предупреждение? Абсурдно, что gzuncompress()
работает не так, как ожидалось.
Примечания:
Проблема, конечно же, в PHP: HTTP-запрос сделан в Tumblr API, который дает хорошо закодированный ответ.
Ответы
Ответ 1
gzuncompress
не будет работать для кодировки gzip
. Это функция декомпрессии для архивов .Z
.
В руководстве перечислены несколько обходных путей для отсутствующего gzdecode()
# 82930 или просто используйте один из upgradephp
или временный файл временного файла gzopen.
Другим вариантом будет принудительное кодирование deflate
с заголовком Accept-Encoding:
, а затем с помощью gzinflate()
для декомпрессии.
Ответ 2
Нашел это для меня: http://www.php.net/manual/en/function.gzdecode.php#106397
По желанию: http://digitalpbk.com/php/file_get_contents-garbled-gzip-encoding-website-scraping
if ( ! function_exists('gzdecode'))
{
/**
* Decode gz coded data
*
* http://php.net/manual/en/function.gzdecode.php
*
* Alternative: http://digitalpbk.com/php/file_get_contents-garbled-gzip-encoding-website-scraping
*
* @param string $data gzencoded data
* @return string inflated data
*/
function gzdecode($data)
{
// strip header and footer and inflate
return gzinflate(substr($data, 10, -8));
}
}
Ответ 3
Перед распаковкой данных вам необходимо собрать ее.
Поэтому, если заголовок содержит
Transfer-Encoding: chunked
вам нужно разблокировать его.
function http_unchunk($data) {
$res=[];
$p=0; $n=strlen($data);
while($p<$n) {
if (preg_match("/^([0-9A-Fa-f]+)\r\n/",substr($data,$p,18),$m)) {
$sz=hexdec($m[1]); $p+=strlen($m[0]);
$res[]=substr($data,$p,$sz); $p+=$sz+2;
} else {
break;
}
}
return implode('',$res);
}
если Content-Encoding - gzip или x-gzip или x-compress, используйте gzdecode
если Content-Encoding дефлируется, используйте gzdeflate
...
if ($chunked) $body=http_unchunk($body);
if ($gzip) $body=gzdecode($body);
if ($deflate) $body=gzdeflate($body);
...