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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10579116/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 22:30:40  来源:igfitidea点击:

How to flush data to browser but continue executing

phpoutput-buffering

提问by aWebDeveloper

I have a ob_start()and a corresponding ob_flush(). I would like to flush a portion of data and continue executing the rest. Using ob_flush()didn't help. Also if possible rest needs to happen without showing loading in browser.

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

EDIT:

编辑:

I don't want to use ajax

我不想使用ajax

采纳答案by Corbin

ob_flushwrites the buffer. In other words, ob_flushtells PHP to give Apache (or nginx/lighttpd/whatever) the output and then for PHP to forget about it. Once Apache has the output, it does whatever it wants with it. (In other words, after ob_flushit's out of your control whether or not it gets immediately written to the browser).

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

So, short answer: There's no guaranteed way to do that.

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

Just a guess, you're likely looking for AJAX. Whenever people are trying to manipulate when page content loads as you're doing, AJAX is almost always the correct path.

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

If you want to continue a task in the background, you can use ignore_user_abort, as detailed here, however, that is often not the optimal approach. You essentially lose control over that thread, and in my opinion, a web server thread is not where heavy processing belongs.

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

I would try to extract it out of the web facing stuff. This could mean a cron entry or just spawning a background process from inside of PHP (a process that though started from inside of script execution will not die with the script, and the script will not wait for it to finish before dying).

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

If you do go that route, it will mean that you can even make some kind of status system if necessary. Then you could monitor the execution and give the user periodic updates on the progress. (Technically you could make a status system with a ignore_user_abort-ed script too, but it doesn't seem as clean to me.)

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

回答by Zombaya

I have done this in the past and this is how I solved it:

我过去曾这样做过,这就是我解决它的方法:

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

As I said in a couple of comments before, you should watch out for gzipping your content, since that will alter the length of your content, but not change the header about it. It also can buffer your output, so it won't get send to the client instantly.
You could try letting apache know to not gzip your content by using apache_setenv('no-gzip', '1');. But this will not work if you use rewrite-rules to go to your page, since then it will also modify those environment variables. At least, it did so for me.

正如我之前在几条评论中所说,您应该注意 gzip 压缩您的内容,因为这会改变您的内容的长度,但不会更改有关它的标题。它还可以缓冲您的输出,因此它不会立即发送到客户端。
您可以尝试让 apache 知道不要使用 .zip 压缩您的内容apache_setenv('no-gzip', '1');。但是,如果您使用 rewrite-rules 转到您的页面,这将不起作用,因为它也会修改这些环境变量。至少,它对我来说是这样。

See more caveats about flushing your content to the user in the manual.

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

回答by Afrig Aminuddin

this is my function

这是我的功能

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

wrap the function to be executed in the end, after php close the connection. and of course the browser will stop buffering.

最后将要执行的函数包裹起来,在php关闭连接后。当然浏览器会停止缓冲。

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

this is how to call the function

这是调用函数的方法

bg_process('test'); 

first argument is callable, second argument is an array to be passed to 'test' function with an indexed array

第一个参数是callable,第二个参数是要传递给带有索引数组的“test”函数的数组

Note : I don't use ob_start()at the beginning of the script.

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

回答by smassey

I have an article explaining how this can be achieved using apache/mod_php on my blog here: http://codehackit.blogspot.com/2011/07/how-to-kill-http-connection-and.htmlHope this helps, cheers

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

回答by sun

fastcgi_finish_request

fastcgi_finish_request

This function flushes all response data to the client and finishes the request. This allows for time consuming tasks to be performed without leaving the connection to the client open.

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

not work on Apache.(PHP 5 >= 5.3.3, PHP 7)

不适用于 Apache。(PHP 5 >= 5.3.3,PHP 7)

回答by Nick Tsai

If you are using PHP-FPM:

如果您使用的是 PHP-FPM:

ignore_user_abort(true);
fastcgi_finish_request();

Above two functions are the key factors which ignore_user_abortprevents error and fastcgi_finish_requestcloses client connection.

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

回答by mowwwalker

Use:

用:

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

..where $lenis the length of the data to be flushed to the client.

..where$len是要刷新到客户端的数据的长度。

I don't have the background to know when and where this is going to work, but I tried on a few browsers, and all returned instantly with:

我没有背景知道这将在何时何地起作用,但我尝试了一些浏览器,并且所有浏览器都立即返回:

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

edit: Chrome, IE, and Opera showed this, while FireFox showed this is more than 5. All of them closed the request after that though.

编辑:Chrome、IE 和 Opera 显示this,而 FireFox 显示this is more than 5. 尽管如此,他们所有人都在此之后关闭了请求。