首頁  >  文章  >  php教程  >  PHP 輸出快取詳解

PHP 輸出快取詳解

黄舟
黄舟原創
2016-12-14 13:13:581439瀏覽

輸出控制函數不對使用 header() 或 setcookie(), 發送的檔案頭資訊產生影響,只對那些類似於 echo() 和 PHP 程式碼的資料區塊有作用。
我們先舉一個簡單的例子,讓大家對Output Control有一個大致的印象: 
Example 1. 

程式碼如下:


ob_start(); "; //輸出 
header(“location:index.php”); //把瀏覽器重新導向到index.php 
ob_end_flush();//輸出全部內容到瀏覽器 
?> 
 

所有對header()函數有了解的人都知道,這個函數會發送一段文件頭給瀏覽器,但是如果在使用這個函數之前已經有了任何輸出(包括空輸出,比如空格,回車和換行)就會提示出錯。如果我們去掉第一行的ob_start(),再執行此程序,我們會發現得到了一條錯誤提示:「Header had all ready send by」!但加上ob_start,就不會提示出錯,原因是當開啟了緩衝區,echo後面的字元不會輸出到瀏覽器,而是保留在伺服器,直到你使用flush或ob_end_flush才會輸出,所以並不會有任何文件頭輸出的錯誤! 
一、 相關函數簡介: 
1、Flush:刷新緩衝區的內容,輸出。 
函數格式:flush() 
說明:這個函數常用,效率很高。 
2、ob_start :開啟輸出緩衝區 
函數格式:void ob_start(void) 
說明:當緩衝區啟動時,所有來自PHP程式的非檔案頭資訊不會傳送,而是保存在內部緩衝區。為了輸出緩衝區的內容,可以使用ob_end_flush()或flush()輸出緩衝區的內容。 
3 、ob_get_contents :傳回內部緩衝區的內容。 
使用方法:string ob_get_contents(void) 
說明:這個函數會傳回目前緩衝區中的內容,如果輸出緩衝區沒有激活,則傳回 FALSE 。 
4、ob_get_length:傳回內部緩衝區的長度。 
使用方法:int ob_get_length(void) 
說明:這個函數會回傳目前緩衝區中的長度;就像ob_get_contents一樣,如果輸出緩衝區沒有啟動。則回傳 FALSE。 
5、ob_end_flush :將內部緩衝區的內容傳送至瀏覽器,並且關閉輸出緩衝區。 
使用方法:void ob_end_flush(void) 
說明:這個函數會傳送輸出緩衝區的內容(如果有的話)。 
6、ob_end_clean:刪除內部緩衝區的內容,並且關閉內部緩衝區 
使用方法:void ob_end_clean(void) 
說明:這個函數不會輸出內部緩衝區的內容而是刪除它!
7、ob_implicit_flush:開啟或關閉絕對刷新 
使用方法:void ob_implicit_flush ([int flag]) 
說明:使用過Perl的人都知道$|=x的意義,這個字串可以開啟/關閉緩衝區,而ob_implicit_flush函數也和那個一樣,預設為關閉緩衝區,開啟絕對輸出後,每個腳本輸出都直接送到瀏覽器,不再需要呼叫flush() 
二、深入了解: 
1.關於Flush函數: 
這個函數在PHP3就出現了,是一個效率很高的函數,他有一個非常有用的功能就是刷新browser的cache.我們舉一個運作效果非常明顯的例子來說明flush. 
Example 2. 

程式碼如下:

for($i = 1; $i // 這句話非常關鍵,cache的結構使得它的內容只有達到一定的大小才能從瀏覽器輸出 
// 換言之,如果cache的內容不達到一定的大小,它是不會在程式執行完畢前輸出的。經 
// 過測試,我發現這個大小的底限是256個字元長。這表示cache以後收到的內容都會 
// 源源不絕的被送出去。
For($j = 1; $j echo $j.” 
”; 
flush(); //這一部會使cache新增的內容被擠出去,顯示到瀏覽器上 
sleep(1); //讓程式「睡」一秒鐘,會讓你把效果看得更清楚 

?> 
 


具體效果你可以到這裡看看http://www.php2000.com/~uchinaboy/out.php 
PHP2000的最新的PHP聊天室就是用的這個技術,可惜的是原始碼未公開L 
注:如果在程式的首部加入ob_implicit_flush()開啟絕對刷新,就可以在程式中不再使用flush(),這樣做的好處是:提高效率!
2. 關於ob系列函數: 
我想先引用我的好朋友y10k的一個例子: 
Example 3. 
比如你用得到伺服器和客戶端的設定訊息,但是這個資訊會因為客戶端的不同而不同,如果想要保存phpinfo()函數的輸出怎麼辦呢?在沒有緩衝區控制之前,可以說一點辦法也沒有,但是有了緩衝區的控制,我們可以輕鬆的解決: 

程式碼如下:


ob_start(); //開啟緩衝區
phpinfo(); //使用phpinfo函數 
$info=ob_get_contents(); //得到緩衝區的內容並且賦值給$info 
$file=fopen('info.txt','w'); //開啟檔案info.txt 
fwrite($file,$info); //寫入訊息到info.txt 
fclose($file); //關閉檔案info.txt 
?> 
 


用以上的方法,就可以把不同使用者的phpinfo資訊保存下來,這在以前恐怕沒有辦法辦到!其實上面就是將一些「過程」轉換為「函數」的方法!
或許有人會問:「難道就這個樣子嗎?還有沒有其他用途?」當然有了,例如筆者論壇的PHP 語法加亮顯示就和這個有關(PHP預設的語法加亮顯示函數會直接輸出,不能儲存結果,如果在每次呼叫都顯示恐怕會很浪費CPU,筆者的論壇就把語法加亮函數顯示的結果用控制緩衝區的方法保留了),大家如果有興趣的話可以來看看http: //www.zphp.com/bbs/! 
可能現在大家對ob_start()的功能有了一定的了解,上面的一個例子看似簡單,但實際上已經掌握了使用ob_start()的重點。 
.使用ob_start開啟browser的cache,這樣可以確保cache的內容在你呼叫flush(),ob_end_flush()(或程式執行完畢)之前不會被輸出。
.現在的你應該知道你所擁有的優點:可以在任何輸出內容後面使用header,setcookie以及session,這是ob_start一個很大的特點;也可以使用ob_start的參數,在cache被寫入之後,然後自動執行指令,例如ob_start("ob_gzhandler");而我們最常用的做法是用ob_get_contents()得到cache中的內容,然後再進行處理… 
.當處理完畢後,我們可以使用各種方法輸出,flush(),ob_end_flush(),以及等到程式執行完畢後的自動輸出。當然,如果你用的是ob_get_contents(),那麼就要你自己控制輸出方式了。
來,讓我們看看能用ob系列函數做些什麼… 
一、靜態模版技術 
簡介:所謂靜態模版功能就是透過某種方式,使得使用者在client端得到的是由PHP產生的html頁面。如果這個html頁面不會再更新,那麼當另外的使用者再次瀏覽此頁面時,程式將不會再呼叫PHP以及相關的資料庫,對於某些資訊量比較大的網站,例如sina,163,sohu。類似這種的技術帶來的好處是非常巨大的。 
我所知道的實作靜態輸出的有兩種方法: 
.透過y10k修改的phplib的一個叫做template.inc.php類別實作。 
.使用ob系列函數實作。 
對於第一種方法,因為不是這篇文章所要研究的問題,所以不再贅述。
我們現在來看看第二種方法的具體實作: 
Example 4. 
ob_start();//打開緩衝區 
?> 
php頁的全部輸出 
?> 
php頁的全部輸出 
? ();//取得php頁面輸出的全部內容 
$fp = fopen(“output00001.html”, “w”); //建立一個文件,並打開,準備寫入 
fwrite($fp, $content) ; //把php頁的內容全部寫入output00001.html,然後… 
fclose($fp); 
?> 
這樣,所謂的靜態模版就很容易的被實現了… 
二、 捕捉輸出 
以上的Example 4.是一種最簡單的情況,你還可以在寫入前對$content進行操作…… 
你可以設法捕捉一些關鍵字,然後去對它進行再處理,比如Example 3.所述的PHP語法高亮顯示。個人認為,這個功能是此函數最大的精華所在,它可以解決各種各樣的問題,但需要你有足夠的想像力… 
Example 5. 
 
Function run_code($code) { 
If ($code) { 
ob_start(); 
eval($code); 
$contents = ob_get_contents(); 
ob_end_clean(); 
}else { 
echo);
return $contents; 

以上這個例子的用途不是很大,不過很典型$code的本身就是一個含有變數的輸出頁面,而這個例子用eval把$code中的變數替換,然後對輸出結果再進行輸出捕捉,再一次的進行處理… 
Example 6. 加速傳輸 
 
/* 
** Title.........: PHP4 HTTP Compression Speeds up the Web 
** Version.. .....: 1.20 
** Author........: catoc  
** Filename......: gzdoc.php 
** Last changed..: 18/10/2000 
** Requirments...: PHP4 >= 4.0.1 
** PHP was configured with --with-zlib[=DIR] 
** Notes.........: Dynamic Content Acceleration compresses 
** the data transmission data on the fly 
** code by sun jin hu (catoc)  
** Most newer browsers since 163.net> 
** Most newer browsers since 1998/19999998/1999998 至 % HTTP 1.1 
** standard known as "content-encoding." 
** Essentially the browser indicates to the 🎜** 伺服器可以接受「內容編碼」
**,如果伺服器有能力,它將
** 壓縮資料並傳輸它。
** 瀏覽器對其進行解壓縮,然後呈現
** 頁面。
** 
** 由John Lim (jlim@natsoft.com.my) 修改
** 基於Sandy McArthur, Jr 的想法 
** 使用........: 
** 之前沒有空格第一個'' 的開頭標籤。
** ------------文件開始---------- 
** | 
** |包括('gzdoc.php'); 
** | ? > 
** | 
** |...頁... 
** | 
** | 
** | gzdocout(); 
** |? > 
** -------------檔案結束--------- 
*/ 
ob_start(); 
ob_implicit_flush(0); 
function CheckCanGzip(){ 
global $HTTP_ACCEPT_ENCODING; 
if (headers_sent() || connection_timeout() || connection_aborted()){ 
return 0; 

if (strpos($HTTP_ACCEPT_ENAINGDINGp. gzip"; 
if (strpos($HTTP_ACCEPT_ENCODING,'gzip') !== false) return "gzip"; 
回傳0; 

/* $level = 壓縮等級0-9,0=無,9=9=9=9=9=9 */ 
function GzDocOut($level=1,$debug=0){ 
$ENCODING = CheckCanGzip(); 
if ($ENCODING){ 
print "nn";
$Contents = ob_get_contents(); 
ob_end_clean(); 
if ($debug){ 
$s = "

不壓縮長度:".strlen($Contents); 
$s = "

不壓縮長度:".strlen($Contents); ".strlen(gzcompress($Contents,$level)); 
$內容.= $s; 

header("內容編碼:$ENCODING"); 
列印「x1fx8bx08x00x00x00x00x0000x ); 
$Crc = crc32($Contents); 
$Contents = gzcompress($Contents,$level); 
$Contents = substr($Contents, 0, strlen($ents) - 4); 列印內容

打印包('V',$Crc); 
打印包('V',$Size); 
退出; 
}其他{ 
ob_end_flush(); 
退出; > 
這是catoc的很早以前的程式碼,是在weblogs.com的一段時間,他利用了zlib的函數,對傳輸的內容進行了壓縮,測試表演,對於10k以上的頁面,會產生效果,而且頁面越大,效果越明顯…

想要取得更多的相關內容請關注PHP中文網(www.php.cn)!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn