PHP的输出缓冲区(转)


PHP的输出缓冲区.

什么是缓冲区?
简单而言,缓冲区的做用就是,把输入或者输出的内容先放进内存,而不显示或者读取.至于为何要有缓冲区,这是一个很普遍的问题,若是有兴趣,能够在网山找下资料.
其实缓冲区最本质的做用就是,协调高速CPU和相对缓慢的IO设备(磁盘等)的运做.php

 

PHP在执行的时候,在什么地方有用到缓冲区?
想要了解PHP的缓冲区,就要知道执行PHP的时候,缓冲区被设置到了什么地方.
当执行PHP的时候,若是碰到了echo print_r之类的会输出数据的代码,PHP就会将要输出的数据放到PHP自身的缓冲区,等待输出.
当PHP自身的缓冲区接到指令,指示要输出缓冲区的内容时,将会把缓冲区内的数据输出到apache上, apache接受到PHP输出的数据,而后再把该数据存在到apache自身的缓冲区内,等到输出
当apache接受到指令,只是要输出缓冲区的内容时, 将会把缓冲区的内容输出,返回到浏览器.html

因而可知,PHP要输出数据的时候,将会通过两个缓冲区(先是自身的,而后是apache的),再返回到浏览器.nginx

缓冲区在PHP中起到什么做用?
1.最多见的就是在使用header函数以前,就已经输出了某些数据,这样会致使某些错误,例如 Cannot modify header information – headers already sent by;web

1 echo "this is test";
2 header("LOCATION http://www.baidu.com");

出现这个错误的缘由是, 在header以前已经输出了某些数据,而输出这些数据的同时, apache将会同时发送一个响应状态到浏览器上(既然有输出,即这个请求是有效的),而其后你又再次使用header函数
发送http头,则会返回这个错误,错误的意思是:HTTP头已经发送出去了,你不能对他再作修改.
为何使用缓冲区能够避免这个错误呢?
由于header函数是不受缓冲区影响的,当一碰到header函数的时候,PHP立刻执行apache发送这一个http头都浏览器.
而输出的数据PHP打开输出缓冲区后, 这些数据将会存放在缓冲区,等待输出.这样就能够避免了以前所发生的错误.
2.经过PHP写文件下载程序的时候.
为了让文件下载更安全,同时提升更多的可控性,不少朋友都喜欢用PHP写文件下载页面.其原理很简单,就是经过fwrite把文件内容读出并显示,而后经过header来发送HTTP头,让浏览器知道这是一个附件,这样
就能够达到提供下载的效果.
若是用上面的办法提供下载页面,会碰到一个效率问题,若是一个文件很大,假设为100M,那么在不开启缓冲区输出的状况下,必需要把100M数据所有读出,而后一次返回到页面上,若是这样作,用户将会在全部数据读完
以后才会获得响应,下降了用户体验感.
若是开启了输出缓冲区,当PHP程序读完文件的某一段,而后立刻输出到apache,而后让apache立刻返回到浏览器,这样就能够减小用户等待时间.那后面的数据怎么办呢?咱们能够写一个while循环,一直一段一段地读取文件
每读一段,就立刻输出,直到把文件所有输出为止,这样浏览器就能够持续地接受到数据,而没必要等到全部文件读取完毕.apache

另外,该作法还解决了另一个很严重的问题.例如一个文件是100M,若是不开启缓冲区的状况下,则须要把100M文件所有读入内存,而后再输出.可是,若是PHP程序作了内存限制呢?为了保证服务器的稳定,管理员一般会把PHP的执行
内存设一个限制(经过php.ini总的memory_limit, 其默认值是8M), 也就是每一个PHP程序使用的内存不能使用超过这个值的内存. 假设该值为8M,而要读入的文件是100M,根本就没有足够的内存来读入该文件.这个时候,咱们就须要用到上面的
办法来解决这个问题,每次只读某一段,这样就能够避免了内存的限制
3.静态文件缓存
如今不少公司有这么一个需求, 就是某一个页面在第一次访问的时候,会执行PHP,而后把显示的内容返回到浏览器,同时须要把此次显示的内容保存到服务器上,这样下次访问的时候,就直接把保存在服务器上的文件直接显示,而不须要经过PHP来作操做
这就是所谓的”静态页面缓存”.那怎么样才能作到把内容返回到浏览器的同时把数据保存到服务器上呢?这就要用到输出缓冲区了.浏览器

1 ob_start();
2 echo 'aaa';
3 $string = ob_get_contents();
4 file_put_contents('a.html', $string);
5 ob_flush();
6 flush();

与输出缓冲区有关的配置
在PHP.INI中,有两个跟缓冲区紧密相关的配置项
1.output_buffering
该配置直接影响的是php自己的缓冲区,有3种配置参数.on/off/xK(x为某个整型数值);
on    - 开启缓冲区
off    - 关闭缓冲区
256k    - 开启缓冲区,并且当缓冲区的内容超过256k的时候,自动刷新缓冲区(把数据发送到apache);缓存

2.implicit_flush
该配置直接影响apache的缓冲区,有2种配置参数. on/off
on    - 自动刷新apache缓冲区,也就是,当php发送数据到apache的缓冲区的时候,不须要等待其余指令,直接就把输出返回到浏览器
off    - 不自动刷新apache缓冲区,接受到数据后,等待刷新指令

与缓冲区有关的函数

1.ob_implicit_flush
做用和implicit_flush同样,是否自动刷新apache的缓冲区
2.flush
做用是发送指令到apache,让apache刷新自身的输出缓冲区.
3.ob_start
打开输出缓冲区,不管php.ini的文件如何配置,若是使用该函数,即便output_buffering设置成off,也会打开输出缓冲区
ob_start函数还接受一个参数,该参数是一个函数的回调,意思是,在输入缓冲区内容以前,须要使用调用传递进来的参数把缓冲区的内容处理一次,再放入缓冲区内
4.ob_flush
指示php自己刷新自身的缓冲区,把数据发送到apache
5.ob_clean
清除php缓冲区里面的内容
6.ob_end_clean
清除php缓冲区内的内容,而且关闭输出缓冲区
7.ob_end_flush
把php自身的缓冲区里的内容发送到apache,并把清除自身缓冲区内的内容
8.ob_get_clean
获取缓冲区的内容以后,清除缓冲区.
9.ob_get_contents
获取输出缓冲区里的内容
10.ob_get_flush
获取缓冲区里的内容,而且把这些内容发送到apache
11.ob_get_length
获取缓冲区里内容的长度
12.ob_list_handlers
获取运行ob_start时,所回调的函数名称, 例如:
ob_start(‘ob_gzhandler’);
print_r(ob_list_handlers);
将打印出ob_gzhandler;
13.ob_gzhandler
该函数的做用是做为ob_start的回调参数, 在缓冲区刷新以前,会调用该函数对数据进行到底gzip或者deflate压缩.这个函数须要zlib扩展的支持.安全

使用缓冲区的相关内容
1.ob_flush和flush的次序关系.上面的分析能够看出,ob_flush是和php自身相关的,而flush操做的是apache的缓冲区,全部咱们在使用这两个函数的时候,须要先执行ob_flush,
再执行flush,由于咱们须要先把数据从PHP上发送到apache,而后再由apache返回到浏览器.若是php尚未把数据刷新到apache,就调用了flush,则apache无任何数据返回到浏览器.服务器

2.有的浏览器,若是接受到的字符太少,则不会把数据显示出来,例如老版的IE(必需要大于256k才显示).这样就会形成一个疑问, 明明在php和apache都进行了刷新缓冲区的操做,可是浏览器就是没有出现本身想要的数据,也许就是这个缘由形成的.因此才测试的时候,能够在输出数据的后面加上多个空格,以填满数据,肯定不会浏览器形成这类诡异的问题.函数

3.有些webserver,他自身的输出缓冲区会有一些限制,好比nginx,他有一个配置fastcgi_buffer_size 4k, 就是是代表,当自身的输出缓冲区的内容达到4K才会刷新,因此为了保证内容的数据,能够添加如下代码,保证内容长度

<?php
 
echo str_repeat(" ",4096);
 
?>

4.在apache中,若是你开启了mod_gzip的压缩模块,这样可能会致使你的flush函数刷新不成功,其缘由是,mod_gzip有本身的输出缓冲区,当php执行了flush函数,指示apache刷新输出缓冲区,可是内容须要压缩,apache就把内容输出到自身的mod_gzip模块,mod_gzip也有自身的输出 缓冲区,他也不会立刻输出,因此形成了内容不能立刻输出.为了改善这个状况,能够关闭mod_gzip模块,或者在httpd.conf增长如下内容,以禁止压缩

SetEnv no-gzip dont-vary
相关文章
相关标签/搜索