ob,輸出緩沖區,是output buffering的簡稱,而不是output cache。ob用對了,是能對速度有一定的幫助,但是盲目的加上ob函數,只會增加CPU額外的負擔
ob的基本原則:如果ob緩存打開,則echo的數據首先放在ob緩存。如果是header信息,直接放在程序緩存。當頁面執行到最後,會把ob緩存的數據放到程序緩存,然後依次返回給浏覽器。 下面我說說ob的基本作用: 1)防止在浏覽器有輸出之後再使用setcookie()、header()或session_start()等發送頭文件的函數造成的錯誤。其實這樣的用法少用為好,養成良好的代碼習慣。 2)捕捉對一些不可獲取的函數的輸出,比如phpinfo()會輸出一大堆的HTML,但是我們無法用一個變量例如$info=phpinfo();來捕捉,這時候ob就管用了。 3)對輸出的內容進行處理,例如進行gzip壓縮,例如進行簡繁轉換,例如進行一些字符串替換。 4)生成靜態文件,其實就是捕捉整頁的輸出,然後存成文件。經常在生成HTML,或者整頁緩存中使用。 對於剛才說的第三點中的GZIP壓縮,可能是很多人想用,卻沒有真用上的,其實稍稍修改下代碼,就可以實現頁面的gzip壓縮。 復制代碼 代碼如下:ob_start(ob_gzhandler); 要緩存的內容 沒錯,加一個ob_gzhandler這個回調函數就可以了,不過這麼做有些小問題,一是需要zlib支持,二是沒有判斷浏覽器是否支持gzip(現在好像都支持,iphone浏覽器好像都支持了)。 以前的做法是判斷一下浏覽器是否支持gzip,然後用第三方的gzip函數來壓縮ob_get_contents() 的內容,最後echo。 一、ob系列函數中常用函數集錦 復制代碼 代碼如下: ob_start(); //打開一個輸出緩沖區,所有的輸出信息不再直接發送到浏覽器,而是保存在輸出緩沖區裡面。 ob_clean(); //刪除內部緩沖區的內容,不關閉緩沖區(不輸出)。 ob_end_clean(); //刪除內部緩沖區的內容,關閉緩沖區(不輸出)。 ob_get_clean(); //返回內部緩沖區的內容,關閉緩沖區。相當於執行 ob_get_contents() and ob_end_clean() ob_flush(); //發送內部緩沖區的內容到浏覽器,刪除緩沖區的內容,不關閉緩沖區。 ob_end_flush(); //發送內部緩沖區的內容到浏覽器,刪除緩沖區的內容,關閉緩沖區。 ob_get_flush(); //返回內部緩沖區的內容,並關閉緩沖區,再釋放緩沖區的內容。相當於ob_end_flush()並返回緩沖區內容。 flush(); //將ob_flush釋放出來的內容,以及不在PHP緩沖區中的內容,全部輸出至浏覽器;刷新內部緩沖區的內容,並輸出。 ob_get_contents(); //返回緩沖區的內容,不輸出。 ob_get_length(); //返回內部緩沖區的長度,如果緩沖區未被激活,該函數返回FALSE。 ob_get_level(); //Return the nesting level of the output buffering mechanism. ob_get_status(); //Get status of output buffers. ob_implicit_flush(); //打開或關閉絕對刷新,默認為關閉,打開後ob_implicit_flush(true),所謂絕對刷新,即當有輸出語句(e.g: echo)被執行時,便把輸出直接發送到浏覽器,而不再需要調用flush()或等到腳本結束時才輸出。 ob_gzhandler //ob_start回調函數,用gzip壓縮緩沖區的內容。 ob_list_handlers //List all output handlers in use output_add_rewrite_var //Add URL rewriter values output_reset_rewrite_vars //Reset URL rewriter values 這些函數的行為受php_ini設置的影響: output_buffering //該值為ON時,將在所有腳本中使用輸出控制;若該值為一個數字,則代表緩沖區的最大字節限制,當緩存內容達到該上限時將會自動向浏覽器輸出當前的緩沖區裡的內容。 output_handler //該選項可將腳本所有的輸出,重定向到一個函數。例如,將 output_handler 設置為 mb_output_handler() 時,字符的編碼將被修改為指定的編碼。設置的任何處理函數,將自動的處理輸出緩沖。 implicit_flush //作用同ob_implicit_flush,默認為Off。 二、實例講解 1、使 header() 函數前可以有echo代碼 Output Control 函數可以讓你自由控制腳本中數據的輸出。它非常地有用,特別是對於:當你想在數據已經輸出後,再輸出文件頭的情況。 輸出控制函數不對使用 header() 或 setcookie(),發送的文件頭信息產生影響,只對那些類似於 echo() 和 PHP 代碼的數據塊有作用。 復制代碼 代碼如下:ob_start(); //打開緩沖區 echo "Hellon"; //輸出 header(“location:index.php”); //把浏覽器重定向到index.php ob_end_flush(); //輸出全部內容到浏覽器 所有對header()函數有了解的人都知道,這個函數會發送一段文件頭給浏覽器,但是如果在使用這個函數之前已經有了任何輸出(包括空輸出,比如空格,回車和換行)就會提示出錯。如果我們去掉第一行的ob_start(),再執行此程序,我們會發現得到了一條錯誤提示:"Header had all ready send by"!但是加上ob_start,就不會提示出錯,原因是當打開了緩沖區,echo後面的字符不會輸出到浏覽器,而是保留在服務器,直到你使用flush或者ob_end_flush才會輸出,所以並不會有任何文件頭輸出的錯誤! 2、保存 phpinfo() 函數的輸出 復制代碼 代碼如下:ob_start(); //打開緩沖區 phpinfo(); //使用phpinfo函數 $info = ob_get_contents(); //得到緩沖區的內容並且賦值給$info $file = fopen('info.txt', 'w'); //打開文件info.txt fwrite($file, $info); //寫入信息到info.txt fclose($file); //關閉文件info.txt 3、靜態模版技術 所謂靜態模版技術就是通過某種方式,使得用戶在client端得到的是由PHP產生的html頁面。如果這個html頁面不會再被更新,那麼當另外的用戶再次浏覽此頁面時,程序將不會再調用PHP以及相關的數據庫,對於某些信息量比較大的網站,例如sina、163、sohu。類似這種的技術帶來的好處是非常巨大的。 復制代碼 代碼如下:ob_start(); //打開緩沖區 php頁面的全部輸出 $content = ob_get_contents(); //取得php頁面輸出的全部內容 $fp = fopen("output00001.html", "w"); //創建一個文件,並打開,准備寫入 fwrite($fp, $content); //把php頁面的內容全部寫入output00001.html,然後…… fclose($fp); 三、輸出緩存句柄ob_gzhandler PHP4.0.4有一個新的輸出緩存句柄ob_gzhandler,它與前面的類相似,但用法不同。使用ob_gzhandler時要在php.ini中加入的內容如下: 代碼如下:output_handler = ob_gzhandler; 這行代碼使得PHP激活輸出緩存,並壓縮它發送出去的所有內容。 如果由於某種原因你不想在php.ini中加上這行代碼,你還可以通過PHP源文件所在目錄的.htaccess文件改變默認的服務器行為(不壓縮),語法如下: 代碼如下:php_value output_handler ob_gzhandler 或者是從PHP代碼調用,如下所示: 代碼如下:ob_start("ob_gzhandler"); 采用輸出緩存句柄的方法確實非常有效,而且不會給服務器帶來什麼特殊的負荷。但必須注意的是,Netscape Communicator對壓縮圖形的支持不佳,因此除非你能夠保證所有用戶都使用IE浏覽器,否則你應該禁止壓縮JPEG和GIF圖形。一般地,對於所有其他文件,這種壓縮都有效,但建議你針對各種浏覽器都分別進行測試,特別是當你使用了特殊的插件或者數據查看器時這一點尤其重要。 注意事項: 1、一些Web服務器的output_buffering默認是4069字符或者更大,即輸出內容必須達到4069字符服務器才會flush刷新輸出緩沖,為了確保flush有效,最好在ob_flush()函數前有以下語句: 代碼如下:print str_repeat("", 4096); //以確保到達output_buffering值 2、ob_* 系列函數是操作PHP本身的輸出緩沖區,所以ob_flush只刷新PHP自身的緩沖區,而flush是刷新apache的緩沖區。所以,正確使用倆者的順序是:先ob_flush,然後flush。ob_flush是把數據從PHP的緩沖中釋放出來,flush是把緩沖內/外的數據全部發送到浏覽器。 3、不要誤認為用了ob_start()後,腳本的echo/print等輸出就永遠不會