【PHP8.x】ob_flush関数の使い方

ob_flush関数の使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

ob_flush関数は、PHPの出力バッファリング機能に関連する関数です。PHPスクリプトは通常、echoなどで生成された出力を、すぐにウェブブラウザなどのクライアントに送らず、一時的なメモリ領域である「出力バッファ」に溜め込みます。このバッファリングは、通常ob_start()関数で開始されます。

ob_flush関数は、現在の出力バッファに溜まっている内容を、その一つ外側のバッファ、または最終的な出力先(クライアント)へと送る役割を果たします。しかし、この関数が呼び出されても、現在の出力バッファリング自体は終了しません。バッファはクリアされ、引き続き新しい出力が溜め込まれます。

この機能により、時間のかかる処理の途中で部分的な出力を段階的にクライアントに送信することが可能になります。例えば、処理の進捗状況をリアルタイムでユーザーに表示したい場合や、大きなデータセットを少しずつ転送して体感的な応答性を向上させたい場合などに利用されます。ob_flush関数を効果的に使用するためには、事前にob_start()関数で出力バッファリングが有効になっている必要があります。これにより、プログラムの柔軟な出力制御が可能になります。

構文(syntax)

1<?php
2ob_start();
3echo "Hello, world!";
4ob_flush();
5?>

引数(parameters)

引数なし

引数はありません

戻り値(return)

戻り値なし

戻り値はありません

サンプルコード

PHP ob_flush でAJAX進捗表示

1<?php
2
3// HTTPヘッダーを設定し、クライアントへの応答を即座に送信するように指示
4// Content-Typeをtext/plainにすることで、プレーンテキストとして扱われます
5header('Content-Type: text/plain');
6// 一部のWebサーバー(Nginxなど)が応答をバッファリングしないように設定
7// これがないと、ob_flushが意図した通りに動作しない場合があります
8header('X-Accel-Buffering: no');
9
10// 出力バッファリングを開始します
11// これにより、echoなどで出力された内容はすぐにクライアントに送信されず、一旦PHPの内部バッファに蓄えられます
12ob_start();
13
14echo "処理を開始します...\n";
15// PHPの出力バッファの内容をシステムバッファにフラッシュ(出力)します
16ob_flush();
17// システムバッファの内容をクライアントにフラッシュ(送信)します
18flush();
19
20// 擬似的な時間のかかる処理をループで表現します
21for ($i = 1; $i <= 5; $i++) {
22    // 処理の進行状況を示すメッセージを出力します
23    echo "処理の進捗: " . ($i * 20) . "%完了しました。\n";
24
25    // PHPの出力バッファをフラッシュし、クライアントにメッセージを送信します
26    ob_flush();
27    flush();
28
29    // 処理に時間がかかっていることをシミュレートするため、1秒間スクリプトの実行を停止します
30    sleep(1);
31}
32
33echo "すべての処理が完了しました。\n";
34
35// 出力バッファリングを終了し、残りのバッファ内容をすべて出力します
36ob_end_flush();
37
38?>

ob_flush関数は、PHPの出力バッファに蓄えられた内容を、一つ上の層のバッファ(例えばウェブサーバーのバッファなど)に「フラッシュ」(送り出す)する役割を持つ関数です。この関数には引数がなく、特定の値を返すこともありません。

通常、PHPスクリプトからの出力は、処理がすべて完了してからまとめてクライアント(ブラウザなど)に送信されます。しかし、ob_start()で出力バッファリングを開始し、処理の途中でob_flush()flush()を組み合わせることで、逐次的に情報をクライアントへ送ることが可能になります。

このサンプルコードは、時間のかかる処理の進捗状況をリアルタイムにクライアントへ表示する例です。まず、ob_start()で出力バッファリングを開始し、echoで出力された内容がすぐに送信されないようにします。次に、echoでメッセージを出力するたびに、ob_flush()でPHP内部のバッファを上位のバッファへ、そしてflush()でその内容を最終的にクライアントへ送信します。これにより、例えばAjaxで利用する場合、ユーザーは処理の完了を待つことなく、進捗状況を段階的に確認できます。ループ内でsleep(1)を使って処理の遅延をシミュレートし、各段階で進捗メッセージが順次表示される様子を示しています。ob_end_flush()は、バッファリングを終了し、残りのすべての出力内容を送信します。コード冒頭のheader設定は、ウェブサーバーによるバッファリングを防ぎ、逐次出力が正しく機能するために重要です。

ob_flushはPHPの出力バッファをフラッシュする関数ですが、WebサーバーやOSのバッファに送るためには、多くの場合flush()関数と組み合わせて使用します。これらを使っても、NginxなどのWebサーバーやプロキシサーバーがレスポンスをバッファリングしていると、リアルタイムな出力が実現できないことがあります。その際はheader('X-Accel-Buffering: no');のようなヘッダー設定や、サーバー側の設定変更も検討してください。また、ob_flushob_start()で出力バッファリングが開始されている場合にのみ機能しますので、開始と終了(ob_end_flush()など)のペアを忘れないようにしましょう。Ajaxなどで部分的にデータを送る際は、クライアント側もそれに対応した受信処理が必要です。

PHP ob_flush() の挙動と flush() での表示

1<?php
2
3/**
4 * PHPの出力バッファリングと ob_flush, flush 関数の連携をデモンストレーションします。
5 * ob_flush() 単体ではブラウザに即座に出力されない("not working"と感じる)理由を理解し、
6 * flush() と組み合わせて利用する方法を示します。
7 *
8 * このスクリプトをWebサーバー経由で実行し、ブラウザで挙動を確認してください。
9 * 数秒ごとに内容が順次表示されるはずです。
10 */
11function demonstrateObFlushBehavior(): void
12{
13    // 出力バッファリングを開始します。
14    // これ以降の echo 等の出力は、直接クライアント(ブラウザ)には送られず、
15    // PHPの内部バッファに一時的に保持されます。
16    ob_start();
17
18    echo "<h1>PHP 出力バッファリングのデモンストレーション</h1>\n";
19    echo "<p>これは最初のメッセージです。</p>\n";
20    echo "<p>ob_flush() を呼び出します...</p>\n";
21
22    // ob_flush() は、現在の出力バッファの内容をPHPの内部出力メカニズムに転送します。
23    // しかし、この時点ではWebサーバーやブラウザのバッファリングにより、
24    // まだクライアント(ブラウザ)にはデータが送信されないことがほとんどです。
25    ob_flush();
26    // HTMLコメントとして、この時点での状況を説明します。
27    echo "<!-- ob_flush() は実行されましたが、まだブラウザには何も表示されないはずです。 -->\n";
28
29    // 処理を一時停止し、時間差がどのように見えるかを確認しやすくします。
30    sleep(2);
31
32    echo "<p>flush() を呼び出します...</p>\n";
33    // flush() は、PHPの内部出力メカニズムに転送された内容を、
34    // 実際にクライアント(ブラウザ)へ送信するよう指示します。
35    // ここで初めて、ob_flush() で転送された内容がブラウザに表示される可能性が高まります。
36    flush();
37    echo "<!-- flush() が実行され、最初のメッセージがブラウザに表示されたはずです。 -->\n";
38
39    // さらに処理を一時停止します。
40    sleep(2);
41
42    echo "<p>これは2番目のメッセージです。</p>\n";
43    echo "<p>再度 ob_flush() を呼び出します...</p>\n";
44    ob_flush();
45    echo "<!-- 再度 ob_flush() は実行されましたが、まだブラウザには何も表示されないはずです。 -->\n";
46
47    sleep(2);
48
49    echo "<p>再度 flush() を呼び出します...</p>\n";
50    flush();
51    echo "<!-- 再度 flush() が実行され、2番目のメッセージがブラウザに表示されたはずです。 -->\n";
52
53    // 出力バッファリングを終了します。
54    // ob_end_flush() は、残りのバッファ内容があればそれを転送し、バッファを閉じます。
55    // (この例では、すでに flush() されているため、残りの内容はほとんどないはずです。)
56    ob_end_flush();
57
58    echo "<p>全ての処理が完了しました。</p>\n";
59}
60
61// デモンストレーション関数を実行します。
62demonstrateObFlushBehavior();
63
64?>

PHPのob_flush関数は、PHPの出力バッファリングを制御する機能の一つです。この関数は、現在アクティブな出力バッファに蓄積された内容を、PHPの内部出力メカニズムへと転送します。引数はなく、戻り値もありません。

多くのWebサーバーやブラウザは、PHPから送られてきたデータをさらに内部でバッファリングするため、ob_flush()を実行しただけでは、その内容がすぐにブラウザに表示されないことがよくあります。これが「ob_flush()が機能しない」と感じられる主な理由です。

ob_flush()でPHPの内部メカニズムに転送された内容を、実際にクライアント(ブラウザ)へ送信させたい場合は、flush()関数と組み合わせて使用します。flush()は、PHPの内部出力メカニズムに転送された内容を、OSやWebサーバーを通じてブラウザに送信するよう指示する役割を担います。このように、ob_flush()flush()を組み合わせることで、長い処理の途中でも段階的に情報をユーザーに表示することが可能になります。

ob_flush()は、PHPの出力バッファにある内容を、その次の層のバッファ(Webサーバーなど)に転送するだけの機能です。そのため、ob_flush()を呼び出しただけでは、ブラウザに即座に表示されないことが多く、「ob_flushが動かない」と誤解しやすい点に注意が必要です。ブラウザに内容を表示させるには、通常flush()関数も組み合わせて使用し、Webサーバーなどのバッファも解放するよう指示する必要があります。この二段階の出力メカニズムを理解することが重要です。ただし、Webサーバーやプロキシ、あるいはブラウザ自体のバッファリング設定によっては、flush()を呼び出しても即座に表示されない場合があることも覚えておいてください。出力バッファリングは必ずob_start()で開始し、処理の最後にはob_end_flush()などで終了させるようにしてください。

ob_flush()flush() で逐次出力を実現する

1<?php
2
3/**
4 * ob_flush() と flush() を使って逐次的に出力をブラウザに送信するサンプルです。
5 *
6 * 「ob_flush() が効かない」という問題は、多くの場合 flush() を併用していないことが原因です。
7 * ob_flush() はPHPの内部バッファをWebサーバーに送信するだけで、
8 * Webサーバーがその内容をすぐにブラウザに送信するとは限りません。
9 * flush() を呼び出すことで、Webサーバーにバッファをクライアント(ブラウザ)に
10 * 送信するように促します。
11 *
12 * 注意: Webサーバーやプロキシの設定、PHPの 'zlib.output_compression' などが
13 * 有効になっている場合、このコードは期待通りに動作しないことがあります。
14 */
15function progressiveOutputExample(): void
16{
17    // 予期しない出力を防ぐため、既存のバッファをクリア
18    if (ob_get_level() > 0) {
19        ob_end_clean();
20    }
21
22    // 出力バッファリングを開始
23    ob_start();
24
25    // ブラウザがコンテンツをバッファリングしないようにヘッダーを設定
26    header('Content-Type: text/plain; charset=utf-8');
27    header('X-Content-Type-Options: nosniff');
28
29    echo "処理を開始します。\n";
30    // 最初のメッセージをすぐにブラウザへ送信
31    ob_flush();
32    flush();
33    
34    // 時間のかかる処理をシミュレート
35    for ($i = 1; $i <= 5; $i++) {
36        sleep(1); // 1秒待機
37        echo "ステップ {$i} が完了しました。\n";
38        
39        // バッファの内容を強制的にクライアントに送信
40        ob_flush(); // PHPのバッファをWebサーバーへ送信
41        flush();    // Webサーバーのバッファをブラウザへ送信
42    }
43    
44    echo "すべての処理が完了しました。\n";
45    
46    // 出力バッファリングを終了し、残りの内容を送信
47    ob_end_flush();
48}
49
50progressiveOutputExample();
51

ob_flush()関数は、PHPの出力バッファリング機能の一部で、ob_start()関数で開始された出力バッファに蓄積されている内容をWebサーバーへ送信する役割を持ちます。この関数は引数を受け取らず、戻り値もありません。

一般的に「ob_flush()が効かない」と感じられる場合、それはWebサーバー側のバッファリングが原因です。ob_flush()はPHPの内部バッファをWebサーバーに渡すだけで、Webサーバーがその内容をすぐにブラウザへ送信するとは限りません。そのため、ブラウザへの即時出力を促すには、ob_flush()flush()を併用する必要があります。flush()はWebサーバーに、現在持っているバッファの内容をクライアント(ブラウザ)に送信するように促す関数です。

サンプルコードでは、ob_start()で出力バッファリングを開始し、echoで出力したテキストをob_flush()でPHPのバッファからWebサーバーへ送り、その後flush()でWebサーバーのバッファをブラウザへ送信するという一連の流れを示しています。sleep()関数を使うことで、処理に時間がかかっている様子を模擬し、逐次的な出力の効果を分かりやすくしています。処理の終了時にはob_end_flush()を呼び出し、バッファリングを終了するとともに、残りの内容を送信します。ただし、Webサーバーやプロキシの設定、PHPのzlib.output_compressionなどの要因によって、このコードが常に期待通りに動作しない場合がある点に留意が必要です。

ob_flush()はPHPの内部バッファをWebサーバーに送信する関数です。しかし、これだけではブラウザにすぐ表示されないことが多く、Webサーバーも独自のバッファを持つため、flush()を呼び出してサーバーからブラウザへの送信を促す必要があります。「ob_flush()が効かない」と感じる場合、このflush()の呼び出し忘れが主な原因です。この2つの関数は基本的にセットで使います。また、Webサーバーやプロキシの設定、PHPのzlib.output_compressionなどが有効だと、出力がバッファリングされて意図通りに逐次表示されない場合があります。コードが正しくても動作しないときは、サーバー環境の設定も見直してみてください。

関連コンテンツ

【PHP8.x】ob_flush関数の使い方 | いっしー@Webエンジニア