Технологи фирмы где я работаю иногда делятся со мной своими заметками, вот одна из них.
Не так много людей (не только разработчиков, а вообще), которые знают о том что сайты могут сжимать данные для экономии траффика, методом Gzip. Ещё меньше тех кто для той же экономии траффика решил программно скачивать (на PHP например) страницы именно в этом формате. И на этом начинается интересное.
Допустим мы скачиваем яндекс, его интересней всего конечно, например заглавная страница:
http://web-sniffer.net/?url=http%3A%2F%2Fwww.yandex.ru%2F&gzip=yes
которая выдаёт заголовок Content-Encoding:gzip
Content (encoded: 13.27 KiB / decoded: 35.57 KiB) - контент в 3 раза сжат gzip'ом
Допустим я умею делать socks запросы, скачивать страницу, в том числе методом chunked и получать body документа в $data.
сделав echo gzinflate($data); (функция gzuncompress делает то же самое, рекомендуется использовать gzinflate)
в итоге ловим
Warning: gzinflate(): data error in ***
Изучив мануалы, находим крайне полезные замечания (на английском)
"Согласно спецификации, CRC32 контрол сумм, блабла, а надо
Adler-32, который ожидает PHP.
поэтому надо править так
function gzuncompress_crc32($data) { $f = tempnam('/tmp', 'gz_fix'); file_put_contents($f, "\x1f\x8b\x08\x00\x00\x00\x00\x00" . $data); return file_get_contents('compress.zlib://' . $f); }
ну, как можно предположить
Warning: gzinflate() блабла
Читаю форумы и юзер контрибутед нотисе дальше
"вы все ламеры, совершенно понятно что заголовок надо обрезать (те самые \x1f\x8b кстати)
$result = gzinflate(substr($compressedData, 2))"
Warning: gzinflate() блабла
And when retrieving mod_deflate gzip'ed content and using gzinflate() to decode the data, be sure to strip the first 11 chars from the retrieved content. $dec = gzinflate(substr($enc,11));"
написан видимо тем же человеком, но уже в другом месте.
ну... как следствие Warning: gzinflate() блабла
Ну, читаем дальше
When retrieving mod_gzip'ed content and using gzinflate() to decode the data, be sure to strip the first 10 chars from the retrieved content. $dec = gzinflate(substr($enc,10));
(что в переводе значит "2 байта отстой и не работает, надо обязательно отрезать 10 байт!")
Warning: gzinflate() блабла
Большинство комментариев в багтреке пхп идут в духе "да вы батенька хидеры-то наверное не отрезали от реквеста, вот и дурак"
Покопавшись ещё с полчасика, и поскачивав исходники разных HTTP-Request классов, обнаружил ещё 2 упоминания числа 2 и 10.
Написав волшебное заклинание:
for($i=10;$i<20;$i++) echo $i.@gzinflate(substr($data,$i)); die();
я обнаружил что работает только echo gzinflate(substr($data,10)); на чём и заканчиваю историю
Прогноз погоды: число 10 - сегодня хорошее число чтобы скачать gzip. =)
P.S. итоге у меня первые 10 символов были с кодами 31,139,8,0,0,0,0,0,0,3, которые нужно всегда отрезать, а до этого как нетрудно догадаться 13,10,13,10 - двойной перевод строки который отделяет хидеры от тела документа.
Комментарии:
SmartMan
06.06.2012 16:25:00