PHP输出缓冲,ob_gzhandler引起的内容编码错误?

9
有人能解释一下我为什么会收到以下错误吗?
如果代码中的echo $gz;被注释掉,我就不会收到任何错误(但也没有输出!),如果没有注释,我就会从Firefox中得到以下错误: 内容编码错误

由于使用了无效或不支持的压缩形式,无法显示您要查看的页面。


感谢您的帮助,以下是代码:
ob_start('ob_gzhandler') OR ob_start();
echo 'eh?';
$gz = ob_get_clean();
echo $gz;

你是否设置了合适的Content-Encoding头信息?顺便提一下,这里的'eh?'没有进行gzip压缩。 - Kemo
@Kemo 我没有手动设置 Content-Encoding 头,但是 Firebug 显示它已经正确设置了,我现在也尝试手动设置了,但是没有任何区别。我知道在我的示例中 "eh?" 没有被压缩 - 正如我在问题中提到的那样,我只是用它来显示无论我返回压缩内容与否都会出现错误。我想我会让它更清楚一些。谢谢。 - tjm
2个回答

16

你的应用程序输出应只包含一种输出编码。如果有多个块使用不同的编码,则浏览器将无法处理结果。因此产生编码错误。

Kohana本身已经使用了输出缓冲区。如果你想要将其与ob_gzhandler输出缓冲区结合使用,你需要在kohana初始化自己之前启动你的缓冲区。这是因为输出缓冲区是可以堆叠的。当kohana完成其输出缓冲时,你的缓冲区将被应用:

ob_start('ob_gzhandler'); # your buffer:
   ob_starts and ends by kohana

每当kohana进行一些输出时,这些块将传递到您的输出回调函数(ob_gzhandler())中并进行gz编码。

然后,浏览器应该只获取到经过gz编码的数据,因为它是顶级输出缓冲区。

使用ob_gzhandler并手动echo缓冲区

如果您使用ob_start('ob_gzhandler')让PHP处理压缩,然后echo ob_get_clean(),则会创建不可靠的输出。这与压缩与输出缓冲区一起工作的方式有关:

PHP将缓存输出块。这意味着PHP开始压缩输出但保留一些字节以继续压缩。因此,ob_get_clean()返回到目前为止已压缩的缓冲区部分。通常,该结果不完整。

为了解决这个问题,请先刷新缓冲区:

ob_start('ob_gzhandler') OR ob_start();
echo 'eh?';
ob_flush();
$gz = ob_get_clean();
echo $gz;

同时确保你之后没有更多的输出。

如果你的PHP脚本已经到达了结尾,它会自动处理这个问题:刷新并输出缓冲区。

现在,你需要手动调用ob_flush()来显式地让PHP通过回调函数推送缓冲区。

使用Curl检查HTTP压缩问题

由于Firefox会返回错误信息,所以需要另一个工具来检查编码错误的原因。你可以使用curl跟踪发生了什么:

curl --compress -i URL

将启用压缩并显示所有响应头和未编码的正文来请求URL。这是必要的,因为PHP会根据请求头透明地启用/禁用ob_gzhandler回调的压缩。

响应还显示PHP将设置所需的响应头,因此无需手动指定它们。这甚至是危险的,因为仅通过调用ob_start('ob_gzhandler')无法确定是否启用了压缩。

如果压缩损坏,curl会给出错误描述但不会显示正文。

以下是使用有缺陷的PHP脚本生成的不完整输出引发的curl错误消息:

HTTP/1.1 200 OK
X-Powered-By: PHP/5.3.6
Content-Encoding: gzip
...

curl: (23) Error while processing content unencoding: invalid code lengths set

通过添加--raw开关,您甚至可以查看原始响应正文:

curl --compress --raw -i URL

这可以给人一种什么出了问题的印象,比如身体内未经压缩的部分。


抱歉,当您正在输入答案时,我刚刚完全重写了问题。如果您的答案解决了原始问题,我会回滚,但是正如您在更新的问题中所看到的那样 - 我可能过于匆忙地认为这是一个Kohana问题,即使我不通过Kohana路由,我仍然会遇到相同的错误。谢谢您的回复 - 我现在会认真阅读它。 - tjm
好的,谢谢。我尝试使用curl,似乎响应是未经编码的,但带有Content-Encoding: gzip,因此在解码时出现错误。 - tjm
测试我添加的代码示例。它可以正常运行。我使用curl和firefox进行了跟踪。 - hakre
是的,对我来说也很新奇,有这么多细节。如果这也解决了 Kohana 的问题,请告诉我。 - hakre
我会做。现在我再看一遍,但我又有些困惑了,因为 ob_get_clean 实际上不会包含任何内容,因为 ob_flush 会丢弃缓冲区的内容。 - tjm
谢谢,那是完美的解决方案! - Jaymin Gajjar

0

这就是 phpharo 的作用:

/** output buffring */
if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false)
{
 ob_start('ob_gzhandler'); ob_start();
}
else
{
 ob_start();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接