在php所谓的输出缓冲,就是代码中的echo 或者其他输出命令在执行的时候是先写入到 php buffer,在脚本执行完或者强制执行输出缓存的命令后,才会把数据输出到浏览器(其中php buffer 就是php.ini中设置的output_buffering ,默认是on,表明无限制大小,可以换成数字来限制大小)。
例子:
echo 'www.111cn.net';
echo '技术';
echo '分享';
这两个echo 是按顺序插入到缓冲区的,只有脚本执行完成或者强制执行缓存输出才会把数据输出到浏览器。
如果我想要实时地输出echo的数据,见下面的代码:
ob_end_flush(); //关闭php缓存,或者在flush()前先执行ob_flush(),下面有解释
echo str_pad(" ", 256);
for ($i=5; $i>0; $i--) {
echo $i. '<br>';
flush();
sleep(1);
}
注意:
1:flush和ob_flush 区别:
乍看之下两者很像,而且很多手册的解释也不清楚,模凌两可,其实两者是有很大区别的。
当php.ini没有开启php buffer缓存时,php脚本输出的内容都会在服务端处于等待输出状态 ,不会保存到输出缓存,因为缓存都没开,此时利用flush可以将那些等待输出的内容立即输出来发到客户端(浏览器或者其他输出端)。
当php.ini开启了php buffer缓存后,php脚本输出内容的第一步是存储在输出缓存中 ,此时等到输出的内容是没有数据的,用flush的话是无效果,取不到数据的。因此要先利用ob_flush把输出缓存中的内容取出来变成等待输出的状态,接下来在利用flush把内容发到客户端。执行的顺序是先ob_flush 再 flush。
因此要实现实时地输出,要么利用ob_end_flush 先关掉php 输出缓存后直接flush,要么先 ob_flush再flush。
2:浏览器无法输出实时数据
把代码改成下面的代码,在chrome firefox ie等浏览器都是一次性输出的,很奇葩的现象:
ob_end_flush(); //关闭php缓存,或者在flush前ob_flush();
echo str_pad(" ", 256);
for ($i=5; $i>0; $i--) {
echo $i;
flush();
sleep(1);
}
找了半天的bug,终于发现了个现象,只要顺便加个html标签,即可实时输出。
原因是:只有在遇到html标签的时候才会即时输出,真是神奇,还好一般输出的内容都会带着html标签,很少纯文本。
解决办法:加个回车或者其他的html标签即可解决问题。
一:下面详细介绍out control 的相关函数
1、flush //将等待输出的内容发送带浏览器,不会对缓存区有影响。
2、ob_flush // 将缓存区的内容变成等待输出状态,数据还没有输出到客户端。
3、ob_start(callback) // 打开输出缓冲区,可以加入回调的callback函数,实现在输出之前执行想要的功能。
例子(1)
ob_start('callbackFun');
echo '1111111';
function callbackFun($string){
return md5($string);//进行md5加密
}
结果:
1
e10adc3949ba59abbe56e057f20f883e
浏览器返回的结果是加密过的字符串,而不是 1111111,说明在数据存入输出缓存之前执行了回调函数对数据进行了md5加密后才存入输出缓存的。
例子(2)
结合ob_gzhandler实现网页内容的gzip压缩,减少传输的大小,提高页面的加载速度。
ob_start('ob_gzhandler');
echo str_repeat('hlmblog', 1024);
使用了ob_gzhandler 后页面的大小:
没使用ob_gzhandler 的页面大小
明显压缩后页面的大小变小了很多。
例子(3)
可以嵌套ob_start,但是记得要有对应的闭合,两个一一对应,不然会报错,或者取不到数据。
ob_start();
var_dump(1);
ob_start();
var_dump(2);
ob_end_flush();
ob_end_flush();
结果:
int 1
int 2
4、ob_get_contents() 获取输出缓冲区的内容或者页面输出的内容
echo str_pad('', 1024);//使缓冲区溢出
ob_start();//打开缓冲区
phpinfo();
$content = ob_get_contents();//获取缓冲区内容
$f = fopen('./phpinfo.txt', 'wb');//打开文件
fwrite($f, $content);//内容写入txt文件
fclose($f);//关闭文件
ob_end_clean();//关闭缓冲区,输出数据并清空浏览器
//ob_end_flush();//发送缓冲区内容到客户端,并关闭缓冲区,不清空浏览器
注意:
这时候浏览器将什么都不输出,因为使用了ob_end_clean() 清空掉了,但是会在当前目录产生一个phpinfo.txt 的文件,里面是获取到的phpinfo信息。
如果使用ob_end_flush,不仅会生成phpinfo.txt 文件,而且还在浏览器输出信息。
5、ob_get_length() 返回输出缓冲区的内容长度
echo str_pad('', 1024);//缓冲区溢出
ob_start();//打开缓冲区
phpinfo();
$string = ob_get_contents();//获取缓冲区内容
$length = ob_get_length();//获取缓冲区内容长度
$re = fopen('./phpinfo.txt', 'wb');
fwrite($re, $string);//将内容写入文件
fclose($re);
var_dump($length); //输出长度
ob_end_flush();//输出并关闭缓冲区
6、ob_get_level() //获取输出缓冲区嵌套级别,就是所处的级别位置
ob_start();
var_dump(ob_get_level());
ob_start();
var_dump(ob_get_level());
ob_end_flush();
ob_end_flush();
浏览器会输出对应的级别:
int 2
int 3
7、ob_get_status() //获取当前缓冲区的状态,返回的是一个数组信息
ob_start('ob_gzhandler');
var_dump(ob_get_status());
ob_start();
var_dump(ob_get_status());
ob_end_flush();
ob_end_flush();
array
'level' => int 2
'type' => int 1
'status' => int 0
'name' => string 'ob_gzhandler' (length=12)
'del' => boolean true
array
'level' => int 3
'type' => int 1
'status' => int 0
'name' => string 'default output handler' (length=22)
'del' => boolean true
返回数组参数详解:
level:嵌套级别,和ob_get_level()获取到的值是一样的。
type :处理缓冲类型,0是系统内部自动处理,1是用户手动处理。
status :缓冲处理状态, 0是开始, 1是进行中, 2是结束。
name: :定义的输出处理函数名称,就是ob_start() 函数中第一个参数的回调函数。
del :是否运行了删除缓冲区操作。
8、ob_list_handlers() //获得处理程序的函数名数组,也就是ob_start函数传入的第一个参数函数名
print_r(ob_list_handlers());
ob_end_flush();
ob_start("ob_gzhandler");
print_r(ob_list_handlers());
ob_end_flush();
浏览器输出对应的处理函数信息数组:
Array ( [0] => default output handler ) Array ( [0] => ob_gzhandler )
9、ob_implicit_flush() // 打开或关闭绝对刷送模式,就是每一次输出后自动执行 flush(),不用对应地写多次的flush,节省代码,提高效率
echo str_pad('', 1024);//缓冲区溢出
ob_end_flush();
ob_implicit_flush(true);//打开绝对刷送
echo 'hlmblog</br>';
//flush();
sleep(1);
echo '分享</br>';
//flush();
sleep(1);
echo '技术</br>';
浏览器实时的输出下面:
hlmblog
分享
技术
10、ob_end_flush() //发送内部缓冲区的内容到浏览器,并且关闭输出缓冲区
11、ob_end_clean() //删除内部缓冲区的内容,并且关闭内部缓冲区
二:控制缓存输出可以用来做什么,具体的几个示例
1:生成静态页面
静态页面的加载速度就是快,这句话是家户喻晓的道理,不用请求数据库,这是多么爽的事情啊。
下面是生成静态页面的例子:
echo str_pad('', 1024);//使缓冲区溢出
ob_start();//打开缓冲区
$content = ob_get_contents();//获取页面输出的内容
$f = fopen('./index.html', 'w');
fwrite($f, $content);//内容写入txt文件
fclose($f);
ob_end_clean();//清空并关闭缓冲区
传说中的静态页面就这样简单的生成。
2:捕获输出
function test($param) {
if($param) {
ob_start();
eval($param);
$contents = ob_get_contents();
ob_end_clean();
}else {
echo '遗憾的没有输出';
exit();
}
return $contents;
}