如何将数据刷新到浏览器但继续执行


How to flush data to browser but continue executing

我有一个ob_start()和一个相应的ob_flush()。我想刷新一部分数据并继续执行其余数据。使用ob_flush()没有帮助。此外,如果可能的话,需要在浏览器中不显示加载的情况下进行休息。

编辑:

我不想使用阿贾克斯

我过去做过这个,这就是我解决它的方式:

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 您的内容,因为这会改变内容的长度,但不会更改标题。 它还可以缓冲您的输出,因此它不会立即发送到客户端。
您可以尝试让 apache 知道不要使用 apache_setenv('no-gzip', '1'); 来压缩您的内容。 但是,如果您使用重写规则转到您的页面,这将不起作用,因为那时它还将修改这些环境变量。 至少,它为我做到了。

请参阅手册中有关向用户刷新内容的更多注意事项。

ob_flush写入缓冲区。换句话说,ob_flush告诉PHP给Apache(或nginx/lighttpd/其他什么(输出,然后让PHP忘记它。一旦 Apache 有了输出,它就可以用它做任何它想做的事情。 (换句话说,ob_flush之后,它是否立即写入浏览器是您无法控制的(。

所以,简短的回答:没有保证的方法可以做到这一点。

只是一个猜测,你可能正在寻找AJAX。 每当人们尝试操作页面内容加载时,AJAX 几乎总是正确的路径。

如果要在后台继续执行任务,可以使用 ignore_user_abort ,但如此处所述,但这通常不是最佳方法。你基本上失去了对该线程的控制,在我看来,Web 服务器线程不是繁重处理所属的地方。

我会尝试将其从面向网络的东西中提取出来。这可能意味着一个 cron 条目或只是从 PHP 内部生成一个后台进程(一个进程虽然从脚本执行内部启动,但不会随着脚本的死亡而死亡,并且脚本不会等待它完成而死亡(。

如果你确实走这条路,这意味着你甚至可以在必要时制作某种状态系统。然后,您可以监视执行并定期向用户提供有关进度的更新。(从技术上讲,您也可以使用ignore_user_abort -ed脚本制作状态系统,但对我来说似乎并不那么干净。

这是我

的函数

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,第二个参数是一个数组,要传递给带有索引数组的"test"函数

注意:我不在脚本开头使用ob_start()

我有一篇文章解释了如何使用 apache/mod_php 在我的博客上实现这一点: http://codehackit.blogspot.com/2011/07/how-to-kill-http-connection-and.html 希望这有帮助,干杯

如果您使用的是 PHP-FPM:

ignore_user_abort(true);
fastcgi_finish_request();

以上两个功能是ignore_user_abort防止错误和fastcgi_finish_request关闭客户端连接的关键因素。

fastcgi_finish_request

此函数将所有响应数据刷新到客户端并完成请求。这允许在不保持与客户端的连接打开的情况下执行耗时的任务。

不在阿帕奇上工作。(PHP 5>= 5.3.3, PHP 7(

使用:

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。不过,在那之后,他们都关闭了请求。