PHP中的output_buffering详细介绍
我个人认为,Outputbuffering是比较纯粹的4.0特征。尽管从概念上看来相当简单,但是outputbuffering功能非常强大,能使开发者更容易地开发高级而有效的程序。
本文将介绍HTTPheader,以及outputbuffering如何帮助您处理HTTPheader,并介绍了outputbuffering的一些高级用法。
HTTPHeader
对于使用HTTP协议建立的每个请求,Web服务器产生的响应通常包括两个部分–标题和主体。例如,如果在Web服务器的文档根目录下有一个小文本文件,叫做example.txt,文件中包含文本Hello,world!,那么对此文件的HTTP请求响应如下所示:
HTTP/1.1200OK Date:Sat,02Sep200021:40:08GMT Server:Apache/1.3.11(Unix)mod_macro/1.1.1PHP/4.0.2-dev Last-Modified:Sat,02Sep200021:39:49GMT ETag:"12600b-e-39b173a5" Accept-Ranges:bytes Content-Length:14 Connection:close Content-Type:text/plain Hello,world!
这个请求中的第一部分(就是较多的那部分)就是HTTPheader。虽然用户在浏览器中看不到HTTPheader,但它包含了用于浏览器的信息,例如文档内容类型,使用的协议版本,文档的最后更改日期等等。HTTPheader并没有太多的规则,通常情况下,它的格式如下:
Field:Value[字段:值]
必须用空行将它们和文档主体分开。
可以从PHP脚本添加或更改此HTTPheader的信息。例如,可以使用header()函数:
header("Location:http://www.php.net/"); //重定向到http://www.php.net/
也可以使用SetCookie()函数:
SetCookie("foo","bar");
你可能会知道HTTPcookies是使用HTTPheaders来实现的。例如,以下PHP文件的HTTP请求响应
<?php SetCookie("foo","bar"); print"Setcookie."; ?>
将会是这样的:
HTTP/1.1200OK Date:Sat,02Sep200021:43:02GMT Server:Apache/1.3.11(Unix)mod_macro/1.1.1PHP/4.0.2-dev X-Powered-By:PHP/4.0.2-dev Set-Cookie:foo=bar Connection:close Content-Type:text/html Setcookie.
浏览器读取从服务器返回的HTTPheader,知道送来了一个叫做foo的cookie(在这里是一个sessioncookie),它的值是bar。
为什么要使用OutputBuffering技术
早在PHP/FI2.0时就很明显需要outputbuffering技术了。如果你使用过这种版本的PHP,那么可能还记得经常会碰到Oops,SetCookiecalledafterheaderhasbeensent这个错误消息,并使你捎头抓耳,也弄不清是什么原因。
如果你已使用过PHP的最新版本--PHP3.0甚至PHP4.0--那么你会知道这个错误消息:Oops,php_set_cookiecalledafterheaderhasbeensent。或者,你在试图调用PHP的header()函数时会遇到Cannotaddheaderinformation-headersalreadysent消息。一般来说,outputbuffering技术用户避免这些烦人的错误消息,同时开发人员也可用于高级的用途。
这些错误是什么时候产生的呢?如果你在已经发送了HTTPheader之后试图添加或修改标题信息,以及在文档主体和标题之间缺少空行时,就会产生这些错误消息。为了理解这是如何产生的,让我们来看看PHP是如何处理HTTPheader输出和主体输出的。
脚本开始执行时,它可以同时发送header(标题)信息和主体信息。
Header信息(来自header()或SetCookie()函数)并不会立即发送,相反,它被保存到一个列表中。
这样就可以允许你修改标题信息,包括缺省的标题(例如Content-Type标题)。但是,一旦脚本发送了任何非标题的输出(例如,使用块或print()调用),那么PHP就必须先发送所有的标题,然后再送出空行,终止HTTPheader,而在此之后才会继续发送主体数据。从这时开始,任何添加或修改标题信息的试图都是不允许的,并会发送上述的错误消息之一。
虽然这并不会引起多大的问题,有时候只是在发出任何输入之前终止HTTPheader,从而引起脚本逻辑的复杂化而已。Outputbuffering技术可以解决这些问题。
OutputBuffering的工作原理
启用outputbuffering时,在脚本发送输出时,PHP并不发送HTTPheader。相反,它将此输出通过管道(pipe)输入到动态增加的缓存中(只能在PHP4.0中使用,它具有中央化的输出机制)。你仍然可以修改,添加标题行,或者设置cookie,因为标题实际上并没有发送。最简单的情况是,当脚本终止时,PHP将自动发送HTTPheader到浏览器,然后再发送输出缓冲中的内容。这简单吧。
基本用法
可以使用下面的四个函数,它们可以帮助你控制outputbuffering:
ob_start()
启用outputbuffering机制。
Outputbuffering支持多层次--例如,可以多次调用ob_start()函数。
ob_end_flush()
发送outputbuffer(输出缓冲)并禁用outputbuffering机制。
ob_end_clean()
清除outputbuffer但不发送,并禁用outputbuffering。
ob_get_contents()
将当前的outputbuffer返回成一个字符串。允许你处理脚本发出的任何输出。
此外,可以启用php.ini中的output_buffering指令。如果启用了此指令,那么每个PHP脚本都相当于一开始就调用了ob_start()函数。
Example1
<?phpob_start();?> <h1>Example1</h1> <?php print"Hello,$user"; SetCookie("Wow","Thiscookiehasbeenseteventhoughwe'vealreadyemittedoutput!"); ?>
这里,尽管你已发送了输出(HTML代码块中和print语句中),也可以使用SetCookie()调用,而不会出错,真的要感谢outputbuffering机制。请注意使用outputbuffering机制用于这种目的会引起一定程度上的性能损失,因此最好缺省情况下不要启用此机制。但是,对于复杂一些的脚本,outputbuffering可以简化逻辑性。
Example2
<?php ob_start(); print"Here'saprettydumbwaytocalculatethelengthofastring."; $length=strlen(ob_get_buffer()); ob_end_clean(); ?>
这个例子显示了一个效率很低的确定字符串长度的。它不是简单的使用strlen()函数处理,而是先启用outputbuffering机制,将字符串打印出来,然后再确定outputbuffer的长度。最后清除outputbuffer(并没有发送),然后禁用outputbuffering机制。