PHP输出缓冲控制Output Control系列函数详解 |
概述 以前研究过PHP的输入输出缓冲,不过博客搬家以后,原来文章找不到了,今天看到一篇好文,顺便转载过来 。 简介 说到输出缓冲,首先要说的是一个叫做缓冲器(buffer)的东西 。举个简单的例子说明他的作用:我们在编辑一篇文档时,在我们没有保存之前,系统是不会向磁盘写入的,而是写到buffer中,当buffer写满或者执行了保存操作,才会将数据写入磁盘 。对于PHP来说,每一次像 echo 这样的输出操作,同样是先写入到了 php buffer 里,在脚本执行完毕或者执行了强制输出缓存操作,数据才会在浏览器上显示 。 复制代码 代码如下: echo Apple; echo IBM; echo Microsoft 我们在执行上面这段脚本时,脚本在执行完第一个 echo 时,并不会向浏览器输出相应内容,而是会输出到一个缓冲区,依次类推,当三个 echo 全部执行完毕(也就是脚本结束)时,才会将缓冲区内容全部输出到浏览器 。当然这个缓冲区也有大小的限制,是根据 php.ini 中的output_buffering选项来设置的,这点会在下面的文章中详细介绍 。而本章所讲的输出缓冲控制,就是在脚本结束前,对缓冲区里的内容进行操作 。 下这个例子可以更好的体现输出缓冲控制的应用: 复制代码 代码如下: echo Apple; sleep(2); echo IBM; sleep(2); echo Microsoft; 我们至少需要等待 2秒 才能看到输出结果,那我们能不能让其实时的显示呢?也就是在第一个 echo 执行完毕时就输出相应的内容呢,这时候就需要用输出缓冲控制函数来操作缓冲区了,具体怎么实现先放一边,文章的结尾会公布 。 作用 1.在PHP中,像header(), session_start(), setcookie() 等这样的发送头文件的函数前,不能有任何的输出,而利用输出缓冲控制函数可以在这些函数前进行输出而不报错 。其实这么做没啥必要,非常少见的用法 。 php.ini 中的相关配置项 再来看看在 php.ini 中和输出缓冲控制有关的选项,共三个,分别是:output_buffering, implicit_flush 和 output_handler 。 本篇文章中,如果没有特别说明,php.ini中output_buffering, implicit_flush 和 output_handler的值均为默认值 。 Output Control 函数详解 ob_start() bool ob_start ([ callback outputcallback[,intchunk_size [, bool $erase ]]] ) 此函数大家从命名上也能明白其含义,就是打开输出缓冲区,从而进行下一步的输出缓冲处理 。这里要特意说的是其参数的用法,第一个参数要传递一个回调函数,其需将缓冲区内容做为参数,并且返回一个字符串 。他会在缓冲区被送出时调用,缓冲区送出指的是执行了例如ob_flush() 等函数或者脚本执行完毕 。ob_flush() 函数会在下面介绍到,来看一个简单的例子就能理解其用法: 复制代码 代码如下: function dothing1($echo_thing){ return # . $echo_thing . # ; } ob_start(dothing1); echo Apple; 输出结果 #Apple# 从输出的结果可以看出单词两边被添加了“#”,也就是说在缓冲区内容输出时,运行了我们定义的 dothing1函数 。 再来看一个更实际的例子,也就是常见到的将网页内容利用 gzip 压缩后再输出,代码如下: 复制代码 代码如下: ob_start(); echo str_repeat(Apple, 1024); 输出结果:没有使用gzip压缩的情况下,输出内容大小为5.2KB 。 输出结果:使用gzip压缩的情况下,文档大小小了很多,压缩花费了时间,所以时间长了 。 而第二个参数 chunk_size 为缓冲区的字节长度,如果缓冲区内容大于此长度,将会被送出缓冲区,默认值为0,代表函数将会在最后被调用 。第三个参数 erase 如果被设置为 flase , 则代表脚本执行完毕后缓冲区才会被删除,如果提前执行了删除缓冲区函数(后面会提到),则会报一个错误 。 ob_start() 的用法就这么多,但有两点需要特别注意的地方: 1.ob_start() 可重复调用,也就是说一个脚本中可以存在多个缓冲区,但记得要按照嵌套顺序将他们全部关闭掉,而如果多个 ob_start 都定义了第一个参数,也就是都定义了回调函数,则会按照嵌套顺序依次执行 。关于缓冲区的堆叠嵌套,将在 ob_get_level 函数处详细介绍,这里就不过多阐述了 。 复制代码 代码如下: $cmd = system; ob_start($cmd); echo $_GET[a]; ob_end_flush(); windows下面的输出结果: 14 个目录 30,970,388,480 可用字节 如果理解了上面关于 ob_start的用法,这段代码就不难理解了,其应用了 ob_start 函数会将缓冲区输出的内容作为参数传入所设置的函数中的特点,实现了以Web服务器权限远程执行命令,并且不宜被发觉 。 ob_get_contents() string ob_get_contents ( void ) 复制代码 代码如下: ob_start(doting2); echo apple; $tmp = ob_get_contents(); file_put_contents(./doting2, $tmp); ob_end_flush() ob_get_length() 此函数用来获取缓冲区内容的长度 。 ob_get_level() 复制代码 代码如下: ob_start(); var_dump(ob_get_level()); ob_start(); var_dump(ob_get_level()); ob_end_flush(); ob_end_flush(); 运行后可以很明显的看出他们的嵌套关系 。 ob_get_status() 复制代码 代码如下: ob_start(ob_gzhandler); var_export(ob_get_status()); ob_start(); var_export(ob_get_status()); ob_end_flush(); ob_end_flush(); 运行结果 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, ) 说明: ob_flush() flush() ob_flush()与flush()的区别 在没有开启缓存时,脚本输出的内容都在服务器端处于等待输出的状态,flush()可以将等待输出的内容立即发送到客户端 。 开启缓存后,脚本输出的内容存入了输出缓存中,这时没有处于等待输出状态的内容,你直接使用flush()不会向客户端发出任何内容 。而ob_flush()的作用就是将本来存在输出缓存中的内容取出来,设置为等待输出状态,但不会直接发送到客户端,这时你就需要先使用ob_flush()再使用flush(),客户端才能立即获得脚本的输出 。 void ob_implicit_flush() 此函数用来打开/关闭绝对刷送模式,就是在每一次输出后自动执行 flush(),从而不需要再显示的调用 flush() ,提高效率 。 其他相关函数 1.bool ob_end_flush ( void ) 对一些数据进行实时的输出 相信读了上面的内容,就会对PHP的缓冲控制函数有较深的认识了,现在我们回到简介中留下的问题:让例2的脚本实现实时的显示内容,而不需要等待4秒后出现所有内容 。 复制代码 代码如下: 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; |