在php所謂的輸出緩衝,就是代碼中的echo 或者其他輸出命令在執行的時候是先寫入到 php buffer,在指令碼執行完或者強制執行輸出緩衝的命令後,才會把資料輸出到瀏覽器(其中php buffer 就是php.ini中設定的output_buffering ,預設是on,表明無限制大小,可以換成數字來限制大小)。
例子:
echo 'www.111cn.net';
echo '技術';
echo '分享';
這兩個echo 是按順序插入到緩衝區的,只有指令碼執行完成或者強制執行緩衝輸出才會把資料輸出到瀏覽器。
如果我想要即時地輸出echo的資料,見下面的代碼:
ob_end_flush(); //關閉php緩衝,或者在flush()前先執行ob_flush(),下面有解釋
echo str_pad(" ", 256);
for ($i=5; $i>0; $i--) {
echo $i. '<br>';
flush();
sleep(1);
}
注意:
1:flush和ob_flush 區別:
乍看之下兩者很像,而且很多手冊的解釋也不清楚,模淩兩可,其實兩者是有很大區別的。
當php.ini沒有開啟php buffer緩衝時,php指令碼輸出的內容都會在服務端處於等待輸出狀態 ,不會儲存到輸出緩衝,因為緩衝都沒開,此時利用flush可以將那些等待輸出的內容立即輸出來發到用戶端(瀏覽器或者其他輸出端)。
當php.ini開啟了php buffer緩衝後,php指令碼輸出內容的第一步是儲存在輸出緩衝中 ,此時等到輸出的內容是沒有資料的,用flush的話是無效果,取不到資料的。因此要先利用ob_flush把輸出緩衝中的內容取出來變成等待輸出的狀態,接下來在利用flush把內容發到用戶端。執行的順序是先ob_flush 再 flush。
因此要實現即時地輸出,要麼利用ob_end_flush 先關掉php 輸出緩衝後直接flush,要麼先 ob_flush再flush。
2:瀏覽器無法輸出即時資料
把代碼改成下面的代碼,在chrome firefox ie等瀏覽器都是一次性輸出的,很奇葩的現象:
ob_end_flush(); //關閉php緩衝,或者在flush前ob_flush();
echo str_pad(" ", 256);
for ($i=5; $i>0; $i--) {
echo $i;
flush();
sleep(1);
}
找了半天的bug,終於發現了個現象,只要順便加個html標籤,即可即時輸出。
原因是:只有在遇到html標籤的時候才會即時輸出,真是神奇,還好一般輸出的內容都會帶著html標籤,很少純文字。
解決辦法:加個斷行符號或者其他的html標籤即可解決問題。
一:下面詳細介紹out control 的相關函數
1、flush //將等待輸出的內容發送帶瀏覽器,不會對緩衝區有影響。
2、ob_flush // 將緩衝區的內容變成等待輸出狀態,資料還沒有輸出到用戶端。
3、ob_start(callback) // 開啟輸出緩衝區,可以加入回調的callback函數,實現在輸出之前執行想要的功能。
例子(1)
ob_start('callbackFun');
echo '1111111';
function callbackFun($string){
return md5($string);//進行md5加密
}
結果:
1
e10adc3949ba59abbe56e057f20f883e
瀏覽器返回的結果是加密過的字串,而不是 1111111,說明在資料存入輸出緩衝之前執行了回呼函數對資料進行了md5加密後才存入輸出緩衝的。
例子(2)
結合ob_gzhandler實現網頁內容的gzip壓縮,減少傳輸的大小,提高頁面的載入速度。
ob_start('ob_gzhandler');
echo str_repeat('hlmblog', 1024);
使用了ob_gzhandler 後頁面的大小:
沒使用ob_gzhandler 的頁面大小
明顯壓縮後頁面的大小變小了很多。
例子(3)
可以嵌套ob_start,但是記得要有對應的閉合,兩個一一對應,不然會報錯,或者取不到資料。
ob_start();
var_dump(1);
ob_start();
var_dump(2);
ob_end_flush();
ob_end_flush();
結果:
int 1
int 2
4、ob_get_contents() 擷取輸出緩衝區的內容或者頁面輸出的內容
echo str_pad('', 1024);//使緩衝區溢位
ob_start();//開啟緩衝區
phpinfo();
$content = ob_get_contents();//擷取緩衝區內容
$f = fopen('./phpinfo.txt', 'wb');//開啟檔案
fwrite($f, $content);//內容寫入txt檔案
fclose($f);//關閉檔案
ob_end_clean();//關閉緩衝區,輸出資料並清空瀏覽器
//ob_end_flush();//發送緩衝區內容到用戶端,並關閉緩衝區,不清空瀏覽器
注意:
這時候瀏覽器將什麼都不輸出,因為使用了ob_end_clean() 清空掉了,但是會在目前的目錄產生一個phpinfo.txt 的檔案,裡面是擷取到的phpinfo資訊。
如果使用ob_end_flush,不僅會產生phpinfo.txt 檔案,而且還在瀏覽器輸出資訊。
5、ob_get_length() 返回輸出緩衝區的內容長度
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();//輸出並關閉緩衝區
6、ob_get_level() //擷取輸出緩衝區嵌套層級,就是所處的層級位置
ob_start();
var_dump(ob_get_level());
ob_start();
var_dump(ob_get_level());
ob_end_flush();
ob_end_flush();
瀏覽器會輸出對應的層級:
int 2
int 3
7、ob_get_status() //擷取當前緩衝區的狀態,返回的是一個數組資訊
ob_start('ob_gzhandler');
var_dump(ob_get_status());
ob_start();
var_dump(ob_get_status());
ob_end_flush();
ob_end_flush();
array
'level' => int 2
'type' => int 1
'status' => int 0
'name' => string 'ob_gzhandler' (length=12)
'del' => boolean true
array
'level' => int 3
'type' => int 1
'status' => int 0
'name' => string 'default output handler' (length=22)
'del' => boolean true
返回數組參數詳解:
level:嵌套層級,和ob_get_level()擷取到的值是一樣的。
type :處理緩衝類型,0是系統內部自動處理,1是使用者手動處理。
status :緩衝處理狀態, 0是開始, 1是進行中, 2是結束。
name: :定義的輸出處理函數名稱,就是ob_start() 函數中第一個參數的回呼函數。
del :是否運行了刪除緩衝區操作。
8、ob_list_handlers() //獲得處理常式的函數名數組,也就是ob_start函數傳入的第一個參數函數名
print_r(ob_list_handlers());
ob_end_flush();
ob_start("ob_gzhandler");
print_r(ob_list_handlers());
ob_end_flush();
瀏覽器輸出對應的處理函數資訊數組:
Array ( [0] => default output handler ) Array ( [0] => ob_gzhandler )
9、ob_implicit_flush() // 開啟或關閉絕對刷送模式,就是每一次輸出後自動執行 flush(),不用對應地寫多次的flush,節省代碼,提高效率
echo str_pad('', 1024);//緩衝區溢位
ob_end_flush();
ob_implicit_flush(true);//開啟絕對刷送
echo 'hlmblog</br>';
//flush();
sleep(1);
echo '分享</br>';
//flush();
sleep(1);
echo '技術</br>';
瀏覽器即時的輸出下面:
hlmblog
分享
技術
10、ob_end_flush() //發送內部緩衝區的內容到瀏覽器,並且關閉輸出緩衝區
11、ob_end_clean() //刪除內部緩衝區的內容,並且關閉內部緩衝區
二:控制緩衝輸出可以用來做什麼,具體的幾個樣本
1:產生靜態頁面
靜態頁面的載入速度就是快,這句話是家戶喻曉的道理,不用請求資料庫,這是多麼爽的事情啊。
下面是產生靜態頁面的例子:
echo str_pad('', 1024);//使緩衝區溢位
ob_start();//開啟緩衝區
$content = ob_get_contents();//擷取頁面輸出的內容
$f = fopen('./index.html', 'w');
fwrite($f, $content);//內容寫入txt檔案
fclose($f);
ob_end_clean();//清空並關閉緩衝區
傳說中的靜態頁面就這樣簡單的產生。
2:捕獲輸出
function test($param) {
if($param) {
ob_start();
eval($param);
$contents = ob_get_contents();
ob_end_clean();
}else {
echo '遺憾的沒有輸出';
exit();
}
return $contents;
}