Буферизация вывода PHP, ошибка кодирования содержимого, вызванная ob_gzhandler? - PullRequest
8 голосов
/ 19 июня 2011

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

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

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


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


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

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

Ответы [ 2 ]

15 голосов
/ 19 июня 2011

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

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

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 достиг конца вашего скрипта, он бы позаботился об этом: очистка и вывод.

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

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

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

curl --compress -i URL

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

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

Если сжатие нарушено, curl выдаст описание ошибки, но не отобразит тело.

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

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

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

0 голосов
/ 04 ноября 2013

Вот что делает 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();
}
...