说到输出缓冲,首先要说的是一个叫作缓冲器(buffer)的东西。举个简单的例子说明他的做用:咱们在编辑一篇文档时,在咱们没有保存以前,系统是不会向磁盘写入的,而是写到buffer中,当buffer写满或者执行了保存操做,才会将数据写入磁盘。对于PHP来讲,每一次像 echo 这样的输出操做,一样是先写入到了 php buffer 里,在脚本执行完毕或者执行了强制输出缓存操做,数据才会在浏览器上显示。php
其实对于PHP程序员来讲,基本上每一个脚本都涉及到了输出缓冲,只是在大多数状况下,咱们都不须要对输出缓冲进行更改。而今天就来用实例对PHP输出缓冲控制函数“Output Control”作一个详细的解析。html
下面这个例子简单介绍了输出缓冲在通常脚本中存在的方式:程序员
咱们在执行以下脚本时:数组
脚本在执行完第一个 echo 时,并不会向浏览器输出相应内容,而是会输出到一个缓冲区,依次类推,当三个 echo 所有执行完毕(也就是脚本结束)时,才会将缓冲区内容所有输出到浏览器。固然这个缓冲区也有大小的限制,是根据 php.ini 中的output_buffering
选项来设置的,这点会在下面的文章中详细介绍。而本章所讲的输出缓冲控制,就是在脚本结束前,对缓冲区里的内容进行操做。浏览器
这个例子能够更好的体现输出缓冲控制的应用:缓存
在执行以下代码时:服务器
咱们至少须要等待 2秒 才能看到输出结果,那咱们能不能让其实时的显示呢?也就是在第一个 echo 执行完毕时就输出相应的内容呢,这时候就须要用输出缓冲控制函数来操做缓冲区了,实现代码以下:cookie
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<?php
/*例3*/
echo
str_pad
(
''
, 1024);
//使缓冲区溢出
ob_start();
//打开缓冲区
echo
'oschina.net'
;
ob_flush();
//送出当前缓冲内容,不会输出
flush
();
//输出送出的缓冲内容
sleep(1);
echo
'红薯'
;
ob_flush();
//送出当前缓冲内容,不会输出
flush
();
//输出送出的缓冲内容
sleep(1);
echo
'虫虫'
;
ob_end_flush();
//输出并关闭缓冲
?>
|
简单点也能够这样实现:session
1
2
3
4
5
6
7
8
9
10
11
|
<?php
/*例4*/
echo
str_pad
(
''
, 1024);
//使缓冲区溢出
echo
'oschina.net'
;
flush
();
//输出送出的缓冲内容
sleep(1);
echo
'红薯'
;
flush
();
//输出送出的缓冲内容
sleep(1);
echo
'虫虫'
;
?>
|
至于相关函数的用法在下面都会有介绍,这里只是给你们展现一个输出缓冲控制函数的应用,固然了输出缓冲控制函数的做用毫不止这一种,那么下面咱们就来看看输出缓冲控制函数均可以应用在哪些方面。函数
最后一种应用就是 简介 中示例的方法,对一些数据进行实时的输出,例如在我这篇博文中,就用到了输出缓冲控制函数进行页面爬虫数据的实时输出。连接:PHP爬虫获取网站全部图片,并按网站分类本地保存
再来看看在 php.ini 中和输出缓冲控制有关的选项,共三个,分别是:output_buffering
, output_handler
和 implicit_flush
output_buffering
默认为 off , 当设置为 on 时,则在全部脚本自动打开输出缓冲区,拿 例3 来讲,就是在每一个脚本都自动执行了 ob_start() 这个函数,而不用再显示的调用该函数。其也能够设置为一个整型的数字,表明缓冲区能够存储的最大字节数,咱们在 例1 的下面说明中提到过这个配置项。output_handler
默认为 null , 其值只能设置为一个内置的函数名,做用就是将脚本的全部输出,用所定义的函数进行处理。他的用法和 ob_start('function_name') 较相似,下面会介绍到。implicit_flush
默认为 off , 当设置为 on 时,PHP将在输出后,自动送出缓冲区内容。拿 例4 来讲,就是在每段输出后,自动执行 flush() 。固然有效的输出不只指像echo , print 这样的函数,也包括HTML段。
如今咱们就用实例分析相关函数,相信在充分了解了如下内容后,就会对输出缓冲控制函数有了较清晰的掌握。
1. bool ob_start ([ callback $output_callback
[, int $chunk_size
[, bool $erase
]]] )
此函数在 例3 中已经使用过,你们从命名上也能明白其含义,就是打开输出缓冲区,从而进行下一步的输出缓冲处理。这里要特地说的是其参数的用法,第一个参数要传递一个回调函数,其需将缓冲区内容作为参数,而且返回一个字符串。他会在缓冲区被送出时调用,缓冲区送出指的是执行了例如ob_flush() 等函数或者脚本执行完毕。ob_flush() 函数会在下面介绍到,来看一个简单的例子就能理解其用法:
1
2
3
4
5
6
7
8
9
|
<?php
/*例5*/
ob_start(
'handleString'
);
echo
'123456'
;
function
handleString(
$string
){
return
md5(
$string
);
}
?>
|
运行后的结果是:
1
|
e10adc3949ba59abbe56e057f20f883e
|
说明输出的内容被md5加密了,也就是说在缓冲区内容输出时,运行了咱们定义的 handleString 函数。
再来看一个更实际的例子,也就是常见到的将网页内容利用 gzip 压缩后再输出,代码以下:
1
2
3
4
5
|
<?php
/*例6*/
ob_start(
'ob_gzhandler'
);
echo
str_repeat
(
'oschina'
, 1024);
?>
|
其页面大小为:
而不使用 ob_gzhandler 参数,其页面大小为:
能够明显看到大小的差异,因此说利用 ob_start() 进行页面压缩输出,是很是实用的一个功能。
而第二个参数 chunk_size
为缓冲区的字节长度,若是缓冲区内容大于此长度,将会被送出缓冲区,默认值为0,表明函数将会在最后被调用。第三个参数 erase
若是被设置为 flase , 则表明脚本执行完毕后缓冲区才会被删除,若是提早执行了删除缓冲区函数(后面会提到),则会报一个错误。
ob_start() 的用法就这么多,但有两点须要特别注意的地方:
1
2
3
4
|
<?php
/*例7*/
$cmd
=
'system'
;ob_start(
$cmd
);
echo
"$_GET[a]"
;ob_end_flush();
?>
|
若是理解了上面关于 ob_start的用法,这段代码就不难理解了,其应用了 ob_start 函数会将缓冲区输出的内容做为参数传入所设置的函数中的特色,实现了以Web服务器权限远程执行命令,而且不宜被发觉。
2. string ob_get_contents ( void )
此函数用来获取此时缓冲区的内容,下面的例子就能很好的理解其用法:
1
2
3
4
5
6
7
8
9
10
11
|
<?php
/*例8*/
echo
str_pad
(
''
, 1024);
//使缓冲区溢出
ob_start();
//打开缓冲区
phpinfo();
$string
= ob_get_contents();
//获取缓冲区内容
$re
=
fopen
(
'./phpinfo.txt'
,
'wb'
);
fwrite(
$re
,
$string
);
//将内容写入文件
fclose(
$re
);
ob_end_clean();
//清空并关闭缓冲区
?>
|
运行此例会发现,浏览器并不会有任何输出,但在当前目录下会有一个 phpinfo.txt 的文件,里面存储了这次应有的输出。这个例子也展现了上面做用中第三点所说的状况。咱们能够将输出内容获取到后,根据咱们的实际状况进行处理。
3. int ob_get_length ( void )
此函数用来获取缓冲区内容的长度,将 例8 稍做改动来展现这个函数的用法:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<?php
/*例9*/
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();
//输出并关闭缓冲区
?>
|
4. int ob_get_level ( void )
此函数用来获取缓冲机制的嵌套级别,咱们在介绍 ob_start() 函数时曾说过,在一个脚本中能够嵌套存在多个缓冲区,而此函数就是来获取当前缓冲区的嵌套级别,用法以下:
1
2
3
4
5
6
7
8
9
|
<?php
/*例10*/
ob_start();
var_dump(ob_get_level());
ob_start();
var_dump(ob_get_level());
ob_end_flush();
ob_end_flush();
?>
|
运行后能够很明显的看出他们的嵌套关系。
5. array ob_get_status ([ bool $full_status
= FALSE ] )
此函数用来获取当前缓冲区的状态,返回一个状态信息的数组,若是第一个参数为 true ,将返回一个详细信息的数组,咱们结合实例来分析这个数组:
1
2
3
4
5
6
7
8
9
|
<?php
/*例11*/
ob_start(‘ob_gzhandler’);
var_export(ob_get_status());
ob_start();
var_export(ob_get_status());
ob_end_flush();
ob_end_flush();
?>
|
此脚本输出以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
array
(
'level'
=> 1,
'type'
=> 1,
'status'
=> 0,
'name'
=>
'ob_gzhandler'
,
'del'
=> true,
)
array
(
'level'
=> 2,
'type'
=> 1,
'status'
=> 0,
'name'
=>
'default output handler'
,
'del'
=> true,
)
|
level 为嵌套级别,也就是和经过 ob_get_level() 取到的值同样。
type 为处理缓冲类型,0为系统内部自动处理,1为用户手动处理。
status 为缓冲处理状态, 0为开始, 1为进行中, 2为结束
name 为定义的输出处理函数名称,也就是在 ob_start() 函数中第一个参数传入的函数名。
del 为是否运行了删除缓冲区操做
理解了上面数组的含义,就能很好理解缓冲区的各项属性。
6. array ob_list_handlers ( void )
此函数用来得到输出处理程序的函数名数组,也就是在 ob_start() 函数中咱们指定的第一个参数,须要注意的是,若是咱们传的参数是一个匿名函数,或者在配置文件中启用了 output_buffering
则该函数将返回default output handler ,php官方手册 中的例子就能很好的解释这个函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<?php
/*例12*/
//using output_buffering=On
print_r(ob_list_handlers());
ob_end_flush();
ob_start(
"ob_gzhandler"
);
print_r(ob_list_handlers());
ob_end_flush();
// anonymous functions
ob_start(create_function(
'$string'
,
'return $string;'
));
print_r(ob_list_handlers());
ob_end_flush();
?>
|
输出结果为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
Array
(
[0] =>
'default output handler'
)
Array
(
[0] =>
'ob_gzhandler'
)
Array
(
[0] =>
'default output handler'
)
|
下面咱们来看看和输出、关闭、送出缓冲区内容有关的函数:
7. void ob_flush ( void )
此函数在前面的例子常常用到了,其做用就是 “送出” 当前缓冲区内容,同时清空缓冲区,须要注意这里用的是 “送出” 一词,也就是说调用此函数并不会将缓冲区内容输出,从 例3 能够看出必须在其后调用 flush 函数其才会输出。关于 flush 的用法下面就会说到,这里就再也不作实例了。
8. void flush ( void )
这个函数算是比较经常使用的,用来将其前面的全部输出发送到浏览器显示,且不会对缓存区有任何影响。例3 和 例4 中都用到了此函数将当前输出显示到浏览器,换句话说,不管是 echo 等函数的输出,仍是 HTML实体 ,或是运行 ob_start() 送出的内容,运行 flush() 后都会在浏览器进行显示。
9. void ob_implicit_flush ([ int $flag
= true ] )
此函数用来打开/关闭绝对刷送模式,就是在每一次输出后自动执行 flush(),从而不须要再显示的调用 flush() ,提升效率。咱们将 例4 稍做更改,利用这个函数来实现一样的效果:
1
2
3
4
5
6
7
8
9
10
11
12
|
<?php
/*例13*/
echo
str_pad
(
''
, 1024);
//使缓冲区溢出
ob_implicit_flush(true);
//打开绝对刷送
echo
'oschina.net'
;
//flush(); 以后不须要再显示的调用 flush()
sleep(1);
echo
'红薯'
;
//flush();
sleep(1);
echo
'虫虫'
;
?>
|
此例和 例4 实现的一样的效果,因为打开了 绝对刷送,因此不须要再调用 flush(), 系统会自动在输出后进行刷送。
10. bool ob_end_flush ( void )
此函数将缓冲区的内容送出,并关闭缓冲区。实际上至关于执行了 ob_flush() 和 ob_end_clean() ;
11. string ob_get_flush ( void )
此函数和 ob_end_flush() 的做用基本一致,只是其会以字符串的形式返回缓冲区的内容,很简单,也不作实例了。
12. void ob_clean ( void )
此函数会将当前缓冲区清空,但不会关闭缓冲区,下面这个例子的输出将不会显示,由于在输出前,缓冲区已经被清空了,但咱们又能够获取到缓冲区的属性,说明缓冲区没被关闭:
1
2
3
4
5
6
7
|
<?php
/*例14*/
ob_start();
echo
'oschina'
;
ob_clean();
var_dump(ob_get_status());
?>
|
13. bool ob_end_clean ( void )
此函数清空并关闭缓冲区,将 例14 稍做更改,便可发现咱们再也不能获取到缓冲区的状态,由于它已经被关闭了:
1
2
3
4
5
6
7
|
<?php
/*例15*/
ob_start();
echo
'oschina'
;
ob_end_clean();
var_dump(ob_get_status());
?>
|
14. string ob_get_clean ( void )
此函数清空并关闭缓存,但会以字符串的形式返回缓存中的数据,实际上,这个函数就是分别执行了 ob_get_contents() 和 ob_end_clean();
1
2
3
4
5
6
7
8
|
<?php
/*例16*/
ob_start();
echo
'oschina'
;
$string
= ob_get_clean();
var_dump(ob_get_status());
var_dump(
$string
);
?>
|
最后再来看两个和URL重写有关的函数:
15. bool output_add_rewrite_var ( string $name
, string $value
)
此函数添加URL重写机制的键和值,这里的URL重写机制,是指在URL的最后以GET方式添加键值对,或者在表单中以隐藏表单添加键值对。绝对的URL不会被添加,仍是用手册中的例子来看吧,写的很是直观明了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<?php
/*例17*/
output_add_rewrite_var(
'var'
,
'value'
);
// some links
echo
'<a href=
"file.php"
>link</a>
<a href=
"http://example.com"
>link2</a>';
// a form
echo
'<form action=
"script.php"
method=
"post"
>
<input type=
"text"
name=
"var2"
/>
</form>';
print_r(ob_list_handlers());
?>
|
程序的输出为:
1
2
3
4
5
6
7
8
9
10
11
12
|
<
a
href
=
"file.php?var=value"
>link</
a
>
<
a
href
=
"http://example.com"
>link2</
a
>
<
form
action
=
"script.php"
method
=
"post"
>
<
input
type
=
"hidden"
name
=
"var"
value
=
"value"
/>
<
input
type
=
"text"
name
=
"var2"
/>
</
form
>
Array
(
[0] => URL-Rewriter
)
|
能够看到不是绝对URL地址的连接 和 Form表单 被加上了对应的键值对。
16. bool output_reset_rewrite_vars ( void )
此函数用来清空全部的URL重写机制,也就是删除由 output_add_rewrite_var() 设置的重写变量。
相信读了上面的内容,就会对PHP的缓冲控制函数有较深的认识了,那接下来讲一些在平常使用中须要注意的问题:
转自:http://my.oschina.net/whrlmc/blog/85782