クライアントにのみログを生成するphpスクリプトがあります。
何かをエコーするとき、オンザフライでクライアントに転送したいです。
(スクリプトの処理中はページが空白になるため)ob_start()
とob_flush()
で遊んでいましたが、うまくいきませんでした。
最適なソリューションは何ですか?
PS:echo
呼び出しの最後にフラッシュを置くのは少し汚いです...
編集:回答が機能しませんでしたPHPまたはApache Fault?
編集:
私はマニュアルページの称賛を読んでいたときに遭遇しました バグ それはob_implicit_flush
は機能しません。以下はその回避策です。
ob_end_flush();
# CODE THAT NEEDS IMMEDIATE FLUSHING
ob_start();
何が起こっているのかもしれませんが、サーバーは、送信する価値のあるパケットと見なされるものを送信するのに十分な文字をサーバーが構築するまで、サーバーからパケットを受信しません。
古い回答:
ob_implicit_flush
これは、出力バッファリングにしばらくバッファリングをオフにするよう指示します。
ob_implicit_flush(true);
# CODE THAT NEEDS IMMEDIATE FLUSHING
ob_implicit_flush(false);
同じ問題が発生し、マニュアルに掲載されている例の1つが機能しました。ここですでに述べたポスターの1つとして文字セットを指定する必要があります。 http://www.php.net/manual/en/function.ob-flush.php#109314
header( 'Content-type: text/html; charset=utf-8' );
echo 'Begin ...<br />';
for( $i = 0 ; $i < 10 ; $i++ )
{
echo $i . '<br />';
flush();
ob_flush();
sleep(1);
}
echo 'End ...<br />';
だからここに私が見つけたものがあります。
フラッシュは、Apacheのmod_gzipまたはNginxのgzipでは機能しません。これは、論理的にコンテンツをgzipしているため、gzipするためにコンテンツをバッファリングする必要があるためです。あらゆる種類のWebサーバーのgzip圧縮がこれに影響します。つまり、サーバー側でgzipを無効にし、fastcgiバッファーサイズを小さくする必要があります。そう:
Php.iniの場合:
output_buffering = Off
zlib.output_compression = Off
Nginx.confで:
gzip off;
proxy_buffering off;
特にphp.iniにアクセスできない場合は、次の行も用意してください。
@ini_set('zlib.output_compression',0);
@ini_set('implicit_flush',1);
@ob_end_clean();
set_time_limit(0);
最後に、もしあれば、以下のコードにコメントしてください:
ob_start('ob_gzhandler');
ob_flush();
PHPテストコード:
ob_implicit_flush(1);
for ($i=0; $i<10; $i++) {
echo $i;
// this is to make the buffer achieve the minimum size in order to flush data
echo str_repeat(' ',1024*64);
sleep(1);
}
動作しないように見えるフラッシュは、文字セットの自動検出の副作用です。
ブラウザは、表示する文字セットを認識するまで何も表示しません。文字セットを指定しない場合、推測を試行する必要があります。問題は、十分なデータがないとうまく推測できないことです。そのため、ブラウザは、表示する前にこの1024バイト(または同様の)バッファを埋める必要があるようです。
したがって、解決策は、ブラウザが文字セットを推測する必要がないようにすることです。
テキストを送信する場合は、「; charset = utf-8 'をコンテンツタイプに追加し、HTMLの場合は、適切なメタタグに文字セットを追加します。
2018年に来る人のために:
唯一のソリューションは私のために働いた:
<?php
if (ob_get_level() == 0) ob_start();
for ($i = 0; $i<10; $i++){
echo "<br> Line to show.";
echo str_pad('',4096)."\n";
ob_flush();
flush();
sleep(2);
}
echo "Done.";
ob_end_flush();
?>
バッファを「埋める」ように見えるので、「4096」の部分を維持することが非常に重要です...
欲しいのは flush メソッドです。例:
echo "log to client";
flush();
次のように、エコーする関数を作成してください:
function fecho($string) {
echo $string;
ob_flush();
}
使用する正しい関数はflush()
です。
<html>
<body>
<p>
Hello! I am waiting for the next message...<br />
<?php flush(); sleep(5); ?>
I am the next message!<br />
<?php flush(); sleep(5); ?>
And I am the last message. Good bye.
</p>
</body>
</html>
IEには、フラッシュされたコンテンツが少なくとも256バイトの場合にのみ出力する「問題」があるため、ページの最初の部分は少なくとも256バイトである必要があることに注意してください。
似たようなことがありました。を使用して
// ini_set("output_buffering", 0); // off
ini_set("zlib.output_compression", 0); // off
ini_set("implicit_flush", 1); // on
私の場合、出力のフラッシュが頻繁に行われました。
しかし、特定のポイント(実行中のループ内)で出力をフラッシュする必要があったため、両方を使用して
ob_flush();
flush();
一緒に働いてくれました。
"output_buffering" ini_set(...)でオフにできませんでした。php.iniで直接オンにする必要があり、phpinfo()はオフにすると「値なし」として設定を表示します、それは正常ですか? 。
これは私にとってはうまくいきます(Apache 2.4/PHP 7.0):
@ob_end_clean();
echo "lorem ipsum...";
flush();
sleep(5);
echo "<br>dolor...";
flush();
sleep(5);
echo "<br>sit amet";
ウイルス対策ソフトウェアが出力フラッシュを妨害している可能性もあります。私の場合、Kaspersky Anti-Virus 2013は、承認済みのソリューションを使用していても、ブラウザーに送信する前にデータチャンクを保持していました。
頻繁に言及されていないことの1つは、さまざまなホスティング環境の詳細のためにオンに維持されるgzip圧縮です。
これは、PHP-FPMをFast CGIとして使用する最新のアプローチで、.htaccess書き換えルールや環境変数を必要としません。
Php.iniまたは.user.iniで:
output_buffering = 0
zlib.output_compression = 0
implicit_flush = true
output_handler =
In PHP script:
header('Content-Encoding: none'); // Disable gzip compression
ob_end_flush(); // Stop buffer
ob_implicit_flush(1); // Implicit flush at each output command
this comment on official PHP ob_end_flush()の必要性に関するドキュメント)を参照してください。
これは私のコードです:(PHP7で動作します)
private function closeConnection()
{
@Apache_setenv('no-gzip', 1);
@ini_set('zlib.output_compression', 0);
@ini_set('implicit_flush', 1);
ignore_user_abort(true);
set_time_limit(0);
ob_start();
// do initial processing here
echo json_encode(['ans' => true]);
header('Connection: close');
header('Content-Length: ' . ob_get_length());
ob_end_flush();
ob_flush();
flush();
}
私は議論に遅れていますが、多くの人がflush()を追加すると言っていることを読みました。各コードの終わりに汚れているように見え、それらは正しいです。
最良の解決策は、deflate、gzip、およびApache、中間ハンドラー、PHPからのすべてのバッファリングを無効にすることです。次に、php.iniに以下が必要です。
output_buffering = Off
zlib.output_compression = Off
implicit_flush = Off
一時的な解決策これをphp.iniに含める[〜#〜] if [〜#〜] flush()で問題を解決できます。しかし、あなたはそれをどこにでも置くのは汚くていと思う。
implicit_flush = On
Php.iniに上記のみを配置する場合、flush()を配置する必要はありません。あなたのコードでもう。
これを試して:
_while (@ob_end_flush());
ob_implicit_flush(true);
echo "first line visible to the browser";
echo "<br />";
sleep(5);
echo "second line visible to the browser after 5 secs";
_
この方法で、現在のスクリプトの出力バッファを実際に無効にしていることに注意してください。 ob_start()で再度有効にできると思います(わかりません)。
重要なことは、上記のように出力バッファを無効にすると、header()
関数を使用してphpスクリプトをリダイレクトできなくなることです。phpはスクリプト実行ごとに1回だけHTTPヘッダーを送信できるからです。ただし、javascriptを使用してリダイレクトできます。それに関しては、phpスクリプトに次の行をエコーさせるだけです。
_ echo '<script type="text/javascript">';
echo 'window.location.href="'.$url.'";';
echo '</script>';
echo '<noscript>';
echo '<meta http-equiv="refresh" content="0;url='.$url.'" />';
echo '</noscript>';
exit;
_
Dreamhostのような特定の共有ホスティングサイトを使用している場合、別のルートを経由せずにPHP出力バッファリングを無効にすることはできません。
出力バッファキャッシュの変更PHP FastCGIを使用している場合、PHP関数flush()、ob_flush()、およびob_implicit_flush()は期待どおりに機能しません。デフォルトでは、出力はPHP(具体的にはApacheモジュールmod_deflateよりも高いレベルでバッファリングされますmod_gzipとフォーム/機能が似ています)。
バッファーなしの出力が必要な場合は、CGIを使用する(FastCGIの代わりに)か、サポートに連絡してmod_deflateを要求する必要がありますあなたのサイトでは無効です。
https://help.dreamhost.com/hc/en-us/articles/214202188-PHP-overview