PHP 手动 GZip 编码

2022-08-30 22:15:27

我正在用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;
}

如果我将内容编码更改为 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

好吧,我认为这是因为你试图压缩一个空字符串。

我按照你给出的方式获取了你的脚本,并在FF和IE中运行它。

两者都失败了,FF说有一个问题(就像你描述的那样)。

但是,我注意到$data是一个空字符串。

当我在文件顶部设置时,它立即工作(浏览器显示“一些测试数据”),并检查Firebug,我可以看到正确的标题。$data = "Some test data.";

Content-Encoding    gzip
Content-Length  68
Vary    Accept-Encoding
Content-Type    text/html

编辑:另外,只是为了指出,你的有点奇怪,因为你的其他条件实际上应该回声,而不是。if ($supportsGzip) {$data$content

编辑:好的,根据您上面修改的功能,有两个关键问题。

主要问题与以下事实有关:您正在通过调用 来擦除标头。PHP Docs上的一条评论指出“ob_end_clean()确实会丢弃标头”。ob_end_clean()

这意味着您在调用之前设置的任何标头都将被擦除。此外,修改后的函数也不会发送 gzip 编码标头。ob_end_clean()

我必须说,这里可能甚至没有必要使用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,这对我来说是开箱即用的:

在我的索引中.php我只是把它放在一些输出之前:

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

它编码它!


推荐