PHP-руководство GZip-кодирование - PullRequest
12 голосов
/ 18 апреля 2011

Я тестировал свой веб-сайт с Page Speed, и результат был около 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

Меня больше не беспокоит получение сжатия столько, сколько я хочучтобы знать, почему это не работает.

Приветствия,

Ответы [ 3 ]

12 голосов
/ 18 апреля 2011

Ну, я думаю, это потому, что вы пытаетесь сжать пустую строку.

Я взял ваш скрипт так, как вы его дали, и запустил его в 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().

6 голосов
/ 18 апреля 2011

Я бы предложил использовать http://php.net/manual/de/function.ob-gzhandler.php,, для меня это работает из коробки:

В моем index.php я просто помещаю это перед выводом:

    /**
     * Enable GZIP-Compression for Browser that support it.
     */
    ob_start("ob_gzhandler");

И это кодирует!

0 голосов
/ 21 апреля 2011

Несколько вещей:

  1. Возможно, вы захотите добавить еще один заголовок: заголовок ('Content-Encoding: gzip');

  2. Вы используете ob_end_clean, который удаляет весь отраженный / напечатанный контент без отправки его в браузер. В зависимости от того, что вы пытаетесь сделать, вы можете вместо этого использовать ob_flush.

  3. Чтобы убедиться, что ваш вывод буферизуется и обрабатывается (и сжимается, если вы используете сжатие буферизации вывода PHP), убедитесь, что все операторы echo / print помещены МЕЖДУ утверждениями ob_start и ob_flush.

- и попробуйте еще раз:)

...