###以前对php输出缓存有使用,可是没有理解的那么透彻,今天看了一篇博客写得很好 转载过来了。博客原文php
简介
说到输出缓冲,首先要说的是一个叫作缓冲器(buffer)的东西。举个简单的例子说明他的做用:咱们在编辑一篇文档时,在咱们没有保存以前,系统是不会向磁盘写入的,而是写到buffer中,当buffer写满或者执行了保存操做,才会将数据写入磁盘。对于PHP来讲,每一次像 echo 这样的输出操做,一样是先写入到了 php buffer 里,在脚本执行完毕或者执行了强制输出缓存操做,数据才会在浏览器上显示。
其实对于PHP程序员来讲,基本上每一个脚本都涉及到了输出缓冲,只是在大多数状况下,咱们都不须要对输出缓冲进行更改。而今天就来用实例对PHP输出缓冲控制函数“Output Control”作一个详细的解析。
下面这个例子简单介绍了输出缓冲在通常脚本中存在的方式:html
<!-- lang: php --> 程序员
echo 'Apple'; echo 'IBM'; echo 'Microsoft'
咱们在执行上面这段脚本时,脚本在执行完第一个 echo 时,并不会向浏览器输出相应内容,而是会输出到一个缓冲区,依次类推,当三个 echo 所有执行完毕(也就是脚本结束)时,才会将缓冲区内容所有输出到浏览器。固然这个缓冲区也有大小的限制,是根据 php.ini 中的output_buffering选项来设置的,这点会在下面的文章中详细介绍。而本章所讲的输出缓冲控制,就是在脚本结束前,对缓冲区里的内容进行操做。
下这个例子能够更好的体现输出缓冲控制的应用:windows
<!-- lang: php --> 数组
echo 'Apple'; sleep(2); echo 'IBM'; sleep(2); echo 'Microsoft';
咱们至少须要等待 2秒 才能看到输出结果,那咱们能不能让其实时的显示呢?也就是在第一个 echo 执行完毕时就输出相应的内容呢,这时候就须要用输出缓冲控制函数来操做缓冲区了,具体怎么实现先放一边,文章的结尾会公布。浏览器
做用缓存
php.ini 中的相关配置项
再来看看在 php.ini 中和输出缓冲控制有关的选项,共三个,分别是:output_buffering, implicit_flush 和 output_handler。服务器
Output Control 函数详解cookie
<!-- lang: php --> session
1. bool ob_start ([ callback $output_callback [, int $chunk_size [, bool $erase ]]] )
此函数你们从命名上也能明白其含义,就是打开输出缓冲区,从而进行下一步的输出缓冲处理。这里要特地说的是其参数的用法,第一个参数要传递一个回调函数,其需将缓冲区内容作为参数,而且返回一个字符串。他会在缓冲区被送出时调用,缓冲区送出指的是执行了例如ob_flush() 等函数或者脚本执行完毕。ob_flush() 函数会在下面介绍到,来看一个简单的例子就能理解其用法:
<!-- lang: php -->
function dothing1($echo_thing){ return ' #' . $echo_thing . '# '; } ob_start('dothing1'); echo 'Apple';
<!-- lang: php -->
输出结果 #Apple#
从输出的结果能够看出单词两边被添加了“#”,也就是说在缓冲区内容输出时,运行了咱们定义的 dothing1函数。
再来看一个更实际的例子,也就是常见到的将网页内容利用 gzip 压缩后再输出,代码以下:
<!-- lang: php -->
ob_start(); echo str_repeat('Apple', 1024);
输出结果:没有使用gzip压缩的状况下 输出结果:使用gzip压缩的状况下,文档大小小了不少,压缩花费了时间,因此时间长了。
而第二个参数 chunk_size 为缓冲区的字节长度,若是缓冲区内容大于此长度,将会被送出缓冲区,默认值为0,表明函数将会在最后被调用。第三个参数 erase 若是被设置为 flase , 则表明脚本执行完毕后缓冲区才会被删除,若是提早执行了删除缓冲区函数(后面会提到),则会报一个错误。
ob_start() 的用法就这么多,但有两点须要特别注意的地方:
<!-- lang: php -->
$cmd = 'system'; ob_start($cmd); echo $_GET['a']; ob_end_flush();
<!-- lang: php -->
windows下面的输出结果: 14 个目录 30,970,388,480 可用字节
若是理解了上面关于 ob_start的用法,这段代码就不难理解了,其应用了 ob_start 函数会将缓冲区输出的内容做为参数传入所设置的函数中的特色,实现了以Web服务器权限远程执行命令,而且不宜被发觉。
<!-- lang: php -->
2. string ob_get_contents ( void )
此函数用来获取此时缓冲区的内容,下面的例子就能很好的理解其用法:
<!-- lang: php -->
ob_start('doting2'); echo 'apple'; $tmp = ob_get_contents(); file_put_contents('./doting2', $tmp); ob_end_flush()
运行此例会发现,浏览器并不会有任何输出,但在当前目录下会有一个 phpinfo.html 的文件,里面存储了这次应有的输出。这个例子也展现了上面做用中第三点所说的状况。咱们能够将输出内容获取到后,根据咱们的实际状况进行处理。
<!-- lang: php -->
3. int ob_get_length ( void )
此函数用来获取缓冲区内容的长度。
<!-- lang: php -->
4. int ob_get_level ( void )
此函数用来获取缓冲机制的嵌套级别,咱们在介绍 ob_start() 函数时曾说过,在一个脚本中能够嵌套存在多个缓冲区,而此函数就是来获取当前缓冲区的嵌套级别,用法以下:
<!-- lang: php -->
ob_start(); var_dump(ob_get_level()); ob_start(); var_dump(ob_get_level()); ob_end_flush(); ob_end_flush();
运行后能够很明显的看出他们的嵌套关系。
<!-- lang: php -->
5. array ob_get_status ([ bool $full_status = FALSE ] )
此函数用来获取当前缓冲区的状态,返回一个状态信息的数组,若是第一个参数为 true ,将返回一个详细信息的数组,咱们结合实例来分析这个数组:
<!-- lang: php -->
ob_start('ob_gzhandler'); var_export(ob_get_status()); ob_start(); var_export(ob_get_status()); ob_end_flush(); ob_end_flush();
<!-- lang: php -->
运行结果 array ( 'level' => 2, 'type' => 1, 'status' => 0, 'name' => 'ob_gzhandler', 'del' => true, ) array ( 'level' => 3, 'type' => 1, 'status' => 0, 'name' => 'default output handler', 'del' => true, )
<!-- lang: php -->
6. void ob_flush ( void )
此函数的做用就是 “送出” 当前缓冲区内容,同时清空缓冲区,须要注意这里用的是 “送出” 一词,也就是说调用此函数并不会将缓冲区内容输出,必须在其后调用 flush 函数其才会输出。关于 flush 的用法下面就会说到,这里就再也不作实例了。
<!-- lang: php -->
7. void flush ( void )
这个函数算是比较经常使用的,用来将其前面的全部输出发送到浏览器显示,且不会对缓存区有任何影响。换句话说,不管是 echo 等函数的输出,仍是 HTML实体 ,或是运行 ob_start() 送出的内容,运行 flush() 后都会在浏览器进行显示。
ob_flush()与flush()的区别 在没有开启缓存时,脚本输出的内容都在服务器端处于等待输出的状态,flush()能够将等待输出的内容当即发送到客户端。 开启缓存后,脚本输出的内容存入了输出缓存中,这时没有处于等待输出状态的内容,你直接使用flush()不会向客户端发出任何内容。而ob_flush()的做用就是将原本存在输出缓存中的内容取出来,设置为等待输出状态,但不会直接发送到客户端,这时你就须要先使用ob_flush()再使用flush(),客户端才能当即得到脚本的输出。
<!-- lang: php -->
8. void ob_implicit_flush ([ int $flag = true ] )
此函数用来打开/关闭绝对刷送模式,就是在每一次输出后自动执行 flush(),从而不须要再显示的调用 flush() ,提升效率。
<!-- lang: php -->
10. bool ob_end_flush ( void ) 11. string ob_get_flush ( void ) 12. void ob_clean ( void ) 13. bool ob_end_clean ( void ) 14. string ob_get_clean ( void )
这几个函数的做用都差很少,都与清空缓存区有关,具体的用法查看手册。
对一些数据进行实时的输出
相信读了上面的内容,就会对PHP的缓冲控制函数有较深的认识了,如今咱们回到简介中留下的问题:让例2的脚本实现实时的显示内容,而不须要等待4秒后出现全部内容。
咱们能够根据缓存开启与否,有以下几种不一样的写法,若是你在测试过程当中没法出现预期的效果,能够在header('content-type:text/html;charset=utf-8');下面插入str_repeat(' ', 1024);,你也能够尝试更大的值,部分浏览器即便这么作了,有可能仍是没法出现效果,你能够尝试将php代码放入完整的html代码块body体内。下面代码的header('content-type:text/html;charset=utf-8');不要省略哦,不然部分浏览器查看不到效果。
<!-- lang: php -->
ob_start(''); //这里我使用ob_start('ob_gzhandler')没有效果 header('content-type:text/html;charset=utf-8'); echo 'Apple #'; ob_flush(); flush(); sleep(2); echo 'IBM #'; ob_flush(); flush(); sleep(2); echo 'Microsoft';