簡單而言,緩沖區的作用就是,把輸入或者輸出的內容先放進內存,而不顯示或者讀取.至於為什麼要有緩沖區,這是一個很廣泛的問題,如果有興趣,可以在網山找下資料.
其實緩沖區最本質的作用就是,協調高速CPU和相對緩慢的IO設備(磁盤等)的運作.
由此可見,PHP要輸出數據的時候,將會經過兩個緩沖區(先是自身的,然後是apache的),再返回到浏覽器.
echo
"this
is test"
;
header(
"LOCATIONhttp://www.baidu.com"
);
出現這個錯誤的原因是, 在header之前已經輸出了某些數據,而輸出這些數據的同時, apache將會同時發送一個響應狀態到浏覽器上(既然有輸出,即這個請求是有效的),而其後你又再次使用header函數
發送http頭,則會返回這個錯誤,錯誤的意思是:HTTP頭已經發送出去了,你不能對他再做修改.
為什麼使用緩沖區可以避免這個錯誤呢?
因為header函數是不受緩沖區影響的,當一碰到header函數的時候,PHP馬上執行apache發送這一個http頭都浏覽器.
而輸出的數據PHP打開輸出緩沖區後, 這些數據將會存放在緩沖區,等待輸出.這樣就可以避免了之前所發生的錯誤.
2.通過PHP寫文件下載程序的時候.
為了讓文件下載更安全,同時提高更多的可控性,很多朋友都喜歡用PHP寫文件下載頁面.其原理很簡單,就是通過fwrite把文件內容讀出並顯示,然後通過header來發送HTTP頭,讓浏覽器知道這是一個附件,這樣
就可以達到提供下載的效果.
如果用上面的辦法提供下載頁面,會碰到一個效率問題,如果一個文件很大,假設為100M,那麼在不開啟緩沖區輸出的情況下,必須要把100M數據全部讀出,然後一次返回到頁面上,如果這樣做,用戶將會在所有數據讀完
之後才會得到響應,降低了用戶體驗感.
如果開啟了輸出緩沖區,當PHP程序讀完文件的某一段,然後馬上輸出到apache,然後讓apache馬上返回到浏覽器,這樣就可以減少用戶等待時間.那後面的數據怎麼辦呢?我們可以寫一個while循環,一直一段一段地讀取文件
每讀一段,就馬上輸出,直到把文件全部輸出為止,這樣浏覽器就可以持續地接受到數據,而不必等到所有文件讀取完畢.
另外,該做法還解決了另外一個很嚴重的問題.例如一個文件是100M,如果不開啟緩沖區的情況下,則需要把100M文件全部讀入內存,然後再輸出.但是,如果PHP程序做了內存限制呢?為了保證服務器的穩定,管理員通常會把PHP的執行
內存設一個限制(通過php.ini總的memory_limit, 其默認值是8M), 也就是每個PHP程序使用的內存不能使用超過這個值的內存. 假設該值為8M,而要讀入的文件是100M,根本就沒有足夠的內存來讀入該文件.這個時候,我們就需要用到上面的
辦法來解決這個問題,每次只讀某一段,這樣就可以避免了內存的限制
3.靜態文件緩存
現在很多公司有這麼一個需求, 就是某一個頁面在第一次訪問的時候,會執行PHP,然後把顯示的內容返回到浏覽器,同時需要把這次顯示的內容保存到服務器上,這樣下次訪問的時候,就直接把保存在服務器上的文件直接顯示,而不需要通過PHP來做操作
這就是所謂的”靜態頁面緩存”.那怎麼樣才能做到把內容返回到浏覽器的同時把數據保存到服務器上呢?這就要用到輸出緩沖區了.
ob_start();
echo
'aaa'
;
$string
=
ob_get_contents();
file_put_contents
(
'a.html'
,
$string
);
ob_flush();
flush
();
2.implicit_flush
該配置直接影響apache的緩沖區,有2種配置參數. on/off
on - 自動刷新apache緩沖區,也就是,當php發送數據到apache的緩沖區的時候,不需要等待其他指令,直接就把輸出返回到浏覽器
off - 不自動刷新apache緩沖區,接受到數據後,等待刷新指令
2.有的浏覽器,如果接受到的字符太少,則不會把數據顯示出來,例如老版的IE(必須要大於256k才顯示).這樣就會造成一個疑問, 明明在php和apache都進行了刷新緩沖區的操作,但是浏覽器就是沒有出現自己想要的數據,也許就是這個原因造成的.所以才測試的時候,可以在輸出數據的後面加上多個空格,以填滿數據,確定不會浏覽器造成這類詭異的問題.
3.有些webserver,他自身的輸出緩沖區會有一些限制,比如nginx,他有一個配置fastcgi_buffer_size 4k, 就是是表明,當自身的輸出緩沖區的內容達到4K才會刷新,所以為了保證內容的數據,可以添加以下代碼,保證內容長度
1 2 3 4 5
echo
str_repeat
(
"
"
,4096);
?>
4.在apache中,如果你開啟了mod_gzip的壓縮模塊,這樣可能會導致你的flush函數刷新不成功,其原因是,mod_gzip有自己的輸出緩沖區,當php執行了flush函數,指示apache刷新輸出緩沖區,但是內容需要壓縮,apache就把內容輸出到自身的mod_gzip模塊,mod_gzip也有自身的輸出 緩沖區,他也不會馬上輸出,所以造成了內容不能馬上輸出.為了改善這個情況,可以關閉mod_gzip模塊,或者在httpd.conf增加以下內容,以禁止壓縮
1
SetEnv no-gzip dont-vary