ob_gzhandler 导致 PHP 输出缓冲、内容编码错误?
谁能解释为什么我收到以下错误?
在代码中,如果 echo $gz;
被注释掉,我不会收到错误(但也没有输出!),如果不是,我会得到(来自 Firefox),
内容编码错误
<小时>您的页面 正在尝试查看无法显示 因为它使用了无效或 不支持的压缩形式。
感谢您的帮助,代码如下:
ob_start('ob_gzhandler') OR ob_start();
echo 'eh?';
$gz = ob_get_clean();
echo $gz;
Can anyone explain why I am receiving the following error?
In the code, if the echo $gz;
is commented out I receive no error (but also no output!), if it isn't I get (from Firefox),
Content Encoding Error
The page you
are trying to view cannot be shown
because it uses an invalid or
unsupported form of compression.
Thanks for your help, here's the code:
ob_start('ob_gzhandler') OR ob_start();
echo 'eh?';
$gz = ob_get_clean();
echo $gz;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的应用程序的输出应该只包含一种输出编码。如果您有多个编码不同的块,那么浏览器将得到无法处理的结果。因此出现编码错误。
Kohana 本身已经使用了输出缓冲区。如果您想将其与 ob_gzhandler 输出缓冲区结合起来,您需要在 kohana 初始化它自己的缓冲区之前启动缓冲区。那是因为输出缓冲区是可堆叠的。当 kohana 完成它的输出缓冲时,您的输出缓冲将适用:
因此,每当 kohana 完成一些输出时,这些块就会传递到您的输出回调中(
ob_gzhandler()
) 并将进行 gz 编码。然后,浏览器应该只获取 gz 编码的数据,因为它是最顶层的输出缓冲区。
使用 ob_gzhandler 并手动回显缓冲区
如果您使用 ob_start('ob_gzhandler') 让 PHP 处理压缩,然后您
echo ob_get_clean()
,您将产生不可靠的输出。这与压缩和输出缓冲的工作方式有关:PHP 将缓冲输出块。这意味着,PHP 开始压缩输出,但保留一些字节继续压缩。因此 ob_get_clean() 返回缓冲区迄今为止压缩的部分。通常结果并不完整。
要解决这个问题,请先刷新缓冲区:
并确保此后不再有任何输出。
如果您让 PHP 到达脚本的末尾,它会处理这个问题:刷新并输出。
现在您需要手动调用 ob_flush() 来显式让 PHP 通过回调推送缓冲区。
使用 Curl 检查 HTTP 压缩问题
由于 Firefox 将返回错误,因此需要另一个工具来检查导致编码错误的原因。您可以使用
curl
来跟踪发生的情况:将请求启用压缩的 URL同时显示所有未编码的响应标头和正文。这是必要的,因为 PHP 根据请求标头透明地启用/禁用 ob_gzhandler 回调的压缩。
响应还表明 PHP 也会设置所需的响应标头。所以不需要手动指定它们。这甚至是危险的,因为仅通过调用 ob_start('ob_gzhandler') 您无法判断是否启用了压缩。
如果压缩被破坏,
curl
将给出错误描述,但不会显示正文。以下是由错误的 php 脚本生成的不完整输出引发的这样一条curl错误消息:
通过添加
--raw
开关,您甚至可以深入了解原始响应正文:这可以给人留下什么印象出了问题,就像体内未压缩的部分一样。
The output of your application should only contain one output encoding. If you have multiple chunks that are encoded differently, then the browser will get a result that it is impossible to work with. Hence the encoding error.
Kohana itself makes already use of the output buffer. If you want to combine that with your ob_gzhandler output buffer, you need to start your buffer before kohana initialized it's own. That's because output buffer are stackable. When kohana has finished it's output buffering, yours will apply:
So whenever kohana has done some output, these chunks will get passed on into your output callback (
ob_gzhandler()
) and will be gz-encoded.The browser should then only get gz-encoded data as it was the output buffer at the topmost level.
Using ob_gzhandler and manually echo'ing the buffer
If you make use of
ob_start('ob_gzhandler')
to let PHP deal with the compression and you thenecho ob_get_clean()
, you will create an unreliable output. That's related to how the compression togther with output buffering works:PHP will buffer chunks of output. That means, PHP starts to compress the output but keeps some bytes to continue compressing. So ob_get_clean() returns the so-far compressed part of the buffer. Often that result is not complete.
To deal with that, flush the buffer first:
And ensure you don't have any more output after that.
If you would have PHP reached the end of your script, it would have taken care of that: Flushing and outputting.
Now you need to manually call
ob_flush()
to explicitly make PHP push the buffer through the callbacks.Inspecting HTTP Compression Problems with Curl
As firefox will return an error, another tool to inspect what's causing the encoding error is needed. You can use
curl
to track what's going on:Will request the URL with compression enabled while displaying all response headers and the body unencoded. This is necessary as PHP transparently enables / disables compression of the
ob_gzhandler
callback based on request headers.A response also shows that PHP will set the needed response headers as well. So no need to specify them manually. That would be even dangerously, because only by calling
ob_start('ob_gzhandler')
you can not say if compression is enabled or not.In case the compression is broken,
curl
will give an error description but would not display the body.Following is such a curl error message provoked with an incompletely generated output by a faulty php script:
By adding the
--raw
switch, you can even peak into the raw response body:That can give an impression what's going wrong, like uncompressed parts within the body.
这就是 phpharo 所做的:
This is what phpharo does: