在一些大型应用长,比如discuz、wordpress等,我们常可以看到php程序可以在执行的同时同步输出执行结果,直到执行完毕。为此笔者展开了相关的探索。
Apache
apache实现这个效果容易很多
1 2 3 4 5 6 7 8 9 10 |
<?php set_time_limit(0); //在有关数据库的大量数据的时候,可以将其设置为0,表示无限制。 ob_end_clean(); //在循环输出前,要关闭输出缓冲区 echo str_pad('',1024); //浏览器在接受输出一定长度内容之前不会显示缓冲输出,这个长度值 IE是256,火狐是1024,不会出现上下的拉动条。 for($i=1;$i<=100;$i++){ echo $i.'<br/>'; flush(); //刷新输出缓冲 sleep(1); //这个控制输出的速度。 } ?> |
程序实现的关键是关闭输出缓冲区与刷新输出缓冲,同时由于边执行边输出的程序往往需要执行较长的时间, 因此我们在程序的开始设置超时时间为0,避免服务器因为程序执行超时而关闭进程。
Nginx
当我们把上面的代码放在Nginx的服务器上执行时,发现并不能成功的实现边执行边输出的效果。
首先这个问题核心就是当缓冲区数据达到一定量时先输出到浏览器。
而apache和nginx 的php执行方式差异导致了两个效果的产生。
为此,我们需要对Nginx的配置进行改动
在nginx.conf: 在http{}中加入fastcgi_keep_conn on;gzip off;
同时程序修改为如下
1 2 3 4 5 6 7 8 9 10 11 12 |
<?php set_time_limit(0); //在有关数据库的大量数据的时候,可以将其设置为0,表示无限制。 ob_end_clean(); //在循环输出前,要关闭输出缓冲区 echo str_pad('',1024); //浏览器在接受输出一定长度内容之前不会显示缓冲输出,这个长度值 IE是256,火狐是1024,不会出现上下的拉动条。 for($i=1;$i<=100;$i++){ echo $i.'<br/>'; echo str_repeat(" ", 1024 * 2);//人为将缓冲数据扩充到2k ob_flush(); flush(); //刷新输出缓冲 sleep(1); //这个控制输出的速度。 } ?> |
上面的代码中,核心是ob_flush和flush以及repeat。
注意,repeat在上面的程序中扩充到了2k,实际要以nginx中的配置为准。
可如下配置
1 2 |
fastcgi_buffer_size 2k;//缓冲区大小 fastcgi_buffers 256 2k; //开辟256个 2k大小的缓冲区 |
扩展
ob_flush()和flush()的区别。
前者是把数据从PHP的缓冲中释放出来,后者是把不在缓冲中的或者说是被释放出来的数据发送到浏览器。所以当缓冲存在的时候,我们必须ob_flush()和flush()同时使用。正确使用的顺序是:先用ob_flush(),后用flush()。