关于PHP中flush的蛋疼记录
好吧,从昨天就开始搞这个flush函数,直到今天中午才弄出来,而最让人蛋疼的最后搞出来的结果,阿西吧,我一定要把这个蛋疼的经历记录下来。。。。。
不知道flush()这个函数的可以先百度了解一下,我这里就简单的提一下吧,上代码:
ob_start(); for($i=0;$i<3;$i++) { echo $i; ob_flush(); flush(); sleep(1); }
大概的意思就是,ob_start()打开缓冲区,程序执行完echo后,一般来说是先放到缓冲区的,等全部执行完后才在前台显示,但是当我们加上flush以后,当执行到flush的时候,就会把缓冲区的数据取到前台显示,也就是说上面这个程序的效果应该是每个一秒钟输出一个数字出来。。。。
但是你以为就这么简单,你错了,这货就是输出不出来。。。
和php官网的案例比较了一下,一个样啊,完美啊有木有,可就是输出不出来。。。 你妹啊!
好吧,接下来就是各种百度。。。
有的说是跟php.ini的配置有关,有的说是跟缓冲区大小有关,有的说是浏览器兼容问题。。。 于是乎我就一个一个的都试了一遍。。。 这他妹的,没一个好使的。。。
亲,你这是跟我开玩笑么? 为什么人家都好使,我就不好使呢? 你能给我一个合理的解释么?
突然间就有一种不是亲生的感觉。。。(你幸福么? 幸福你妹啊~)
就在今天中午,翻着百度的时候,突然就看到一个哥们儿跟我遇到情况一样,看来这天下还有和我一样命苦的孩子~
研读了一下这哥们儿的文章,读到最后,我震精了~ 尼玛竟然说要加上html标签才能输出出来!!!
于是乎就把上面的代码改成了这样:
for($i=0;$i<3;$i++) { echo '<span>'.$i.'</span>'; ob_flush(); flush(); sleep(1); }
运行了一下,阿西吧,还真尼玛跑出来了。。。。(哈利路亚~ 哈利路亚~ 哈利路亚~~~)
万能的主呀,您这是魔兽更新没什么好玩儿的,就来玩儿我了是吧?! 你敢不敢给我一个更狗血的结果呀~?!(上帝的心思屌丝你别猜,别猜别猜,你猜来猜去你也不明白,不明白不明白~)
算了,就这样吧,我认了。。。 下面把这次找的一些小资源放出来,说不定会有用。。。
PHP flush sleep 输出缓存控制详解
有了解过PHP缓存输出控制函数的朋友肯定对上面这段代码很熟悉,它想实现的效果是每个1秒输出1个数字,完成全部输出需要10秒,不过实际执行中你会发现奇怪的现象,有些人或者有些时候它的表现如你所愿,而有些人或者有些时候却是10秒后才会一次性输出10个数字。我曾经为此抓狂不已,有朋友留言说这个情况往往是因为IE的缓存必须达到256个字符才会输出,可实际上我之前也考虑到IE的情况,可依旧会有时灵时不灵的情况。今天仔细读过手册才明白,这些不可预料的现象是有它的理由的。
原来php.ini中有两个关键参数会影响到php的缓存输出控制:
参数1:output_buffering :on/off 或者整数。设置为on时,将在所有脚本中使用输出缓存控制,不限制缓存的大小。而设置为整数时,如output_buffering=4096,当缓存数据达到4096字节时会自动输出刷新缓存。而这个参数的不同正是导致以上代码在不同时候执行结果不同的原因。当output_buffering关闭时,脚本所有的输出(echo)都会即时发送到客户端,执行上面代码时就是每秒输出一个数字。而开启output_buffering后,输出内容就会先缓存在服务端,直到脚本结束时才一起发送给客户端。
参数2:implicit_flush:on/off。设定ON意味着,当脚本有输出时,自动立即发送到客户端。相当于在echo后自动加flush()。
php缓存输出控制的相关函数:
第一个参数:回调函数,可选。在缓存输出前可以对其进行过滤或其他处理。最常见的用法是ob_start(‘ob_gzhandler’),即对缓存的数据进行gzip压缩后再发送给客户端。
第二个参数:缓存块的大小,可选。如果被缓存的内容达到或操作缓存块的大小,缓存会自动输出。默认值是0,指不限定大小,缓存到结束为止。还有个特殊值1,代表chunk_size=4096。
第三个参数:是否擦除缓存,可选,默认是true,如果设置为false,则在脚本执行结束前,缓存都不会被清除。
可以使用ob_get_contents()以字符串形式获取服务端缓存的数据,使用ob_end_flush()则会输出被缓存起来的数据,并关闭缓存。
而使用ob_end_clean()则会静默的清除服务端缓存的数据,而不会有任何数据或其他行为。
服务端的缓存是堆叠起来的,也就是说你在开启了ob_start()后,关闭之前,在其内部还可以开启另外一个缓存ob_start()。不过你也要务必保证关闭缓存的操作和开启缓存的操作数量一样多。
ob_start()可以指定一个回调函数来处理缓存数据,如果一个ob_start()内部嵌套了另一个
ob_start(),我们假定,外层的ob_start(),编号是A,内层的ob_start() 编号是B,它们各自制定了一个回调函数分别是functionA和functionB,那么在缓存B中的数据输出时,它会先辈funcitonB回调函数处理,再交给外层的functionA回调函数处理,之后才能输出到客户端。
另外,手册说,对于某些web服务器,比如apache,在使用回调函数有可能会改变程序当前的工作目录,解决方法是在回调函数中自行手动把工作目录修改回来,用chdir函数,这点似乎不常遇到,遇到的时候记得去查手册吧。
flush()和ob_flush()
这两个函数的使用怕是很多人最迷惑的一个问题,手册上对两个函数的解释也语焉不详,没有明确的指出它们的区别,似乎二者的功能都是刷新输出缓存。但在我们文章一开始的代码中如果讲fush()替换成ob_flush(),程序就再不能正确执行了。显然,它们是有区别的,否则也手册中直接说明其中一个是另外一个函数的别名即可了,没必要分别说明。那么它们的区别到底是什么呢?
反复研究了手册的说明,参考了手册中一些人的留言,自己琢磨应该是这样的:
在没有开启缓存时,脚本输出的内容都在服务器端处于等待输出的状态,flush()可以将等待输出的内容立即发送到客户端。
开启缓存后,脚本输出的内容存入了输出缓存中,这时没有处于等待输出状态的内容,你直接使用flush()不会向客户端发出任何内容。而ob_flush()的作用就是将本来存在输出缓存中的内容取出来,设置为等待输出状态,但不会直接发送到客户端,这时你就需要先使用ob_flush()再使用flush(),客户端才能立即获得脚本的输出。
也就是说本文开头的脚本,可以根据缓存开启与否,有如下几种不同的写法:
注:以下代码都未考虑IE缓存必须大于256字节才输出的问题,如在IE下测试,请在代码开始加一句: