web-dev-qa-db-ja.com

PHPで出力バッファリングを無効にする方法

Webカメラに接続してソケットから読み取り、print関数を使用してこのデータを出力する簡単なリレースクリプトを作成しました。データは、境界が既に設定されているMJPGデータです。読み取ったデータを出力するだけです。

問題はPHPはこのデータをバッファリングしているようです。カメラを1 FPSに設定すると、フィードは7〜8秒間フリーズし、すぐに8フレームを表示します。解像度を設定すると巨大なサイズにすると、カメラは毎秒1フレーム程度移動します。その後、バッファリングが行われていると仮定します(巨大なサイズはバッファをすぐにいっぱいにし、小さなサイズはそうではないため)。このバッファリングを無効にします。

コード:

ignore_user_abort(false);

$boundary = "myboundary";

//Set this so PHP doesn't timeout during a long stream
set_time_limit(0);

$socketConn = @fsockopen ("192.168.1.6", 1989, $errno, $errstr, 2);
if (!$socketConn)
exit();
stream_set_timeout($socketConn, 10);
fputs ($socketConn, "GET /mjpeg HTTP/1.0\r\n\r\n");

//Setup Header Information
header("Cache-Control: no-cache");
header("Cache-Control: private");
header("Pragma: no-cache");
header("Content-type: multipart/x-mixed-replace; boundary=$boundary");

@ini_set('implicit_flush', 1);
for ($i = 0; $i < ob_get_level(); $i++)
ob_end_flush();
ob_implicit_flush(1);

stream_set_blocking($f2, false);

//Send data to client
while (connection_status() == CONNECTION_NORMAL)
{
    $chunk = fread($socketConn, 128);
    print $chunk;   
}

fclose($socketConn);
29
Ioncannon

tl; drバージョン

2つのことを行います。

  1. ユーザースペースの出力バッファを無効にします...

    • グローバルに、どちらかによって...

      • Php.iniで_output_buffering_をオフにする、または
      • Apache設定で_output_buffering_を無効にする

        _php_flag "output_buffering" Off
        _
    • またはあなたが気にするスクリプトのために、どちらかによって...

      • ob_end_flush()の呼び出し、または
      • ob_end_clean()の呼び出し
  2. また、次のいずれかの方法で、サーバーレベルの出力バッファーを可能な限り無効にします。

    • スクリプトの開始時にob_implicit_flush()を呼び出す、または
    • echoステートメントまたは出力を応答本文に追加する他のステートメントの後にflush()を呼び出す

長いバージョン

紛らわしいことに、関連する可能性のある2層のバッファリングがあり、PHPドキュメンテーションは2つを区別するのに不十分な仕事をします。

出力バッファー

通常、最初の層は、「PHP docs」によって「出力バッファ」として参照されます。このバッファリング層は、HTTP応答のbodyへの出力にのみ影響し、ヘッダー。出力バッファリングは ob_start() でオンにし、 ob_end_flush() または ob_end_clean() 。また、php.iniの _output_buffering_ オプションを使用して、すべてのスクリプトを出力バッファリングで自動的に開始させることもできます。

productionバージョンのphp.ini のこのオプションのデフォルト値は4096です。つまり、出力の最初の4096バイトが出力バッファーにバッファーされ、その時点でフラッシュされ、出力バッファーが行われます。オフにしました。

Php.iniファイルで_output_buffering_をOffに設定することにより(または、

_php_flag "output_buffering" Off
_

apacheを使用している場合は、Apache構成で)。または、スクリプトの開始時にob_end_clean()またはob_end_flush()を呼び出すことにより、単一のスクリプトに対して無効にすることができます。

書き込みバッファー、およびWebサーバーバッファー

出力バッファを超えるのは、PHPマニュアルが「書き込みバッファ」と呼ぶものに加えて、Webサーバーにあるバッファリングシステムです。PHP = _mod_php_を介したApacheで、_mod_gzip_を使用していない場合、 flush() を呼び出してこれらをフラッシュできます。他のバックエンドでは、動作する可能性がありますが、マニュアルは保証を与えるのが難しいです:

説明

_void flush ( void )
_

PHPと、バックエンドPHP=が使用しているもの(CGI、Webサーバーなど)の書き込みバッファをフラッシュします。これは、現在の出力をブラウザにはいくつかの注意事項があります。

flush()は、Webサーバーのバッファリングスキームをオーバーライドできない場合があり、ブラウザのクライアント側のバッファリングには影響しません。また、PHPのユーザー空間の出力バッファリングメカニズムにも影響しません。つまり、 ob_flush()flush()の両方を呼び出して、ob出力バッファーを使用している場合はこれらを呼び出す必要があります。 。

また、いくつかの方法でPHP echoを呼び出すたびに自動的にflush()を呼び出します(または、応答に出力をエコーする他の操作を行う)体)。

1つ目は、 ob_implicit_flush() を呼び出すことです。この関数の名前は一見したところに注意してください。接頭辞_ob__が与えられた場合、合理的な人は_ob_start_、_ob_flush_などのように「出力バッファ」に影響を与えると予想します。しかし、そうではありません。 ob_implicit_flush()は、flush()と同様に、サーバーレベルの出力バッファーに影響を与え、他の_ob__関数によって制御される出力バッファーとは一切対話しません。

2つ目は、php.iniで _implicit_flush_ フラグをOnに設定して、暗黙的なフラッシュをグローバルに有効にすることです。これは、すべてのスクリプトの開始時にob_implicit_flush()を呼び出すことと同じです。マニュアルはこれに対して助言をしていることに注意してください"深刻なパフォーマンスへの影響"。これについては、この 接線関連の回答 で説明します。

50
Mark Amery

出力バッファリングを無効にするのではなく、読み取り操作ごとに flush() を呼び出すだけで済みます。これにより、サーバー構成を台無しにする必要がなくなり、スクリプトの移植性が向上します。

17
DaveRandom

出力バッファリングは階層化することができ、以前のコードが複数のレベルを作成していた場合がありました。これですべてがクリアされます。

while (ob_get_level()) ob_end_clean(); 
// or ob_end_flush() if you want the contents of the buffer.
9
Yehosef

PHPで出力バッファリングを無効にするために、.htaccessファイルで以下のコードを提供できます。

php_flag "output_buffering" off
2
Binod

この質問は少し古いことを知っていますが、この質問に戻って、次のようにスクリプトごとに出力バッファリングをオフにすることができます。

if (ob_get_level())
   ob_end_clean();

これにより、後続のスクリプトの出力バッファリングがすべてオフになります。

0
Solomon Closson