1. 程式人生 > >php--->php 緩沖區 buffer 原理

php--->php 緩沖區 buffer 原理

web 字符串 替換 nginx apache 也說 linu 解釋 row

php 緩沖區 buffer 原理

1.緩沖流程
  • 從php腳本echo(print、print_r...)內容之後,是如何顯示給用戶的呢,下面看看流程
echo、print => php output_buffering => webServer buffer => browser buff => browser display
//即:腳本輸出 => php的緩沖區設置 => 系統的緩沖區設置(apache、nginx) => 瀏覽器的緩沖區設置 => 顯示給用戶
2. php buffer
- php運行的結果先放入緩沖區(buffer),只有當緩沖區滿了或者php運行完畢,才將數據輸出去。
- 緩沖區是通過php.ini中的output_buffering變量控制,可以設置大於0的數值來打開buffer。
- ob_start()手動激活php output_buffering機制,使得即便輸出超過了4kb數據,也不把數據交給tcp傳給瀏覽器,因為ob_start()將php buffer空間設置到了足夠大 。只有直到腳本結束,或者調用ob_end_flush函數,才會把數據發送給客戶端瀏覽器。需要註意的是php.ini中php buffer是關閉的,再次調用ob_end_flush()會報warning。
3.webServer buffer
  • 這裏主要講apache和nginx的緩沖區。
    • 1、apache buffer
      • 當php的輸出數據給apache服務器時,它也會做一層buffer(也將數據放入它的緩沖區,當緩沖區數據滿或執行完畢時,才輸出數據)。
      • 若想關閉緩沖區,可以在php層使用flush()來強制將緩沖區數據輸出。
      • fulsh() 的工作原理:在apache module的sapi下, flush會通過調用sapi_module的flush成員函數指針, 間接的調用apache的api: ap_rflush刷新apache的輸出緩沖區, 當然手冊中也說了, 有一些apache的其他模塊, 可能會改變這個動作的結果.例如mod_gzip,可能自己進行輸出緩沖區,這將導致flush()函數產生的結果不會立即被發送到客戶端瀏覽器。
    • 2、nginx buffer
      • nginx使用fastcgi緩沖區來緩沖數據。很遺憾的是,fastcgi是強制將buffer打開的,無法關閉緩沖區。
      • 有人有可能會想,無法關閉可以將buffer設置的足夠小,來使緩沖數據輸出,達到無緩沖的效果。但是這個想法無法實現。
        原因一:fastcgi buffer無法識別小於1k的數值。
        原因二:受參數之間大小關系的影響。
      • 具體可以看看fastcgi的一些buffer設置。
        fastcgi_buffer_size:用來存儲response的header數據。
        fastcgi_buffers:用來存儲response的內容數據.
        fastcgi_busy_buffers_size:用來控制同時傳輸到客戶端的buffer數量。一旦fastcgi_buffers設置的 buffer被寫入,直到buffer裏面的數據被完整的傳輸完(傳輸到客戶端),這些buffer將會一直處在busy狀態,我們不能對這些 buffer進行任何別的操作。所有處在busy狀態的buffer size加起來不能超過fastcgi_busy_buffers_size。
      • 參數之間大小關系:
        fastcgi_busy_buffers_size < (all fastcgi_buffers – one buffer) 並且fastcgi_busy_buffers_size>=max (fastcgi_buffer_size, one fastcgi _buffers)。
        例如,在nginx.conf配置中有:
        fastcgi_buffers 4 128k
        fastcgi_buffer_size 256k
        那麽fastcgi_busy_buffers_size<(4*128k – 4k) 並且fastcgi_busy_buffers_size>=max(256k, 128k)
        其中,4k(one buffer的大小)是linux系統默認的緩存大小,即一個內存頁。
        若fastcgi_buffer_size設置的很小,會導致header過小的錯誤。你也同樣無法保證設置的值會滿足所有的情況。
      • 要註意的是:
        flush, 嚴格來講, 這個只有在PHP做為apache的Module(handler或者filter)安裝的時候, 才有實際作用. 它是刷新WebServer(可以認為特指apache)的緩沖區.所以在nginx下,flush()函數是無法起作用的。
4.browser buffer
  • IE為256Bytes, Chrome與FireFox為1000Bytes,只有輸出數據達到了這個長度或者腳本結束瀏覽器才會將數據輸出在頁面上。
  • 在 php端無法關閉瀏覽器buffer。
    為了使得數據及時輸出,可以在發送真正內容 數據前,發送一些空格來填滿瀏覽器的buffer。
    瀏覽器的buffer一滿,就會將其他新輸出的數據輸出。
    但是不同的瀏覽器會設置不同的buffer大小。
    為了保險期間,可以發送4096個空格,因為目前比較流行的瀏覽器的buffer還沒有超過4k(一個內頁大小)。
5.輸出緩沖區相關函數主要有:

ob_start() - 打開輸出控制緩沖
ob_get_length() - 返回輸出緩沖區的長度
ob_get_level() - 返回輸出緩沖區的嵌套級別
ob_get_status() - 返回輸出緩沖區的狀態(數組形式返回,默認返回最頂層,參數為true時返回所有)
ob_get_contents() - 返回輸出緩沖區的內容
ob_get_clean() - 以字符串格式返回當前輸出緩沖區並關閉輸出緩沖
ob_end_clean() - 清空(擦除)緩沖區並關閉輸出緩沖
ob_get_flush() - 以字符串返回輸出緩沖區內容並關閉緩沖
ob_end_flush() - 沖刷出(送出)輸出緩沖區內容緩沖並關閉輸出緩沖

6.辨析
  • ob_end_flush()與ob_end_clean()區別
    • 這兩個函數都會關閉輸出緩沖。
    • 不同的是,ob_end_flush()只是把PHP緩沖區中的數據發送到客戶端瀏覽器,而ob_clean_clean()將PHP緩沖區中的數據刪除,但不發送給客戶端。ob_end_flush()調用之後,PHP緩沖區中的數據依然存在,ob_get_contents()依然可以獲取PHP緩沖區中的數據拷貝。
  • flush()和ob_flush()
    • 參考:https://www.cnblogs.com/phpper/p/7750104.html
    • 這兩個函數的使用怕是很多人最迷惑的一個問題,手冊上對兩個函數的解釋也語焉不詳,沒有明確的指出它們的區別,似乎二者的功能都是刷新輸出緩存。但在我們文章一開始的代碼中如果講fush()替換成ob_flush(),程序就再不能正確執行了。顯然,它們是有區別的,否則也手冊中直接說明其中一個是另外一個函數的別名即可了,沒必要分別說明。那麽它們的區別到底是什麽呢?
    • 反復研究了手冊的說明,參考了手冊中一些人的留言,自己琢磨應該是這樣的: 在沒有開啟緩存時,腳本輸出的內容都在服務器端處於等待輸出的狀態,flush()可以將等待輸出的內容立即發送到客戶端。 開啟緩存後,腳本輸出的內容存入了輸出緩存中,這時沒有處於等待輸出狀態的內容,你直接使用flush()不會向客戶端發出任何內容。而ob_flush()的作用就是將本來存在輸出緩存中的內容取出來,設置為等待輸出狀態,但不會直接發送到客戶端,這時你就需要先使用ob_flush()再使用flush(),客戶端才能立即獲得腳本的輸出。

php--->php 緩沖區 buffer 原理