Буферизация вывода PHP, ошибка кодирования содержимого, вызванная ob_gzhandler?

Может кто-нибудь объяснить, почему я получаю следующую ошибку?

В коде, если echo $gz; закомментирован, я не получаю никакой ошибки (но также и никакого вывода!), если это не получается (из Firefox),

Ошибка кодирования содержимого


Страница, на которой вы пытаться просмотреть не могут быть показаны потому что он использует недопустимый или неподдерживаемая форма сжатия.


Спасибо за вашу помощь, вот код:

ob_start('ob_gzhandler') OR ob_start();
echo 'eh?';
$gz = ob_get_clean();
echo $gz;

Ответ 1

Вывод вашего приложения должен содержать только одну выходную кодировку. Если у вас есть несколько фрагментов, которые кодируются по-разному, то браузер получит результат, с которым невозможно работать. Следовательно, ошибка кодирования.

Сам Kohana уже использует выходной буфер. Если вы хотите совместить это с вашим выходным буфером ob_gzhandler, вам нужно запустить свой буфер до того, как кохана инициализировала его. Это потому, что выходной буфер является штабелируемым. Когда кохана закончит буферизацию вывода, ваш будет применяться:

ob_start('ob_gzhandler'); # your buffer:
   ob_starts and ends by kohana

Поэтому всякий раз, когда kohana делает какой-то вывод, эти куски будут переданы в ваш обратный вызов (ob_gzhandler()) и будет gz- закодирован.

Затем браузер должен получить только gz-кодированные данные, поскольку это был выходной буфер на самом верхнем уровне.

Использование ob_gzhandler и ручное повторение буфера

Если вы используете ob_start('ob_gzhandler'), чтобы PHP имел дело с сжатием, а затем echo ob_get_clean(), вы создадите ненадежный вывод. Это связано с тем, как работает сжатие с выходной буферизацией:

PHP будет заполнять куски вывода. Это означает, что PHP начинает сжимать вывод, но сохраняет некоторые байты для продолжения сжатия. Таким образом, ob_get_clean() возвращает так называемую сжатую часть буфера. Часто этот результат не завершен.

Чтобы справиться с этим, сначала промойте буфер:

ob_start('ob_gzhandler') OR ob_start();
echo 'eh?';
ob_flush();
$gz = ob_get_clean();
echo $gz;

И убедитесь, что после этого у вас больше нет выходных данных.

Если бы у вас был PHP, который достиг бы конца вашего script, он бы позаботился об этом: Промывка и вывод.

Теперь вам нужно вручную вызвать ob_flush(), чтобы явным образом заставить PHP вытолкнуть буфер через обратные вызовы.

Проверка проблем сжатия HTTP с помощью Curl

Когда firefox вернет ошибку, потребуется другой инструмент для проверки того, что вызывает ошибку кодирования. Вы можете использовать curl, чтобы отслеживать, что происходит:

curl --compress -i URL

Будет запрашивать URL с включенной компрессией при отображении всех заголовков ответов и неэкодированного тела. Это необходимо, так как PHP прозрачно включает/отключает сжатие обратного вызова ob_gzhandler на основе заголовков запросов.

Ответ также показывает, что PHP также установит нужные заголовки ответов. Поэтому нет необходимости указывать их вручную. Это было бы опасно, потому что только при вызове ob_start('ob_gzhandler') вы не можете сказать, включено ли сжатие.

В случае нарушения сжатия, curl даст описание ошибки, но не отобразит тело.

Ниже приводится такое сообщение об ошибке завивки, вызванное неполностью генерируемым выходом с ошибкой php script:

HTTP/1.1 200 OK
X-Powered-By: PHP/5.3.6
Content-Encoding: gzip
...

curl: (23) Error while processing content unencoding: invalid code lengths set

Добавив переключатель --raw, вы можете даже пик в тело необработанного ответа:

curl --compress --raw -i URL

Это может создать впечатление, что происходит не так, как несжатые части тела.

Ответ 2

Это то, что делает phpharo:

/** output buffring */
if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false)
{
 ob_start('ob_gzhandler'); ob_start();
}
else
{
 ob_start();
}