Поврежденные данные при распаковке - PullRequest
0 голосов
/ 20 апреля 2010

Это скрипт, который я написал для распаковки контента на моем сайте, который находится в gzip.php. Я использую его так: на страницах, где я хочу включить gzipping, я включаю файл вверху, а внизу вызываю функцию вывода так:

print_gzipped_page('javascript')

Если файл является css-файлом, я использую 'css' в качестве аргумента $ type, а если это php-файл, я вызываю функцию, не объявляя никаких аргументов. Скрипт прекрасно работает во всех браузерах, кроме Opera, которая выдает ошибку, утверждающую, что не может декодировать страницу из-за поврежденных данных. Может кто-нибудь сказать мне, что я сделал не так?

<?php
function print_gzipped_page($type = false) {
    if(headers_sent()){
        $encoding = false;
    }
    elseif( strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'x-gzip') !== false ){
        $encoding = 'x-gzip';
    }
    elseif( strpos($_SERVER['HTTP_ACCEPT_ENCODING'],'gzip') !== false ){
        $encoding = 'gzip';
    }
    else{
        $encoding = false;
    }
    if ($type!=false) {
        $type_header_array = array("css" => "Content-Type: text/css", "javascript" => "Content-Type: application/x-javascript");
        $type_header = $type_header_array[$type];
    }

    $contents = ob_get_contents();
    ob_end_clean();
    $etag = '"' .  md5($contents) . '"';
    $etag_header = 'Etag: ' . $etag;
    header($etag_header);

    if ($type!=false) {
        header($type_header);
    }

    if (isset($_SERVER['HTTP_IF_NONE_MATCH']) and $_SERVER['HTTP_IF_NONE_MATCH']==$etag) {
        header("HTTP/1.1 304 Not Modified");
        exit();
    }

    if($encoding){
        header('Content-Encoding: '.$encoding);
        print("\x1f\x8b\x08\x00\x00\x00\x00\x00");
        $size = strlen($contents);
        $contents = gzcompress($contents, 9);
        $contents = substr($contents, 0, $size);
    }

    echo $contents;
    exit();
}

ob_start();
ob_implicit_flush(0);
?>

Дополнительная информация: скрипт работает, если длина сжатого документа составляет всего 10-15 символов.

Спасибо за помощь, исправленная версия:

<?php
function print_gzipped_page($type = false) {
    if(headers_sent()){
        $encoding = false;
    }
    elseif( strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'x-gzip') !== false ){
        $encoding = 'x-gzip';
    }
    elseif( strpos($_SERVER['HTTP_ACCEPT_ENCODING'],'gzip') !== false ){
        $encoding = 'gzip';
    }
    else{
        $encoding = false;
    }
    if ($type!=false) {
        $type_header_array = array("css" => "Content-Type: text/css", "javascript" => "Content-Type: application/x-javascript");
        $type_header = $type_header_array[$type];
        header($type_header);
    }

    $contents = ob_get_contents();
    ob_end_clean();

    $etag = '"' .  md5($contents) . '"';
    $etag_header = 'Etag: ' . $etag;
    header($etag_header);

    if (isset($_SERVER['HTTP_IF_NONE_MATCH']) and $_SERVER['HTTP_IF_NONE_MATCH']==$etag) {
        header("HTTP/1.1 304 Not Modified");
        exit();
    }

    if($encoding){
        header('Content-Encoding: ' . $encoding);
        $contents = gzencode($contents, 9);
    }

    $length = strlen($contents);
    header('Content-Length: ' . $length);
    echo $contents;
    exit();
}

ob_start();
ob_implicit_flush(0);
?>

Ответы [ 2 ]

3 голосов
/ 29 апреля 2010

Этот подход слишком неуклюжий.Скорее используйте ob_gzhandler.Он автоматически GZIP контент, который поддерживает его клиент и установить необходимые заголовки.

1 голос
/ 20 апреля 2010

Две вещи выделяются:

1) вы, похоже, не устанавливаете заголовок Content-Length для размера сжатых данных. (Возможно, я упустил это из виду.) Если вы не установите это, браузер может подумать, что вы отправили данные слишком рано.

2) вы делаете подстроку сжатого содержимого $ с несжатым размером $. Некоторые браузеры прекращают распаковку, когда внутренняя структура имеет маркер EOF, но другие браузеры (Opera?) Могут пытаться распаковать весь загруженный буфер. Это определенно даст вам ошибку «поврежденные данные». Вы можете не видеть эту проблему с небольшими буферами, потому что объем служебных данных и степень сжатия могут точно совпадать.

...