PHP-кодирование GZip вручную
Я тестировал свой сайт со скоростью страницы, и результат был около 70/100. Включить сжатие было первым и самым важным фактором в замедлении.
Я знаю, что могу это сделать, изменив php.ini, чтобы автоматически это сделать, но меня больше интересовал ручной метод (gzencode
).
Проблема заключается либо в том, что все браузеры не могут открыть веб-сайт (Firefox: "Страница, которую вы пытаетесь просмотреть, не может быть показана, поскольку она использует недопустимую или неподдерживаемую форму сжатия". Chrome: "303, кодирование содержимого ERR" и т.д.), либо они отображают закодированную строку.
Live Headers показывает, что браузер принимает кодировку, а ответ имеет тип содержимого, но он все еще не работает.
GET / HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 5827
Vary: Accept-Encoding
private function _compress($data) {
//return trim(preg_replace(array('/\>[^\S ]+/s','/[^\S ]+\</s','/(\s)+/s'), array('>','<','\\1'), $data));
$supportsGzip = strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false;
ob_start();
if ($supportsGzip) {
echo gzencode(trim(preg_replace('/\s+/', ' ', $data)), 9);
} else {
echo $data;
}
$content = ob_get_contents();
header("content-type: text/html; charset: UTF-8");
header("cache-control: must-revalidate");
$offset = 60 * 60;
$expire = "expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
header($expire);
header('Content-Length: ' . strlen($content));
header('Vary: Accept-Encoding');
ob_end_clean();
echo $content;
}
Если я изменил Content-Encoding на zlib, я получу закодированную строку:
‹������ÕZÿsÛ¶ÿW^‘¥²o‘¨/–-Ë–ÚØ‰_Ôµ•õÚ_v I°I‚!A©j–Öºnçÿb·»%ÍÚë²nëå?‘þ›=€¤L)’,ÛIw>ŸEâxïáƒ÷°ùÞ½O¶Ÿï߇Žtlؼµ·» $kŸ•¶ ã^ã<܃•\¾� Ÿº—\¸Ô6ŒûŽ"^Õ0z½^®WÊ ¿m4ÅjŰ…XÎ’©Ã¦ænS·]#ÌÕF-|8LRPL²ìIÈ»5²-\É\™mô=FÀŒJ5"Ù—RóÝ�³Cý€ÉZ([ÙŠb%¹´YýÑãáîcx}±iD´˜¿KV#4"á§x>¬°à®íÒ ãpÅËæî1øÌ®‘@öm
Мне больше не нужно беспокоиться о сжатии, так как я хочу знать, почему он не работает.
Приветствия,
Ответы
Ответ 1
Ну, я думаю, это потому, что вы пытаетесь сжать пустую строку.
Я взял ваш script, как вы его дали, и запустил его в FF и IE.
Оба отказались, и FF сказал, что была проблема (как вы описали).
Однако я заметил, что $data - это пустая строка.
Когда я установил $data = "Some test data.";
в верхней части файла, он сразу сработал (браузер отобразил "Некоторые тестовые данные" ) и, проверяя Firebug, я вижу правильные заголовки.
Content-Encoding gzip
Content-Length 68
Vary Accept-Encoding
Content-Type text/html
Изменить: Кроме того, просто чтобы указать, ваш if ($supportsGzip) {
немного нечетный, потому что ваше условие else должно действительно выводить $data
, а не $content
.
Изменить: Хорошо, основываясь на вашей пересмотренной функции выше, есть две ключевые проблемы.
Основная проблема связана с тем, что вы уничтожаете заголовки, вызывая ob_end_clean()
. Комментарий к PHP Docs гласит, что "ob_end_clean() отменяет заголовки".
Это означает, что любые заголовки, которые вы установили перед вызовом ob_end_clean()
, будут стерты. Кроме того, ваша исправленная функция также не отправляет заголовок кодировки gzip.
Я должен сказать, что, вероятно, нет необходимости даже использовать ob_start и связанные функции здесь. Попробуйте следующее:
function _compress( $data ) {
$supportsGzip = strpos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip' ) !== false;
if ( $supportsGzip ) {
$content = gzencode( trim( preg_replace( '/\s+/', ' ', $data ) ), 9);
header('Content-Encoding: gzip');
} else {
$content = $data;
}
$offset = 60 * 60;
$expire = "expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
header("content-type: text/html; charset: UTF-8");
header("cache-control: must-revalidate");
header( $expire );
header( 'Content-Length: ' . strlen( $content ) );
header('Vary: Accept-Encoding');
echo $content;
}
_compress( "Some test data" );
Это работает в IE и FF, но у меня не было времени проверить другие браузеры.
Если вы действительно должны использовать ob_start и связанные функции, убедитесь, что вы устанавливаете заголовки после вызова ob_end_clean()
.
Ответ 2
Я предлагаю использовать http://php.net/manual/de/function.ob-gzhandler.php, это работает для меня:
В моем index.php я просто помещаю это перед некоторым выходом:
/**
* Enable GZIP-Compression for Browser that support it.
*/
ob_start("ob_gzhandler");
И он кодирует его!
Ответ 3
Несколько вещей:
-
Возможно, вы захотите добавить другой заголовок:
header ('Content-Encoding: gzip');
-
Вы используете ob_end_clean, который удаляет все эхо/печатные материалы, не отправляя их в браузер. В зависимости от того, что вы пытаетесь сделать, вы можете использовать ob_flush вместо этого.
-
Чтобы убедиться, что ваш вывод буферизирован и обработан (и сжат, если вы используете сжатие буферизации вывода PHP), убедитесь, что все инструкции echo/print размещены BETWEEN с объектами ob_start и ob_flush.
- и повторите попытку:)