2012-05-14 7 views
19

私はob_start()と対応するob_flush()を持っています。私はデータの一部をフラッシュして残りの部分を実行し続けたいと思います。 ob_flush()を使用しても役に立ちませんでした。可能であれば、ブラウザーに読み込みを表示せずに残りの部分を実行する必要があります。ブラウザにデータをフラッシュして実行する方法

EDIT:

私はアヤックス

+0

最初のob_flushを実行した後、他の出力を表示しますか?または、クライアントが伝えることができ、その後何らかの処理がバックグラウンドで継続される限り、要求が完全に終了するようにしますか? – Corbin

+0

バックグラウンドで続行 – aWebDeveloper

+0

Ok、私の答えを更新しました。 – Corbin

答えて

15

ob_flushを使用したくないが、バッファを書き込みます。言い換えれば、ob_flushは、Apacheに(またはnginx/lighttpd/whatever)出力を与え、PHPがそれを忘れるように指示します。 Apacheが出力を受け取ると、それが望むものは何でもします。 (言い換えれば、ob_flushの後は、ブラウザにすぐに書き込まれるかどうかはあなたのコントロールから外れています)。

したがって、短い答え:それを行うための保証された方法はありません。

AJAXを探しているようです。あなたがやっているときにページコンテンツが読み込まれるときに人々が操作しようとするたびに、AJAXはほとんど常に正しいパスです。

バックグラウンドでタスクを続行する場合は、hereのようにignore_user_abortを使用できますが、これは最適な方法ではないことがよくあります。あなたは本質的にそのスレッドを制御できなくなります。私の意見では、Webサーバーのスレッドは処理の重い部分ではありません。

私は、ウェブに絡んでいるものから抽出しようとします。これは、cronエントリを意味するか、PHPの内部からバックグラウンドプロセスを生成するだけです(スクリプトの実行から開始されても、スクリプトでは終了しませんが、スクリプトは終了するまで待つことはありません)。

もしあなたがそのルートに行くなら、必要であればある種のステータスシステムを作ることさえできます。その後、実行を監視して、進行状況に関する定期的な更新をユーザに与えることができます。 (技術的には、ignore_user_abort -edスクリプトを使ってステータスシステムを作ることもできますが、それは私にとってはきれいではありません)。

+1

新しいユーザがログインすると、データ。このデータはすぐに保存されますが、ユーザーに割り込んだり、ブラウザに読み込んだりすることはありません。 – aWebDeveloper

1

私のブログでは、apache/mod_phpを使ってこれを達成する方法を説明する記事があります。 :http://codehackit.blogspot.com/2011/07/how-to-kill-http-connection-and.htmlこれが役に立てば幸い、歓声

+7

ここでどのように動作するかを少し追加しておけば、サイトがダウンした場合でもここで解決できます。あなたのblogpostで書いたコードが動作します。しかし、あなたのコンテンツをgzipする前にApacheに伝えた場合、それはもはや機能しません(長さはもう正しくないので) – Zombaya

-1

用途:

header("Content-Length: $len"); 

..where $lenはクライアントにフラッシュするデータの長さです。

私はいつ、どこで、これは動作するように起こっている知っている背景を持っていないが、私はいくつかのブラウザで試みたが、すべてがで即座に返さ:

<?PHP 
    header("Content-length:5"); 
    echo "this is more than 5"; 
    sleep(5); 
?> 

編集:クローム、IE、およびOperaはthisを示し、FireFoxはthis is more than 5を示しました。彼らのすべてはその後、要求を閉じた。

+0

これはcontent-lengthが実際のコンテンツと同じ長さである必要があるからです。そしてgzipに注意してください。それはあなたの応答の長さを変えるでしょうから。 – Zombaya

+0

@ Zombaya、私はそれがいかに関連しているかわかりません。彼は一定量の後に彼の出力を切断しようとしていない限り、これは、必要なデータを送信した後、要求を終了するために働く必要があります。 – mowwwalker

+0

まあ、それをやろうとしたときに長さが実際の長さと一致しないと、接続は常に閉じずに読み込みを続けます。 – Zombaya

15

私は過去にこれを行っているし、これは私がそれを解決する方法である:

ob_start(); 

/* 
* Generate your output here 
*/ 

// Ignore connection-closing by the client/user 
ignore_user_abort(true); 

// Set your timelimit to a length long enough for your script to run, 
// but not so long it will bog down your server in case multiple versions run 
// or this script get's in an endless loop. 
if ( 
    !ini_get('safe_mode') 
    && strpos(ini_get('disable_functions'), 'set_time_limit') === FALSE 
){ 
    set_time_limit(60); 
} 

// Get your output and send it to the client 
$content = ob_get_contents();   // Get the content of the output buffer 
ob_end_clean();      // Close current output buffer 
$len = strlen($content);    // Get the length 
header('Connection: close');   // Tell the client to close connection 
header("Content-Length: $len");  // Close connection after $len characters 
echo $content;      // Output content 
flush();        // Force php-output-cache to flush to browser. 
            // See caveats below. 

// Optional: kill all other output buffering 
while (ob_get_level() > 0) { 
    ob_end_clean(); 
} 

私はそれが変更されますので、前に、あなたは、あなたのコンテンツをgzippingに気を付ける必要があり、コメントのカップルで述べたようにあなたのコンテンツの長さは、それについてのヘッダーを変更しないでください。それはまたあなたの出力をバッファリングすることができるので、即座にクライアントに送信されることはありません。
apache_setenv('no-gzip', '1');を使用して、gzipを使用しないようにApacheに知らせることができます。しかし、これはあなたのページに行くために書き換えルールを使用する場合、それらの環境変数を変更するので、動作しません。少なくとも、それは私のためにそうしました。

manualのコンテンツをユーザーにフラッシュする方法について、さらに詳しい警告をご覧ください。

+0

PHP関数がob_get_content ** S ** –

+1

であることをご確認ください。 $ len!= $ size; –

+1

@LukeOliff、ヘッドアップのおかげで、それが変更されました。 – Zombaya

4

これは、PHPが接続を閉じた後、最後に実行される機能をラップ

function bg_process($fn, $arr) { 
    $call = function($fn, $arr){ 
     header('Connection: close'); 
     header('Content-length: '.ob_get_length()); 
     ob_flush(); 
     flush(); 
     call_user_func_array($fn, $arr); 
     }; 
    register_shutdown_function($call, $fn, $arr); 
    } 

私の関数です。もちろん、ブラウザはバッファリングを停止します。

function test() { 
    while (true) { 
     echo 'this text will never seen by user'; 
     } 
    } 

これは最初の引数

bg_process('test'); 

関数を呼び出す方法では 2番目の引数はインデックス配列

注と「テスト」関数に渡される配列である、callableあります。私はob_start()をスクリプトの冒頭に使用しません。