Некоторое время назад я написал небольшую библиотеку WebSocket и обнаружил, что добавить поддержку gzip на удивление легко. Я не до конца осознавал, что deflate_init()
/ deflate_add()
/ inflate_init()
/ inflate_add()
функции были на самом деле только для PHP 7, и теперь я хотел бы иметь возможность запускать мой сервер WebSocket в среде PHP 5.
Моя проблема в том, deflate_add()
производит вывод, который немного отличается от gzdeflate()
— на один символ в тестовом примере ниже.
deflate_add()
/inflate_add()
Подход работает отлично в браузере, поэтому вывод gzdeflate()
неправильный. я догадываюсь gzdeflate()
/gzinflate()
используете zlib с различными опциями — что-то, связанное с состоянием потока, может быть? — и это заставляет все рушиться.
В конечном итоге я хочу знать, смогу ли я убедить PHP-функции zlib 5-й эпохи выводить «правильные» дефлированные данные.
Прежде всего, deflate_init()
/deflate_add()
подход, который я использовал на PHP 7:
$data = "ABC";
$ctx = deflate_init(ZLIB_ENCODING_RAW);
// unfortunately I can't find the gigantic blog post with example code
// that I learned from :(, but it contained the Ruby equivalent of the
// the substr() below. I blinked at it a bit but apparently this is how
// it's done.
$deflated = substr(deflate_add($ctx, $data, ZLIB_SYNC_FLUSH), 0, -4);
// $deflated is now "rtr\6\0"
$ictx = inflate_init(ZLIB_ENCODING_RAW);
$data2 = inflate_add($ictx, $deflated, ZLIB_NO_FLUSH);
// $data2 is now "ABC"
Вот что произойдет, если я использую gzdeflate()
/gzinflate()
:
$data = "ABC";
$deflated = gzdeflate($data, 9, ZLIB_ENCODING_RAW);
// $deflated is now "str\6\0"
$output = gzinflate($deflated);
// $output is now "ABC"
Пытаясь gzinflate()
выход inflate_add()
производит data error
. Как TL; DR:
print gzinflate("rtr\6\0")."\n"; // will bomb out
print gzinflate("str\6\0")."\n"; // prints "ABC"
То, что вы называете правильно, неверно, а то, что вы называете неправильно, правильно.
С deflate_add
вы намеренно создаете неопределенный, то есть недопустимый, дефляционный поток. Я понятия не имею. (По-видимому, и вы, поскольку это произошло из «гигантского поста в блоге», который вы не можете найти.) Это делается с помощью ZLIB_SYNC_FLUSH
который завершает текущий блок deflate и добавляет пустой сохраненный блок. substr(,,-4)
удаляет большую часть этого пустого сохраненного блока в конце, оставляя вас с неполным, недопустимым потоком инфляции, преждевременно заканчивающимся в середине сохраненного блока.
gzdeflate
с другой стороны, создается правильно завершенный поток дефлятирования, причем один блок дефляции помечается как последний блок. Единственная разница между двумя потоками — это первый (наименее значимый) бит, который равен 1, чтобы обозначить последний блок.
Вы не говорите, как правильно завершенный поток дефлята «заставляет все рушиться». В любом случае вы можете создать правильно завершенный поток deflate_add
используя ZLIB_FINISH
вместо ZLIB_SYNC_FLUSH
и отказываясь от substr
,
Нет способа создать неверный поток с дефляцией gzdeflate
, если ты об этом. Вы не можете просто изменить первый бит, так как для большей строки последний блок может не быть первым блоком.
Других решений пока нет …