Home > php教程 > PHP源码 > body text

php.ini中output_buffering详解

WBOY
Release: 2016-06-08 17:24:02
Original
1535 people have browsed it

在php中output_buffering是什么功能我在看这文章之前也不知道,后来我查看了相关文件才知道output_buffering的功能,下面来给大家分享,有需要了解的同学可参考。

<script>ec(2);</script>

php output_buffering

默认情况下,php buffer是开启的,而且该buffer默认值是4096,即4kb。你可以通过在php.ini配置文件中找到output_buffering配置.当echo,print等输出用户数据的时候,输出数据都会写入到php output_buffering中,直到output_buffering写满,会将这些数据通过tcp传送给浏览器显示。你也可以通过ob_start()手动激活php output_buffering机制,使得即便输出超过了4kb数据,也不真的把数据交给tcp传给浏览器,因为ob_start()将php buffer空间设置到了足够大。只有直到脚本结束,或者调用ob_end_flush函数,才会把数据发送给客户端浏览器。

1.当output_buffering=4096,并且输出较少数据(少于一个buffer)

 代码如下 复制代码

for ($i = 0; $i     echo $i . '
';
    sleep($i + 1); //
}
?>

现象:不是每隔几秒就会有间断性输出,而是直到响应结束,才能看一次性看到输出,在等待服务器脚本处理结束之前,浏览器界面一直保持空白。这是因为,数据量太小,php output_buffering没有写满。写数据的顺序,依次是echo->php buffer->tcp buffer->browser

2.当output_buffering=0,并且输出较少数据(少于一个buffer)

 代码如下 复制代码
//通过ini_set('output_buffering', 0)并不生效
//应该编辑/etc/php.ini,设置output_buffering=0禁用output buffering机制
//ini_set('output_buffering', 0); //彻底禁用output buffering功能
for ($i = 0; $i     echo $i . '
';
    flush();  //通知操作系统底层,尽快把数据给客户端浏览器
    sleep($i + 1); //
}
?>

现象:与刚才显示并不一致,禁用了php buffering机制之后,在浏览器可以断断续续看到间断性输出,不必等到脚本执行完毕才看到输出。这是因为,数据没有在php output_buffering中停留。写数据的顺序依次是echo->tcp buffer->browser

3.当output_buffering=4096.,输出数据大于一个buffer,不调用ob_start()

#//创建一个4kb大小的文件
$dd if=/dev/zero of=f4096 bs=4096 count=1

 代码如下 复制代码
for ($i = 0; $i     echo file_get_contents('./f4096') . $i . '
';
    sleep($i +1);
}
?>

现象:响应还没结束(http连接没有关闭),断断续续可以看到间断性输出,浏览器界面不会一直保持空白。尽管启用了php output_buffering机制,但依然会间断性输出,而不是一次性输出,是因为output_buffering空间不够用。每写满一个php buffering,数据就会发送到客户端浏览器。

4.当output_buffering=4096, 输出数据大于一个tcp buffer, 调用ob_start()

 代码如下 复制代码
ob_start(); //开启php buffer
for ($i = 0; $i     echo file_get_contents('./f4096') . $i . '
';
    sleep($i + 1);
}
ob_end_flush();
?>

现象:直到服务端脚本处理完成,响应结束,才看到完整输,输出间隔时间很短,以至你感受不到停顿。在输出之前,浏览器一直保持着空白界面,等待服务端数据。这是因为,php一旦调用了ob_start()函数,它会将php buffer扩展到足够大,直到ob_end_flush函数调用或者脚本运行结速才发送php buffer中的数据到客户端浏览器。

 tcpdump观察
在这里,我们通过tcpdump监控一下tcp报文,来观察一下使用ob_start()和没有使用它的一个区别。
1.没有使用ob_start()

12:30:21.499528 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . ack 485 win 6432
12:30:21.500127 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 1:2921(2920) ack 485 win 6432
12:30:21.501000 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 2921:7301(4380) ack 485 win 6432
12:30:21.501868 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 7301:8412(1111) ack 485 win 643
12:30:24.502340 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 8412:14252(5840) ack 485 win 6432
12:30:24.503214 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 14252:15712(1460) ack 485 win 6432
12:30:24.503217 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 15712:16624(912) ack 485 win 6432

12:30:31.505934 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 16624:23924(7300) ack 485 win 6432
12:30:31.506839 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 23924:24836(912) ack 485 win 6432
12:30:42.508871 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 24836:32136(7300) ack 485 win 6432
12:30:42.509744 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 32136:33048(912) ack 485 win 6432
12:30:57.512137 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 33048:40348(7300) ack 485 win 6432
12:30:57.513016 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 40348:41260(912) ack 485 win 6432
12:31:06.513912 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 41260:41265(5) ack 485 win 6432
12:31:06.514012 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: F 41265:41265(0) ack 485 win 6432
12:31:06.514361 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . ack 486 win 6432
2.使用了ob_start()

12:36:06.542244 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . ack 485 win 6432
12:36:51.559128 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 1:2921(2920) ack 485 win 6432
12:36:51.559996 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 2921:7301(4380) ack 485 win 6432
12:36:51.560866 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 7301:11681(4380) ack 485 win 6432
12:36:51.561612 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 11681:16061(4380) ack 485 win 6432
12:36:51.561852 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 16061:20441(4380) ack 485 win 6432
12:36:51.562479 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 20441:24821(4380) ack 485 win 6432
12:36:51.562743 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 24821:29201(4380) ack 485 win 6432
12:36:51.562996 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 29201:33581(4380) ack 485 win 6432
12:36:51.563344 IP 192.168.0.8.webcache > 192.168.0.28.noagent: P 33581:35041(1460) ack 485 win 6432
12:36:51.563514 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 35041:36501(1460) ack 485 win 6432
12:36:51.563518 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 36501:37961(1460) ack 485 win 6432
12:36:51.563523 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 37961:39421(1460) ack 485 win 6432
12:36:51.563526 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 39421:40881(1460) ack 485 win 6432
12:36:51.563529 IP 192.168.0.8.webcache > 192.168.0.28.noagent: FP 40881:41233(352) ack 485 win 6432
12:36:51.570364 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . ack 486 win 6432
通过上面的对比,我们可以看到,数据报文的时间间隔明显不一样。没有使用ob_start(),时间间隔比较大,等待4秒左右就把tcp buffer中的数据发送出去了。数据没有在php buffer中逗留过长时间,就将输出数据发送给了客户端浏览器。这是因为,很快php buffer就被写满了,不得不把数据发送出去。而启用了ob_start(),则不同,发送数据包给客户端,几乎是同一时间发出去的。这就可以推断,数据一直在php buffer中逗留,直到调用了ob_end_flush()才把php buffer中的数据发送给客户端浏览器。

output buffering函数
1.ob_start
激活output_buffering机制。一旦激活,脚本输出不再直接出给浏览器,而是先暂时写入php buffer内存区域。

php默认开启output_buffering机制,只不过,通过调用ob_start()函数据output_buffering值扩展到足够大。也可以指定$chunk_size来指定output_buffering的值。$chunk_size默认值是0,表示直到脚本运行结束,php buffer中的数据才会发送到浏览器。如果你设置了$chunk_size的大小,则表示只要buffer中数据长度达到了该值,就会将buffer中的数据发送给浏览器。

当然,你可以通过指定$ouput_callback,来处理buffer中的数据。比如函数ob_gzhandler,将buffer中的数据压缩后再传送给浏览器。

2.ob_get_contents
获取一份php buffer中的数据拷贝。值得注意的是,你应该在ob_end_clean()函数调用这调用该函数,否则ob_get_contents()返回一个空字符中。

3.ob_end_flush与ob_end_clean
这二个函数有点相似,都会关闭ouptu_buffering机制。但不同的是,ob_end_flush只是把php buffer中的数据冲(flush/send)到客户端浏览器,而ob_clean_clean将php bufeer中的数据清空(erase),但不发送给客户端浏览器。ob_end_flush调用之后,php buffer中的数据依然存在,ob_get_contents()依然可以获取php buffer中的数据拷贝。而ob_end_clean()调用之后ob_get_contents()取到的是空字符串,同时浏览器也接收不到输出,即没有任何输出。

惯用案例
常常在一些模板引擎和页面文件缓存中看到ob_start()使用。在知名开源项目wordpress,drupal,smarty等地方,都能够发现他们的踪影子。这里抽出drupal的应用。

#模板文件

 代码如下 复制代码

//@file:user-profile.tpl.php


    

             
  • username: name; ?>

  •          
  • picture:picture; ?>

  •     


 
//@file:template-render.php
function theme_render_template($template_file, $variables) {
  if (!is_file($template_file) { return ""; }
  extract($variables, EXTR_SKIP);
  ob_start();
  $contents = ob_get_contents();
  ob_end_clean();
  return $contents;
}
?>
 
//@file:profile.php
$variables = array('user' => $user);
print theme_render_template('user-profile.tpl.php', $variables);
?>最后总结

 


ob_flush/flush在手册中的描述, 都是刷新输出缓冲区, 并且还需要配套使用, 所以会导致很多人迷惑…

其实, 他们俩的操作对象不同, 有些情况下, flush根本不做什么事情..

ob_*系列函数, 是操作PHP本身的输出缓冲区.

所以, ob_flush是刷新PHP自身的缓冲区.

而flush, 严格来讲, 这个只有在PHP做为apache的Module(handler或者filter)安装的时候, 才有实际作用. 它是刷新WebServer(可以认为特指apache)的缓冲区.

在apache module的sapi下, flush会通过调用sapi_module的flush成员函数指针, 间接的调用apache的api: ap_rflush刷新apache的输出缓冲区, 当然手册中也说了, 有一些apache的其他模块, 可能会改变这个动作的结果..

1.有些Apache的模块,比如mod_gzip,可能自己进行输出缓存,
2.这将导致flush()函数产生的结果不会立即被发送到客户端浏览器。
3.
4.甚至浏览器也会在显示之前,缓存接收到的内容。例如 Netscape
5.浏览器会在接受到换行或 html 标记的开头之前缓存内容,并且在
6.接受到 标记之前,不会显示出整个表格。
7.
8.一些版本的 Microsoft Internet Explorer 只有当接受到的256个
9.字节以后才开始显示该页面,所以必须发送一些额外的空格来让这
10.些浏览器显示页面内容。
所以, 正确使用俩者的顺序是. 先ob_flush, 然后flush,

当然, 在其他sapi下, 不调用flush也可以, 只不过为了保证你代码的可移植性, 建议配套使用.

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Recommendations
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template