gzipping时损坏的数据

时间:2010-04-20 14:42:07

标签: php http compression gzip

这是我为在我的网站上压缩内容而编写的脚本,该脚本位于“gzip.php”中。我使用它的方式是在我要启用gzipping的页面上我在顶部和底部包含文件我调用输出函数如下:

print_gzipped_page('javascript')

如果文件是css文件,我使用'css'作为$ type-argument,如果它是一个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 个答案:

答案 0 :(得分:3)

这种做法有点过于笨拙。而是使用ob_gzhandler。它会自动GZIP客户端支持的内容并设置必要的标题。

ob_start('ob_gzhandler');
readfile($path);

答案 1 :(得分:1)

有两件事突出:

1)您似乎没有将Content-Length标头设置为压缩数据的大小。 (也许我忽略了它。)如果你没有设置它,浏览器可能会认为你太早发送数据了。

2)您正在使用未压缩的$ size执行压缩$ content的子记录。当内部结构具有EOF标记时,某些浏览器将停止解压缩,但其他浏览器(Opera?)可能会尝试解压缩整个下载的缓冲区。这肯定会给你一个“损坏的数据”错误。您可能没有看到小缓冲区出现此问题,因为开销量和压缩量可能完全匹配。