一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

php 页面输出缓存控制深入分析

时间:2015-06-08 编辑:简简单单 来源:一聚教程网


在php所谓的输出缓冲,就是代码中的echo 或者其他输出命令在执行的时候是先写入到 php buffer,在脚本执行完或者强制执行输出缓存的命令后,才会把数据输出到浏览器(其中php buffer 就是php.ini中设置的output_buffering ,默认是on,表明无限制大小,可以换成数字来限制大小)。

例子:


echo 'www.111com.net';
echo '技术';
echo '分享';

这两个echo 是按顺序插入到缓冲区的,只有脚本执行完成或者强制执行缓存输出才会把数据输出到浏览器。
如果我想要实时地输出echo的数据,见下面的代码:

ob_end_flush(); //关闭php缓存,或者在flush()前先执行ob_flush(),下面有解释
echo str_pad(" ", 256); 
for ($i=5; $i>0; $i--) { 
   echo $i. '
'; 
   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 后页面的大小:
QQ截图20140530175025

 

没使用ob_gzhandler 的页面大小

 

QQ截图20140530175056

 

明显压缩后页面的大小变小了很多。

例子(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
';
//flush(); 
sleep(1);
echo '分享
';
//flush();
sleep(1);
echo '技术
';
浏览器实时的输出下面:

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;
}

热门栏目