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

作成日: 更新日:

flush関数は、PHPの出力バッファに蓄えられた内容を強制的にクライアント(ウェブブラウザなど)へ送出する命令を実行する関数です。PHPスクリプトは、生成された出力(HTMLやテキストデータなど)をウェブサーバへ送る前に、内部的な出力バッファに一時的に蓄えます。これは、データの送受信をまとめて行うことで処理の効率を高めるためです。しかし、長時間かかる処理中にユーザーに進捗状況を伝えたい場合など、スクリプトの実行が完了する前に一部のデータを送りたい状況があります。flush関数を呼び出すことで、この内部バッファに溜まっているデータが直ちにウェブサーバへ送られ、さらにそこからクライアントへ送信されるように促されます。

この機能は、処理に時間がかかる場合にプログレスバーを表示するなど、リアルタイムに近いユーザーフィードバックを提供したい場合に特に役立ちます。ただし、flush関数を呼び出しても、ウェブサーバやブラウザのバッファリング機構により、データが即座にユーザーのブラウザに表示されない場合があります。特に、ウェブサーバで出力圧縮(gzipなど)が有効になっている場合は、圧縮処理のためにデータがさらにバッファリングされる可能性がある点に注意が必要です。PHPの出力バッファリングをより細かく制御するには、ob_start()ob_end_flush()といった関連する出力制御関数と組み合わせて使用することが一般的です。

基本的な使い方

構文(syntax)

<?php

flush();

?>

引数(parameters)

引数なし

引数はありません

戻り値(return)

void

flush関数は、PHPスクリプトの実行中にバッファリングされている出力を即座にブラウザなどのクライアントに送信します。戻り値はありません。

サンプルコード

PHPのob_flushとflushの違いを理解する

<?php

/**
 * このスクリプトは、PHPの出力バッファリング (`ob_flush`) と
 * ウェブサーバーへの出力 (`flush`) の違いをデモンストレーションします。
 *
 * 【重要】
 * Webブラウザでリアルタイムな段階的出力を確認するには、以下の点に注意してください。
 * 1. Webサーバー (例: Apache, Nginx) のバッファリング設定を無効にするか、
 *    `Transfer-Encoding: chunked` をサポートするよう設定されている必要があります。
 *    多くのWebサーバーはデフォルトでバッファリングを行います。
 * 2. ブラウザ自体も受信したコンテンツをバッファリングすることがあります。
 *    これはブラウザの種類や設定に依存します。
 * 3. CLI (コマンドラインインターフェース) で実行すると、通常はバッファリングの影響を受けにくく、
 *    より直接的に出力の変化を確認できます。
 */

// 出力バッファリングを開始します。
// これ以降の echo は、直接クライアントに送られず、PHPの内部バッファに蓄積されます。
ob_start();

echo "Step 1: この行はまだブラウザに送信されません。<br>\n";

// ob_flush(): 現在の出力バッファ (ob_start() で開始したもの) の内容を、
// 次の上位のバッファ (またはPHPのメイン出力ストリーム) へフラッシュします。
// この時点では、まだWebサーバーのバッファに留まっている可能性があり、
// 通常、ブラウザには届きません。バッファ自体はクリアされますが、停止はしません。
ob_flush();

echo "Step 2: ob_flush() の後、この行が現在のバッファに追加されました。<br>\n";

// flush(): PHPのすべての出力バッファ (ob_flush() によって上位に送られた内容も含む)
// の内容を、Webサーバーのバッファからクライアントへ強制的に送信しようと試みます。
// ここで初めて、Step 1 と Step 2 の内容がブラウザに表示され始める可能性があります。
flush();

// ブラウザでの表示を確認しやすくするために一時停止します。
sleep(2);

echo "Step 3: flush() の後、さらにこの行を追加しました。<br>\n";

// 再度 flush() を呼び出し、Step 3 の内容もブラウザへ送信を試みます。
flush();

// ob_end_flush(): 現在の出力バッファを終了し、残っている内容をフラッシュします。
// これがないと、スクリプトの最後まで出力はバッファに残り、
// スクリプト終了時にまとめて出力される可能性があります。
ob_end_flush();

// --- キーワード 'fflush' についての補足説明 ---
// flush() と ob_flush() はHTTPレスポンスの出力バッファリングに関連するPHP関数です。
// 一方、fflush() は、C標準ライブラリに由来する関数で、PHPではファイルストリーム (例: fopen() で開いたファイル)
// の内部バッファをディスクやネットワークなどの物理メディアへ書き出すために使用されます。
// 例えば、fwrite() でファイルに書き込んだ後、fflush($file_pointer) を呼び出すことで、
// バッファリングされたデータが確実にファイルに書き込まれます。
// これはWeb出力バッファとは用途が異なるため、直接的な比較対象ではありません。

?>

PHP 8のflush関数は、引数を取らず、戻り値もありません(void)。この関数は、PHPがこれまでに生成したすべての出力(echoなどで出力された内容)を、Webサーバーのバッファからクライアント(通常はWebブラウザ)へ強制的に送信しようと試みます。

サンプルコードでは、まずob_start()でPHPの出力バッファリングを開始します。これにより、echoされた内容は直接クライアントに送られず、PHP内部のバッファに一時的に蓄積されます。 次にob_flush()を呼び出すと、現在のアクティブな出力バッファの内容がPHPの次の上位バッファ、またはPHPのメイン出力ストリームへ移動します。しかし、この時点ではまだWebサーバーのバッファに留まることが多く、ブラウザには表示されません。 その後、flush()を呼び出すと、PHPのすべての出力バッファの内容がWebサーバーのバッファからクライアントへ送られ、ブラウザに表示され始める可能性があります。スクリプトの最後にob_end_flush()は、出力バッファリングを終了し、残りの内容をフラッシュします。

なお、Webサーバーやブラウザがコンテンツをバッファリングする場合があるため、flush()を呼び出してもリアルタイムに表示されないことがあります。コマンドラインインターフェース(CLI)で実行すると、より直接的な出力を確認できます。

また、キーワードにあったfflush()は、C標準ライブラリ由来の関数で、PHPではfopen()で開いたファイルストリームの内部バッファをディスクなどの物理メディアへ書き出すために使用され、Web出力バッファとは用途が異なります。

PHPのflush()はウェブサーバーへの出力バッファを、ob_flush()はPHPの内部バッファを上位にフラッシュする機能です。一方、fflush()はファイルストリームのバッファを物理メディアに書き出す関数であり、用途が異なりますので混同しないよう注意が必要です。flush()を呼び出しても、Webサーバーやブラウザがさらにバッファリングを行う場合があるため、すぐにブラウザに表示されないことがあります。リアルタイムな段階的出力を確認するには、Webサーバーの設定調整が必要な場合があります。コマンドラインインターフェース(CLI)で実行すると、これらのバッファリングの影響を受けにくく、より直接的に動作を確認できます。出力バッファリングを適切に利用するには、ob_start()ob_end_flush()を組み合わせて使用することが基本となります。

PHP flush()で段階表示する

<?php

/**
 * PHPのflush()関数の動作と、出力がすぐに表示されない一般的な問題
 * (通称「php flush not working」)に対処する方法を示します。
 *
 * flush()関数は、現在の出力バッファの内容をWebサーバーに送信しますが、
 * ブラウザに即座に表示されるためには、PHPのバッファリング(ob_start()など)と
 * Webサーバー(Apache, Nginxなど)のバッファリングの両方を適切に制御する必要があります。
 * この例では、これらのバッファリングを制御し、段階的に内容が表示されるようにします。
 */
function demonstrateFlushBehavior(): void
{
    // Webブラウザがコンテンツをすぐにレンダリングできるように、
    // 適切なContent-Typeヘッダーとキャッシュ無効化ヘッダーを設定します。
    header('Content-Type: text/html; charset=utf-8');
    // キャッシュを無効にし、ブラウザやプロキシによるバッファリングを防ぎます。
    header('Cache-Control: no-cache, no-store, must-revalidate');
    header('Pragma: no-cache');
    header('Expires: 0');

    echo '<!DOCTYPE html>';
    echo '<html>';
    echo '<head>';
    echo '<title>PHP flush() Example</title>';
    echo '</head>';
    echo '<body>';
    echo '<h1>PHP flush() 関数デモンストレーション</h1>';

    // PHPの出力バッファリングを開始します。
    // これにより、echoなどで出力された内容はすぐに送信されず、
    // PHP内部のバッファに蓄えられます。
    ob_start();

    echo '<p>ステップ1: この行はすぐに表示されるはずです。</p>' . PHP_EOL;
    // PHPの出力バッファの内容をWebサーバーのバッファへ送信します。
    ob_flush();
    // Webサーバーのバッファをクライアント(ブラウザ)へ送信します。
    // ブラウザはこの時点で受け取った内容を表示しようとします。
    flush();

    // 処理を一時停止し、ブラウザが前の内容をレンダリングする時間を与えます。
    sleep(2);

    echo '<p>ステップ2: 2秒後にこの行が表示されるはずです。</p>' . PHP_EOL;
    ob_flush();
    flush();

    sleep(2);

    echo '<p>ステップ3: さらに2秒後にこの行が表示されるはずです。</p>' . PHP_EOL;
    ob_flush();
    flush();

    sleep(2);

    echo '<p>完了しました。</p>' . PHP_EOL;
    ob_flush();
    flush();

    echo '</body>';
    echo '</html>';

    // スクリプトの最後に残っているPHP出力バッファの内容をすべてフラッシュし、
    // バッファリングを終了します。
    ob_end_flush();
}

// デモンストレーション関数の実行
demonstrateFlushBehavior();

PHPのflush()関数は、Webサーバーの出力バッファに蓄えられた内容を、直ちにクライアント(Webブラウザなど)へ送信する役割を持つ関数です。この関数は引数を取らず、戻り値もありません。通常、PHPスクリプトからの出力はすべての処理が完了してからまとめて送信されますが、flush()を使用することで、処理の途中で段階的に内容を送信できます。

しかし、「php flush not working」と呼ばれる現象のように、flush()を呼び出してもすぐにWebブラウザに内容が表示されないことがあります。これは、flush()関数単体では、PHP自身の出力バッファ、Webサーバー(Apache, Nginxなど)のバッファ、さらにはブラウザ側のバッファリングが介在するためです。この問題を解決し、flush()を効果的に機能させるには、PHPの出力バッファリングを適切に制御する必要があります。具体的には、ob_start()でバッファリングを開始し、echoなどで出力された内容をPHP内部のバッファに蓄えます。そして、ob_flush()でPHPバッファの内容をWebサーバーに送り、その後にflush()を呼び出すことでWebサーバーからクライアントへ強制的に送信します。さらに、header()関数でキャッシュを無効にする設定も重要です。

サンプルコードでは、これらのテクニックを組み合わせて使用しています。header()でキャッシュを無効化し、ob_start()ob_flush()、そしてflush()を組み合わせて、sleep()関数で一時停止を入れながら、コンテンツが時間差で段階的にWebブラウザに表示される様子をデモンストレーションしています。これにより、処理の進行状況をリアルタイムでユーザーに伝えることが可能となります。

flush()関数は、PHPの出力バッファの内容をWebサーバーへ送信する機能ですが、ブラウザに即座に表示されないことがあります。これは、PHPの出力バッファリングに加え、Webサーバー、プロキシ、ブラウザ側でもバッファリングが行われるためです。

サンプルコードのように、ob_start()でPHPのバッファリングを開始し、ob_flush()でPHPバッファをWebサーバーに送り、その後にflush()でWebサーバーのバッファをクライアントへ送るという連携が重要です。また、header()関数でキャッシュ制御を適切に行い、ブラウザやプロキシによるバッファリングを防ぐことも、即時表示のための重要なポイントです。

sleep()関数は、デモンストレーションのために処理を一時停止させていますが、実運用ではユーザー体験を損ねるため、特別な要件がない限り使用は推奨されません。多層的なバッファリングの仕組みを理解し、適切に制御することが、flush()を効果的に利用する鍵となります。

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