设为首页 收藏本站
查看: 671|回复: 0

[经验分享] php关于ob_start('ob_gzhandler')启用GZIP压缩的bug

[复制链接]

尚未签到

发表于 2015-8-25 11:14:46 | 显示全部楼层 |阅读模式
如果使用ob_start("ob_gzhandler");
则ob_clean()后面的输出将不显示,这是个bug,
可以用ob_end_clean();ob_start("ob_gzhandler"); 代替ob_clean();
否则后面输出内容将是空。  <?php
error_reporting(E_ALL);
ob_start("ob_gzhandler");
echo "content";
ob_clean();
echo "more content";
?>
上面的代码期望输出more content实际上什么内容也不会输出。
  下面就正常了
<?php
error_reporting(E_ALL);
ob_start("ob_gzhandler");
echo "content";
ob_end_clean();
ob_start("ob_gzhandler");
echo "more content";
?>
  下面自定义一个回调函数再测试
<?php
function my_ob_gzhandler($buffer,$mod){
   header("Content-Encoding: gzip");
   return gzencode($buffer, 9, FORCE_GZIP);
}
  error_reporting(E_ALL);
ob_start("my_ob_gzhandler");
echo "content";
ob_clean();
echo "more content";
?>
上面是正常的,但使用ob_end_clean代替ob_clean后又会导致后面的输出不会显示。
  因此即使是下面的代码依然会在使用ob_clean或者ob_end_clean后会导致输出为空。
<?php
if (ini_get('zlib.output_compression')) {
   if (ini_get('zlib.output_compression_level') != 9) {
      ini_set('zlib.output_compression_level', '9');
   }
   ob_start();
} else {
   if (strstr($_SERVER['HTTP_ACCEPT_ENCODING'], "gzip")) {
      ob_start("ob_gzhandler");
   } else {
      ob_start();
   }
}
?>
  最稳定的启用页面压缩的方法应该类似下面
<?php
if(extension_loaded('zlib')) {
ini_set('zlib.output_compression', 'On');
ini_set('zlib.output_compression_level', '3');
}
?>
  但如果一定要使用ob_gzhandler来启用页面压缩就要注意本文的第一句话了。
  事实上,下面的代码只是浏览器不显示
error_reporting(E_ALL);
ob_start("ob_gzhandler");
echo "content";
ob_clean();
echo "more content";
  但如果测试一下
  telnet localhost 80
GET /test.php HTTP/1.0
<Enter>
<Enter>
  将会返回如下信息
  HTTP/1.1 200 OK
Date: Fri, 20 Feb 2009 15:40:17 GMT
Server: Apache/2.2.6 (Win32) PHP/5.2.5
X-Powered-By: PHP/5.2.5
Vary: Accept-Encoding
Content-Length: 12
Connection: close
Content-Type: text/html
  more content
  失去了跟主机的连接。
  可以看出more content已经输出
  但为何浏览器不显示呢?
  下面引用http://bugs.php.net/bug.php?id=34071


[10 Aug 2005 6:08pm UTC] dennis at nocertainty dot com Description:
------------
When using ob_start('ob_gzhandler') and ob_clean() the output buffer is
destroyed, and no ob_* function works anymore. It seems that PHP4 had
this problem as well (http://bugs.php.net/bug.php?id=29125)
Reproduce code:
---------------
<?php
ob_start('ob_gzhandler');
echo 'Should NOT be shown';
ob_clean();
echo 'Should be shown';
?>
Expected result:
----------------
"Should be shown" should've been printed, instead nothing is returned,
and nothing displays anymore.

[10 Aug 2005 6:14pm UTC] tony2001@php.net Can't reproduce.
Please try with PHP CLI and tell what SAPI you're using.

[10 Aug 2005 6:19pm UTC] dennis at nocertainty dot com It works with PHP CLI.
SAPI: cgi-fcgi

[10 Aug 2005 6:39pm UTC] tony2001@php.net Still can't reproduce, even with FCGI.
Does this work for you:
<?php
function foo($data) {
return $data;
}
ob_start('foo');
echo 'Should NOT be shown';
ob_clean();
echo 'Should be shown';
?>
?

[10 Aug 2005 6:50pm UTC] dennis at nocertainty dot com Yes, that works. But as soon as I use ob_gzhandler, instead of foo,
nothing is displayed.
I run PHP4 and PHP5 at the same time (port 80 is PHP4.3.4, port 83 is
PHP5Dev). Could it be that the bug is caused by my PHP4 installation?

[10 Aug 2005 6:56pm UTC] tony2001@php.net Are you sure there is nothing shown in the "View Source" tab?
I'm almost sure your browser just hides binary output from you. So try
this:
telnet localhost 80
GET /script.php HTTP/1.0
<Enter>
<Enter>

[10 Aug 2005 7:03pm UTC] dennis at nocertainty dot com You're right, that works, and I get the correct result.

[10 Aug 2005 7:20pm UTC] rasmus@php.net That's not a very good test since ob_gzhandler checks the request's
accept-encoding and since your telnet test didn't specify that you could
accept gzip or deflate, then the gzhandler simply didn't do anything.

[10 Aug 2005 7:21pm UTC] tony2001@php.net Not PHP problem then.

[10 Aug 2005 7:44pm UTC] dennis at nocertainty dot com Rasmus is right. The telnet thing works because ob_gzhandler doesn't do
anything. As soon as a specify a Content-Encoding: gzip header, nothing
gets displayed again. So it's not my browser that's causing the problem.

[10 Aug 2005 7:47pm UTC] dennis at nocertainty dot com Also, I disabled PHP4 in my http.conf file, and it still doesn't work
properly in PHP5Dev. So I still believe there's a bug in PHP5.

[10 Aug 2005 8:12pm UTC] tony2001@php.net Then provide more info about it; look into the apache logs; try on
another server and with another PHP version etc etc.
As I've already said, it works perfectly here.

[11 Aug 2005 8:54pm UTC] dennis at nocertainty dot com I found someone else who has the same problem as me:
http://www.sitepoint.com/forums/showpost.php?p=2093119&postcount=5
However, I can't find any specific information. I looked through my
Apache error log, and the only thing I found was:
[Wed Aug 10 18:59:56 2005] [error] [client 127.0.0.1] request failed:
erroneous characters after protocol string: \\xff\\xfb\\x1f\\xff\\xfb
\\xff\\xfb\\x18\\xff\\xfb'\\xff\\xfd\\x01\\xff\\xfb\\x03\\xff\\xfd\\x03G
ET /gzip2.php HTTP/1.0
[Wed Aug 10 19:00:21 2005] [error] [client 127.0.0.1] request failed:
erroneous characters after protocol string: \\xff\\xfb\\x1f\\xff\\xfb
\\xff\\xfb\\x18\\xff\\xfb'\\xff\\xfd\\x01\\xff\\xfb\\x03\\xff\\xfd\\x03G
ET /gzip2.php HTTP/1.0
But I'm not sure if that's entirely relevant. But there's nothing more
that's related to it.

[11 Aug 2005 11:12pm UTC] sniper@php.net 1) Check your php.ini settings (how they differ to whatever you used as
base for your php.ini, -dist or -recommended)
2) Set error_reporting to E_ALL and try again..

[14 Aug 2005 11:10pm UTC] dehstil at gmail dot com I've reproduced the bug. I've been wondering why my script wouldn't run
until I saw this bug.  I'm using apache server on win xp with php 4 as a
module.
The above code produced the bug:
<?php
ob_start('ob_gzhandler');
echo 'Should NOT be shown';
ob_clean();
echo 'Should be shown';
?>
With further debuging this doesn't work either:
<?php
function handler($buffer,$mode){
$buffer=ob_gzhandler($buffer,$mode);
return $buffer;
}
ob_start('handler');
echo 'Should NOT be shown';
ob_clean();
echo 'Should be shown';
?>
I noticed that the content-length in my headers was non-zero so I tried
this and lo and behold:
<?php
function handler($buffer,$mode){
$buffer=ob_gzhandler($buffer,$mode);
header('Content-Encoding:');
header('Content-Type: text/plain');
header('Vary:');
return bin2hex($buffer);
}
ob_start('handler');
echo 'Should NOT be shown';
ob_clean();
echo 'Should be shown';
?>
I realized the bug is sending bad gz binary but for some reason the
following code did work...:
<?php
function handler($buffer,$mode){
$buffer=ob_gzhandler($buffer,$mode);
header('Content-Encoding:');
header('Content-Type: text/plain');
header('Vary:');
return gzuncompress($buffer);
}
ob_start('handler');
echo 'Should NOT be shown';
ob_clean();
echo 'Should be shown';
?>
To my surprise, this didn't, thus confusing me:
<?php
function handler($buffer,$mode){
$buffer=ob_gzhandler($buffer,$mode);
header('Content-Encoding:');
header('Content-Type: text/plain');
header('Vary:');
return 'test'.gzuncompress($buffer);
}
ob_start('handler');
echo 'Should NOT be shown';
ob_clean();
echo 'Should be shown';
?>
I'll be looking for the source on cvs and report back to ya!

[19 Aug 2005 1:00am UTC] php-bugs at lists dot php dot net No feedback was provided for this bug for over a week, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".

[27 Jan 2006 4:32pm UTC] greg at xdissent dot com this appears to be ob_gzhandler's fault.  it seems to send the
content-encoding: gzip header even if ob_end_clean or similar is called
which produces no output.  that means that if you use ob_gzhandler and
then change your mind about compression and need to kill that buffer,
you're out of luck. in the following small example, "output" WILL be
printed in plaintext but will be misinterpreted by the browser as
gzipped content.
<?php
ob_start("ob_gzhandler");
echo("trashed");
ob_end_clean();
echo("output");
?>
you can use telnet to better view the situation because it will almost
always result in a white browser window.  as others have pointed out,
you have to use the accept-encoding to trigger ob_gzhandler's
compression:
$ telnet localhost 80
GET /ob_test.php HTTP/1.1
Host: localhost
Accept-Encoding: gzip,deflate
now, should ob_gzhandler really be sending the header if the buffer is
ended without outputting anything?  should it maybe check the length of
the buffer when it is closed to determine whether or not

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-103965-1-1.html 上篇帖子: 基于原生PHP交叉会员权限控制 下篇帖子: CodeIgniter框架中关于URL(index.php)的那些事
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表