20

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

編集:

ajaxは使いたくない

4

7 に答える 7

18

私は過去にこれを行いましたが、これが私がそれを解決した方法です:

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();
}

以前のいくつかのコメントで述べたように、コンテンツの長さは変更されますが、ヘッダーは変更されないため、コンテンツを gzip 圧縮することに注意する必要があります。また、出力をバッファすることもできるため、すぐにクライアントに送信されることはありません。
を使用して、コンテンツを gzip しないように apache に知らせることができますapache_setenv('no-gzip', '1');。ただし、rewrite-rules を使用してページに移動すると、これらの環境変数も変更されるため、これは機能しません。少なくとも、私にとってはそうでした。

マニュアルでコンテンツをユーザーにフラッシュすることに関するその他の警告を参照してください。

于 2012-05-14T09:15:24.480 に答える
15

ob_flushバッファに書き込みます。言い換えると、ob_flushApache(またはnginx / lighttpd / whatever)に出力を提供し、PHPがそれを忘れるようにPHPに指示します。Apacheが出力を取得すると、Apacheは必要な処理を実行します。(言い換えると、ob_flushそれが制御不能になった後、それがすぐにブラウザに書き込まれるかどうか)。

だから、簡単な答え:それを行うための保証された方法はありません。

推測ですが、おそらくAJAXを探しています。あなたがしているようにページコンテンツがロードされるときに人々が操作しようとするときはいつでも、AJAXはほとんど常に正しいパスです。

バックグラウンドでタスクを続行する場合は、ここignore_user_abortで詳しく説明するようにを使用できますが、多くの場合、これは最適なアプローチではありません。あなたは本質的にそのスレッドの制御を失います、そして私の意見では、ウェブサーバースレッドは重い処理が属する場所ではありません。

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

そのルートに行けば、必要に応じて何らかのステータスシステムを作成することもできます。次に、実行を監視し、進行状況を定期的に更新することができます。(技術的には、-edスクリプトを使用してステータスシステムを作成することもできますが、ignore_user_abort私にはそれほどクリーンではないようです。)

于 2012-05-14T07:32:06.337 に答える
5

これが私の機能です

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);
    }

phpが接続を閉じた後、最後に実行される関数をラップします。もちろん、ブラウザはバッファリングを停止します。

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

これは関数を呼び出す方法です

bg_process('test'); 

最初の引数はcallable、2 番目の引数は、インデックス付き配列を使用して「test」関数に渡される配列です

ob_start()注:スクリプトの冒頭では使用しません。

于 2012-05-17T06:37:46.893 に答える
2

私のブログにapache/mod_phpを使用してこれを実現する方法を説明する記事があります:http ://codehackit.blogspot.com/2011/07/how-to-kill-http-connection-and.htmlこれがお役に立てば幸いです。乾杯

于 2012-05-14T07:50:34.567 に答える
-1

使用する:

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

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

これがいつどこで機能するかを知るための背景はありませんが、いくつかのブラウザで試してみたところ、すべてすぐに次のように返されました。

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

編集:Chrome、IE、Operaが表示さthisれ、FireFoxが表示されthis is more than 5ました。その後、全員がリクエストを閉じました。

于 2012-05-14T07:53:03.377 に答える