如沐博客-互联网观察者

致力于互联网产业的发展

« php json_encode输出为空问题php curl 301无效,php curl网页不自动跳转,php CURLOPT_FOLLOWLOCATION选项无效的解决办法 »

关于PHP 刷新缓冲区操作(边执行边输出)简单分析

 背景:估计那个同学想做PHP的长连接,或者是想有些较为少用的用法,但它涉及到了缓冲的概念(PHP和Apache,PHP和Nginx等,Web服务器的一个接口等)
关于PHP 刷新缓冲区操作(边执行边输出)简单分析:
PHP群里有一位同学问

 

<?php ob_start(); echo 'Begin ...<br />'; for( $i  =  0 ;  $i  <  10 ;  $i++ ) {     echo $i . '<br />';     flush();     ob_flush();     sleep(1); } echo 'End ...<br />'; exit; ?>

这段代码在apache下能边执行边输出,在nginx下怎么就不行了?

简单的理解为2个问题:

1 首先这个问题核心就是当缓冲区数据达到一定量时先输出到浏览器。

2 apache和nginx 的php执行方式差异。

这个问题和我上篇博文《FastCGI 技术介绍》有一定的联系,apache是以CGI/CLI的方式调用php。而nginx 是以fastcgi方式调用PHP。FastCGI 基于Unix domain socket或者tcp/ip进行通信。
步骤  名称  描述
1  FCGI_PARAMS  从web服务器如nginx向fastcgi应用程序发送请求数据、环境变量等
2  FCGI_STDIN  接送从web服务器发送来的数据
3  FCGI_DATA  过滤web服务器发送来的数据
4  FCGI_STDOUT  发送数据到web服务器
5  FCGI_STDERR  发送状态(错误信息)到web服务器
6  FCGI_END_REQUEST  结束本次http请求

就是意味着可以设置一定的缓冲区大小 来实现。

土话就是:人为让缓冲区容量达到一定额。

nginx FastCGI 提供了2个参数

修改nginx.conf

location ~ \.php$ {     …     fastcgi_buffer_size 2k;//缓冲区大小    fastcgi_buffers 256 2k; //开辟256个 2k大小的缓冲区 }

参数可以调整。具体文档:http://wiki.nginx.org/HttpFastcgiModule#fastcgi_buffer_size

修改上述PHP代码

复制代码
<?php  echo 'Begin ...<br />'; for ($i = 0; $i < 10; $i++) {     echo $i . '<br />';     echo str_repeat(" ", 1024 * 2);//人为将缓冲数据扩充到2k    flush();     ob_flush();     sleep(1); } echo 'End ...<br />'; exit; ?>
复制代码

来自:http://www.cydphp.cn/?p=155
再就是这位兄弟的:http://www.cydphp.cn/?p=107  【写得比较原始,原始的CGI,当年没有PHP时是这么干的,可以有较为深入的理解】

转:http://www.justwinit.cn/post/6182/

--------------------------------分割线---------------------------

<?php
header('Content-Type: text/html;charset=utf-8');
ob_start();
$array = array(0,1,2,3,4,5,6,7,8,9);
$size = count($array);
for ($i=0;$i<$size;$i++) {
    for ($j=0;$j<$size-1;$j++) {
        if ($array[$j] < $array[$j+1]) {
            $temp = $array[$j];
            $array[$j] = $array[$j+1];
            $array[$j+1] = $temp;
        }
    }
    print_r($array);
    echo '<br />'.str_repeat(' ', 1024*4);
    ob_flush();
    flush();
    sleep(1);
}
echo 'Done.';
ob_end_flush();
?>
PHP_CLI_Server能够实时输出.
Apache和Nginx的gzip可能会进行输出缓存,这将导致flush()函数产生的结果不会立即被发送到客户端浏览器.
在Nginx+PHP-FPM下还要注意Nginx的fastcgi buffer,比如:
fastcgi_buffer_size 128k;
fastcgi_buffers 8 128k;
表示Nginx会缓冲PHP-FPM输出的信息,当达到128k时才会将缓冲区的数据发送给客户端,那么我们首先需要将这个缓冲区调小:
fastcgi_buffer_size 4k;
fastcgi_buffers 8 4k;
并且,必须禁用gzip:
gzip off;
然后,在php中,在ob_flush和flush前,输出一段达到4k的内容,例如:
echo str_repeat(' ', 1024*4);
到此,PHP就可以正常通过ob_flush和flush逐行输出需要的内容了.

Nginx 的 buffer 机制:
来自 FastCGI Server 的响应内容,Nginx 会将其缓冲到内存中,然后依次发送到客户端浏览器。
缓冲区的大小涉及的两个参数是 fastcgi_buffers 和 fastcgi_buffer_size 。
http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html


如果还是不行
 

nginx 里面 flush 默认是无效的, 这个函数默认是作用在php作为 apache模块时才有效,如果需要 nginx 里面支持,需要加上一行

header('X-Accel-Buffering: no');

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

日历

最新评论及回复

最近发表

Copyright 2010-2020 25230.NET All Rights Reserved.