【问题标题】:PHP Manual GZip EncodingPHP 手动 GZip 编码
【发布时间】:2011-08-07 15:03:30
【问题描述】:

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

我不再关心压缩,而是想知道它为什么不起作用。

干杯,

【问题讨论】:

  • 如果$supportsGzip 不应该Content-Length 是压缩内容的长度吗?
  • @Fanis,contents 保存缓冲区的内容,取决于 $supportsGzip 的编码或纯文本。
  • 奇怪,如果您使用 ob_gzhandler() 而不是滚动自己的压缩包装器,您会得到相同的行为吗?
  • @user687976 你说得对,我在寻找 $data 时设法错过了那一行。实际上,正如@Craig Sefton 在他的回答中提到的那样,这可能是问题吗? $data vs $content

标签: php encoding gzip compression


【解决方案1】:

嗯,我想这是因为你试图压缩一个空字符串。

我按照您提供的脚本获取了您的脚本,并在 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() 后设置标题。

【讨论】:

  • GZIP 不是加密算法,而是压缩算法。
  • 数据串是函数参数,代码是sn-p。我什至尝试了data= "Some string",但仍然没有通过测试。
  • @user687976 - 刚刚用更多信息更新了我的答案。希望对您有所帮助。
  • 如果不是$supportGzip,则无需调用header('Content-Encoding: gzip');
【解决方案2】:

我建议使用http://php.net/manual/de/function.ob-gzhandler.php,这对我来说开箱即用:

在我的 index.php 中,我只是将它放在一些输出之前:

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

它对其进行编码!

【讨论】:

  • if ($supportsGzip) { ob_start("ob_gzhandler"); echo trim(preg_replace('/\s+/', ' ', $data)); } 试过了,但还是打不开。在调用此函数之前不显示任何输出。
  • 您不需要 if() 在它前面,因为 php 会为您检查(来自文档): ob_gzhandler() 旨在用作 ob_start() 的回调函数有助于将 gz 编码的数据发送到支持压缩网页的 Web 浏览器。在 ob_gzhandler() 实际发送压缩数据之前,它会确定浏览器将接受哪种类型的内容编码(“gzip”、“deflate”或根本不接受),并将相应地返回其输出。 ...如果浏览器不支持压缩页面,则此函数返回 FALSE。
  • 有一种方法可以检查用户是否支持编码以下代码应该在文档的开头: if (substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) ob_start("ob_gzhandler ");否则 ob_start();不需要使用 ob_flush (在这种情况下是自动添加的)
【解决方案3】:

一些事情:

  1. 您可能想要添加另一个标题: header('Content-Encoding: gzip');

  2. 您正在使用 ob_end_clean,它会删除所有回显/打印的内容而不将其发送到浏览器。根据您要执行的操作,您可能需要改用 ob_flush。

  3. 为确保您的输出被缓冲和处理(如果您使用 PHP 的输出缓冲压缩,则被压缩),请确保所有 echo/print 语句都放在 ob_start 和 ob_flush 语句之间。

--然后再试一次:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-27
    • 1970-01-01
    • 1970-01-01
    • 2015-01-17
    • 2017-10-19
    • 2012-04-21
    • 1970-01-01
    相关资源
    最近更新 更多