php缓冲区的介绍及应用
缓冲区的作用是把输入或输出的内容先放进内存,而不直接显示或读取。php提供了一些输出缓冲区的函数来控制输出。当执行echo、print之类的会输出数据的代码,php就会将要输出的数据保存在自己的缓冲区,然后等待输出。
缓冲流程
缓冲一般有3个阶段,php的缓冲、web服务器的缓冲、浏览器的缓冲。
和缓冲相关的配置
在php.ini中有几个和缓冲区相关的配置,下面我们一起来看看
output_buffering
该参数用来设置是否开启缓冲区以及缓冲区的大小,有三种设置方式
- On 当设置为on时表示开启缓冲区且缓冲区不受限制(使用它要注意)
- Off 关闭输出缓冲
- 数字 表示开启缓冲区且设置缓冲区的大小,单位是字节(建议的配置)
output_handler
默认为NULL,它是设置一个回调函数,将脚本的所有输出,用所定义的函数进行处理。类似与ob_start($output_callback)。
$output_callback:
- ob_gzhandler : 使用ext/zlib压缩输出
- mb_output_handler : 使用ext/mbstring转换字符编码
- ob_iconv_handler : 使用ext/iconv转换字符编码
- ob_tidyhandler : 使用ext/tidy整理输出的HTML文本
implicit_flush
若开启此项,则表示当php有数据发送到web server时,web sever会直接输出。这相当于在每次调用echo或print后调用flush函数。开启次选项会严重影响性能,一般只建议开发阶段可以开启。
和缓冲区有关的函数
ob_start
此函数将打开输出缓冲。当输出缓冲激活后,脚本将不会输出内容(除http标头外),相反需要输出的内容被存储在内部缓冲区中。
ob_clean
删除内部缓冲区的内容,不关闭缓冲区(不输出)。
ob_end_clean
删除内部缓冲区的内容,关闭缓冲区(不输出)。
ob_get_clean
返回内部缓冲区的内容,关闭缓冲区(不输出)。相当于执行 ob_get_contents()和 ob_end_clean()
ob_flush
发送内部缓冲区的内容到浏览器,删除缓冲区的内容,不关闭缓冲区。
ob_end_flush
发送内部缓冲区的内容到浏览器,删除缓冲区的内容,关闭缓冲区。
ob_get_flush
返回内部缓冲区的内容,并关闭缓冲区,再释放缓冲区的内容。相当于ob_end_flush()并返回缓冲区内容。
flush
一般会和ob_flush()一起使用,ob_flush()发送php自身缓冲区,而flush则刷新web server缓冲区。
if (ob_get_level() == 0) ob_start();
for ($i = 0; $i<10; $i++){
echo "<br> Line to show.";
echo str_pad('',4096)."\n";
ob_flush();
flush();
sleep(2);
}
echo "Done.";
ob_end_flush();
ob_get_contents
返回缓冲区的内容,不输出。
ob_get_length()
返回内部缓冲区的长度,如果缓冲区未被激活,该函数返回FALSE。
注意事项
ob_flush和flush的次序关系
ob_flush是和php自身相关的,而flush操作的是apache的缓冲区,所以我们在使用这两个函数的时候,需要先执行ob_flush,再执行flush,因为我们需要先把数据从PHP上发送到apache,然后再由apache返回到浏览器。如果php还没有把数据刷新到apache,就调用了flush,则apache无任何数据返回到浏览器.
webserver不刷新缓冲问题
有些webserver,他自身的输出缓冲区会有一些限制,比如nginx,他有一个配置fastcgi_buffer_size 4k, 就是表明,当自身的输出缓冲区的内容达到4K才会刷新,所以为了保证内容的数据,可以添加以下代码,保证内容长度
echo str_repeat(" ",4096);
输出缓冲应用
使 header() 函数前可以有echo代码
输出缓冲函数可以让你自由控制脚本中数据的输出。它非常地有用,特别是对于:当你想在数据已经输出后,再输出文件头的情况。输出缓冲函数不会对setcookie以及header造成影响。
复制代码 代码如下:
ob_start(); //打开缓冲区
echo "Hello\n"; //输出
header(“location:index.php”); //把浏览器重定向到index.php
ob_end_flush(); //输出全部内容到浏览器
上面代码不会报错,但如果没有开启输出缓冲的话就会出问题。
保存 phpinfo() 函数的输出
我们知道phpinfo里面有大量有用的信息,我们有时候经常会去查找相关的信息。但如果直接输出到浏览器,那么许多敏感信息也会显示。我们可以将phpinfo()产生的信息保存到一个文件里。
<?php
ob_start(); //打开缓冲区
phpinfo(); //使用phpinfo函数
$info = ob_get_contents(); //得到缓冲区的内容并且赋值给$info
$file = fopen('info.txt', 'w'); //打开文件info.txt
ob_clean(); // 关闭缓冲区
fwrite($file, $info); //写入信息到info.txt
fclose($file); //关闭文件info.txt
静态模版技术
一般的cms都有静态模板,它的好处是节省资源(不走php程序)、加快响应。使用输出缓冲可以完成该应用。
<?php
ob_start(); //打开缓冲区
echo '...'; // 输出内容
$fp = fopen('index.html', 'w');
fwrite($fp, ob_get_contents());
fclose($fp);
ob_end_clean();
收集错误信息并屏蔽错误输出
在系统上线的时候,我们通常不希望用户看到错误信息,但希望将错误信息保存到日志里,方便我们日后排查。使用输出缓冲,可以来完成。
<?php
// 处理非致命错误
function errorHandle($errLevel, $errInfo, $errFile, $errLine)
{
ob_start();
echo '错误:'.PHP_EOL;
print_r(['file' => $errFile, 'level' => $errLevel, 'line' => $errLine, 'info' => $errInfo]);
file_put_contents('error.txt',ob_get_contents(), FILE_APPEND );
ob_clean();
}
// 处理致命错误及异常
function exceptionHandle(Throwable $ex)
{
ob_start();
echo '异常:'.PHP_EOL;
print_r(['file' => $ex->getFile(), 'level' => $ex->getCode(), 'line' => $ex->getLine(), 'info' => $ex->getMessage()]);
file_put_contents('error.txt',ob_get_contents(), FILE_APPEND );
ob_clean();
}
set_error_handler('errorHandle');
set_exception_handler('exceptionHandle');
echo $a;
new b();
文章部分内容参考自:https://segmentfault.com/a/1190000009220776#item-4