當前位置:首頁 > PHP教程 > php應用 > 列表

php.ini中output_buffering詳解

發布:smiling 來源: PHP粉絲網  添加日期:2014-07-24 14:28:20 瀏覽: 評論:0 

php output_buffering

默認情況下,php buffer是開啟的,而且該buffer默認值是4096,即4kb,你可以通過在php.ini配置文件中找到output_buffering配置,當echo,print等輸出用戶數據的時候,輸出數據都會寫入到php output_buffering中,直到output_buffering寫滿,會將這些數據通過tcp傳送給瀏覽器顯示,你也可以通過ob_start()手動激活php output_buffering機制,使得即便輸出超過了4kb數據,也不真的把數據交給tcp傳給瀏覽器,因為ob_start()將php buffer空間設置到了足夠大,只有直到腳本結束,或者調用ob_end_flush函數,才會把數據發送給客戶端瀏覽器.

1.當output_buffering=4096,并且輸出較少數據(少于一個buffer),代碼如下:

  1. <?php 
  2. for ($i = 0; $i < 10; $i++) { 
  3.     echo $i . '<br/>'
  4.     sleep($i + 1); // 
  5. ?> 

現象:不是每隔幾秒就會有間斷性輸出,而是直到響應結束,才能看一次性看到輸出,在等待服務器腳本處理結束之前,瀏覽器界面一直保持空白,這是因為,數據量太小,php output_buffering沒有寫滿,寫數據的順序,依次是echo->php buffer->tcp buffer->browser

2.當output_buffering=0,并且輸出較少數據(少于一個buffer),代碼如下:

  1. <?php 
  2. //通過ini_set('output_buffering', 0)并不生效 
  3. //應該編輯/etc/php.ini,設置output_buffering=0禁用output buffering機制 
  4. //ini_set('output_buffering', 0); //徹底禁用output buffering功能 
  5. for ($i = 0; $i < 10; $i++) { 
  6.     echo $i . '<br/>'
  7.     flush();  //通知操作系統底層,盡快把數據給客戶端瀏覽器 
  8.     sleep($i + 1); // 
  9. ?> 

現象:與剛才顯示并不一致,禁用了php buffering機制之后,在瀏覽器可以斷斷續續看到間斷性輸出,不必等到腳本執行完畢才看到輸出,這是因為,數據沒有在php output_buffering中停留,寫數據的順序依次是echo->tcp buffer->browser

3.當output_buffering=4096.,輸出數據大于一個buffer,不調用ob_start(),代碼如下:

  1. #//創建一個4kb大小的文件 
  2. $dd if=/dev/zero of=f4096 bs=4096 count=1 
  3. <?php 
  4. for ($i = 0; $i < 10; $i++) { 
  5.     echo file_get_contents('./f4096') . $i . '<br/>'
  6.     sleep($i +1); 
  7. ?>  

現象:響應還沒結束(http連接沒有關閉),斷斷續續可以看到間斷性輸出,瀏覽器界面不會一直保持空白,盡管啟用了php output_buffering機制,但依然會間斷性輸出,而不是一次性輸出,是因為output_buffering空間不夠用,每寫滿一個php buffering,數據就會發送到客戶端瀏覽器.

4.當output_buffering=4096,輸出數據大于一個tcp buffer,調用ob_start(),代碼如下 :

  1. <?php 
  2. ob_start(); //開啟php buffer 
  3. for ($i = 0; $i < 10; $i++) { 
  4.     echo file_get_contents('./f4096') . $i . '<br/>'
  5.     sleep($i + 1); 
  6. ob_end_flush(); 
  7. ?> 

現象:直到服務端腳本處理完成,響應結束,才看到完整輸,輸出間隔時間很短,以至你感受不到停頓,在輸出之前,瀏覽器一直保持著空白界面,等待服務端數據,這是因為,php一旦調用了ob_start()函數,它會將php buffer擴展到足夠大,直到ob_end_flush函數調用或者腳本運行結速才發送php buffer中的數據到客戶端瀏覽器.

tcpdump觀察

在這里,我們通過tcpdump監控一下tcp報文,來觀察一下使用ob_start()和沒有使用它的一個區別.

1.沒有使用ob_start()

  1. 12:30:21.499528 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . ack 485 win 6432 
  2. 12:30:21.500127 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 1:2921(2920) ack 485 win 6432 
  3. 12:30:21.501000 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 2921:7301(4380) ack 485 win 6432 
  4. 12:30:21.501868 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 7301:8412(1111) ack 485 win 643 
  5. 12:30:24.502340 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 8412:14252(5840) ack 485 win 6432 
  6. 12:30:24.503214 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 14252:15712(1460) ack 485 win 6432 
  7. 12:30:24.503217 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 15712:16624(912) ack 485 win 6432 
  8.  
  9. 12:30:31.505934 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 16624:23924(7300) ack 485 win 6432 
  10. 12:30:31.506839 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 23924:24836(912) ack 485 win 6432 
  11. 12:30:42.508871 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 24836:32136(7300) ack 485 win 6432 
  12. 12:30:42.509744 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 32136:33048(912) ack 485 win 6432 
  13. 12:30:57.512137 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . 33048:40348(7300) ack 485 win 6432 
  14. 12:30:57.513016 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 40348:41260(912) ack 485 win 6432 
  15. 12:31:06.513912 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: P 41260:41265(5) ack 485 win 6432 
  16. 12:31:06.514012 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: F 41265:41265(0) ack 485 win 6432 
  17. 12:31:06.514361 IP 192.168.0.8.webcache > 192.168.0.28.cymtec-port: . ack 486 win 6432 

 

2.使用了ob_start()
  1. 12:36:06.542244 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . ack 485 win 6432 
  2. 12:36:51.559128 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 1:2921(2920) ack 485 win 6432 
  3. 12:36:51.559996 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 2921:7301(4380) ack 485 win 6432 
  4. 12:36:51.560866 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 7301:11681(4380) ack 485 win 6432 
  5. 12:36:51.561612 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 11681:16061(4380) ack 485 win 6432 
  6. 12:36:51.561852 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 16061:20441(4380) ack 485 win 6432 
  7. 12:36:51.562479 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 20441:24821(4380) ack 485 win 6432 
  8. 12:36:51.562743 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 24821:29201(4380) ack 485 win 6432 
  9. 12:36:51.562996 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 29201:33581(4380) ack 485 win 6432 
  10. 12:36:51.563344 IP 192.168.0.8.webcache > 192.168.0.28.noagent: P 33581:35041(1460) ack 485 win 6432 
  11. 12:36:51.563514 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 35041:36501(1460) ack 485 win 6432 
  12. 12:36:51.563518 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 36501:37961(1460) ack 485 win 6432 
  13. 12:36:51.563523 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 37961:39421(1460) ack 485 win 6432 
  14. 12:36:51.563526 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . 39421:40881(1460) ack 485 win 6432 
  15. 12:36:51.563529 IP 192.168.0.8.webcache > 192.168.0.28.noagent: FP 40881:41233(352) ack 485 win 6432 
  16. 12:36:51.570364 IP 192.168.0.8.webcache > 192.168.0.28.noagent: . ack 486 win 6432 

通過上面的對比,我們可以看到,數據報文的時間間隔明顯不一樣,沒有使用ob_start(),時間間隔比較大,等待4秒左右就把tcp buffer中的數據發送出去了。數據沒有在php buffer中逗留過長時間,就將輸出數據發送給了客戶端瀏覽器。這是因為,很快php buffer就被寫滿了,不得不把數據發送出去。而啟用了ob_start(),則不同,發送數據包給客戶端,幾乎是同一時間發出去的。這就可以推斷,數據一直在php buffer中逗留,直到調用了ob_end_flush()才把php buffer中的數據發送給客戶端瀏覽器。

output buffering函數

1.ob_start

激活output_buffering機制。一旦激活,腳本輸出不再直接出給瀏覽器,而是先暫時寫入php buffer內存區域。

php默認開啟output_buffering機制,只不過,通過調用ob_start()函數據output_buffering值擴展到足夠大。也可以指定$chunk_size來指定output_buffering的值。$chunk_size默認值是0,表示直到腳本運行結束,php buffer中的數據才會發送到瀏覽器。如果你設置了$chunk_size的大小,則表示只要buffer中數據長度達到了該值,就會將buffer中的數據發送給瀏覽器。

當然,你可以通過指定$ouput_callback,來處理buffer中的數據。比如函數ob_gzhandler,將buffer中的數據壓縮后再傳送給瀏覽器。

2.ob_get_contents

獲取一份php buffer中的數據拷貝。值得注意的是,你應該在ob_end_clean()函數調用這調用該函數,否則ob_get_contents()返回一個空字符中。

3.ob_end_flush與ob_end_clean

這二個函數有點相似,都會關閉ouptu_buffering機制。但不同的是,ob_end_flush只是把php buffer中的數據沖(flush/send)到客戶端瀏覽器,而ob_clean_clean將php bufeer中的數據清空(erase),但不發送給客戶端瀏覽器。ob_end_flush調用之后,php buffer中的數據依然存在,ob_get_contents()依然可以獲取php buffer中的數據拷貝。而ob_end_clean()調用之后ob_get_contents()取到的是空字符串,同時瀏覽器也接收不到輸出,即沒有任何輸出。

慣用案例:常常在一些模板引擎和頁面文件緩存中看到ob_start()使用。在知名開源項目wordpress,drupal,smarty等地方,都能夠發現他們的蹤影子。這里抽出drupal的應用。

#模板文件代碼如下:

  1. //@file:user-profile.tpl.php 
  2. <div> 
  3.      <ul> 
  4.           <li>username: <?php echo $user->name; ?></li> 
  5.           <li>picture:<?php echo $user->picture; ?></li> 
  6.      </ul> 
  7. </div> 
  8.  
  9. //@file:template-render.php 
  10. <?php 
  11. function theme_render_template($template_file$variables) { 
  12.   if (!is_file($template_file) { return ""; } 
  13.   extract($variables, EXTR_SKIP); 
  14.   ob_start(); 
  15.   $contents = ob_get_contents(); 
  16.   ob_end_clean(); 
  17.   return $contents
  18. ?> 
  19.  
  20. //@file:profile.php 
  21. <?php 
  22. $variables = array('user' => $user); 
  23. print theme_render_template('user-profile.tpl.php'$variables); 
  24. ?> 

最后總結:

ob_flush/flush在手冊中的描述, 都是刷新輸出緩沖區, 并且還需要配套使用, 所以會導致很多人迷惑…其實,他們倆的操作對象不同,有些情況下,flush根本不做什么事情..

ob_*系列函數, 是操作PHP本身的輸出緩沖區.

所以, ob_flush是刷新PHP自身的緩沖區.

而flush, 嚴格來講, 這個只有在PHP做為apache的Module(handler或者filter)安裝的時候, 才有實際作用. 它是刷新WebServer(可以認為特指apache)的緩沖區.

在apache module的sapi下, flush會通過調用sapi_module的flush成員函數指針, 間接的調用apache的api: ap_rflush刷新apache的輸出緩沖區, 當然手冊中也說了, 有一些apache的其他模塊, 可能會改變這個動作的結果..

1.有些Apache的模塊,比如mod_gzip,可能自己進行輸出緩存,

2.這將導致flush()函數產生的結果不會立即被發送到客戶端瀏覽器。

4.甚至瀏覽器也會在顯示之前,緩存接收到的內容。例如 Netscape

5.瀏覽器會在接受到換行或 html 標記的開頭之前緩存內容,并且在

6.接受到 </table> 標記之前,不會顯示出整個表格。

8.一些版本的 Microsoft Internet Explorer 只有當接受到的256個

9.字節以后才開始顯示該頁面,所以必須發送一些額外的空格來讓這

10.些瀏覽器顯示頁面內容。

所以, 正確使用倆者的順序是. 先ob_flush, 然后flush,

當然,在其他sapi下,不調用flush也可以,只不過為了保證你代碼的可移植性,建議配套使用.

Tags: php ini output_buffering

分享到:

天气网首页彩吧