私のパソコン雑記帖

沈黙の "flush"

カテゴリー: PHP
23Aug2006⇒2Apr2010更新

"flush"!!
動画の "flash" ではありません。「洗い出す」というような意味があります。php 関数の一つで、バッファーされている出力をブラウザに対して出力しようとします。うまくいけば・・・。


"flush" されずに "flustrate"

<?php
for ($i=0;$i<1000;$i++) {
print "☆";
sleep(1); }
?>

というスクリプトを実行すると完了するのに16分近くかかりますが、繰り返し操作が終わるまでブラウザ上に出力されず、おそらく途中でタイムアウトになってしまいます。これが大量にメールを送信するスクリプトだったりして、途中でタイムアウトされてしまうと一寸ややこしいことになります。これを回避する手段として、flush 関数を使い逐一出力することがすすめられています。

ところがこの flush なかなかの曲者で、ただ単に flush() を挿入した位では働いてくれません。ネット上でも、flush に関するSOSやアドバイスが多々見られます。その中に、ob_end_flush や ob_end_clean() を併用しなければならないこと、またそれで解決をみたという報告が多く見られます。まず「出力のバッファリングを オフにせよ」ということで合理的なことではあります。ただ、私の場合それでも解決せず、ブラウザは沈黙を守ったままでした。


あれこれやってみたが・・・

結局、最初見逃していた flush の注意事項に腰をすえて取組むことになりました。大概、次のようなことが書かれています。

  1. mod_gzip のような Apache 用のサーバモジュールはそれ自体がバッファリングを行います。そのため、flush() をコールしても即時にデータをクライアントに送信しないという結果につながります。
  2. ブラウザ側で表示前に入力をバッファリングすることもあり得ます。Netscape では例えば改行または開始タグを受信するまでテキストはバッファリングされ、最も外側のテーブルのタグが現れるまでテーブルは描画されません。
  3. いくつかのバージョンの Microsoft Internet Explorer は 256 バイトの 出力を受けてからページを表示し始めます。このため、これらのブラウザにページを表示させるには、フラッシュする前に余分な空白を送信する必要があるかもしれません。

2. 3. は容易に理解できるし対処もできます。しかしそれでもブラウザは沈黙。残ったのは 1. です。意味は分かりますが、具体的な対処法まで説明してくれていません。

散々探しまわってようやく見つけたのが MODWEST Customer Support というサイト。ここに対処法の説明がありました。 mod_gzip_on Off と .htaccess に1行書き込むだけ。「あっけない」って感じですが、とにかくこれでようやくブラウザはサクサクと出力し始めてくれました。

いつ来るか分からないタイムアウトにビクビクしながらブラウザを眺めているのは、心臓に負荷がかかります。逐一表示されると目に見えて進行状況がわかるので精神衛生上もすこぶる良好。


"flush" と文字化け

内部エンコーディングが euc-jp の場合、これも結構わずらわしい問題のようです。

私の場合、ob_end_clean() を併用した場合は文字化けが起こり、ob_end_flush() では問題がおこりませんでした。そんなに単純なものではないと思いますが。環境によって解決法が異なるのかもしれません。


"set_time_limit" の併用

タイムアウトを回避する手段の一つとして、set_time_limit(0) として制限時間を解除する方法もすすめられているようです。

しかしセーフモードでは使用できないとのこと。私の共有サーバ環境ではセーフモードを解除出来そうも無いので深追いはしていません。今のところ、これがなくても”flush”されるので支障は感じません。


テストサンプル

<?php
ob_end_flush(); //(1)
for ($i=0;$i<1000;$i++) {
print "☆";
flush(); //(2)
sleep(1);
}
?>

.htaccess に一行 mod_gzip_on Off を追加 //(3)

(1) (2) (3) のいずれが欠けても逐次出力はできません。
サーバー環境によっても状況が変ると思いますので、テスト環境を参照しておきます。
XREA s68_coreserver、Apache 1.3.37、PHP 5.2.5

実際は sleep に代わって繰り返しの対象となるジョブコードが入ることになるでしょう。例えばメールリストから宛先を拾ってきてメール送信する等。ジョブコードそのものはプリント出力と無関係でも、何らかのプリント出力を挿入することで逐次画面が切り替わり、タイムアウトを避けることが出来ます。またプリント出力を工夫することでスマートな進捗表示を設計することも出来るでしょう。



コメント


【test】  2016年12月20日 16時18分

teset