PHP Flush 可以工作......甚至在 Nginx 中

发布于 2024-10-15 03:59:34 字数 152 浏览 2 评论 0原文

是否可以在每次执行循环时回显?例如:

foreach(range(1,9) as $n){
    echo $n."\n";
    sleep(1);
}

我希望看到它每次打印每个结果,而不是在循环完成时打印所有内容。

Is it possible to echo each time the loop is executed? For example:

foreach(range(1,9) as $n){
    echo $n."\n";
    sleep(1);
}

Instead of printing everything when the loop is finished, I'd like to see it printing each result per time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

遗弃M 2024-10-22 03:59:34

消除 nginx 缓冲的最简单方法是发出标头:

header('X-Accel-Buffering: no');

这会消除 proxy_buffering 和(如果您的 nginx >= 1.5.6)fastcgi_buffering。如果您使用 php-fpm,fastcgi 位至关重要。根据需要进行标头也更加方便。

有关 X-Accel-Buffering 的文档
有关 fastcgi_buffering 的文档

The easiest way to eliminate nginx's buffering is by emitting a header:

header('X-Accel-Buffering: no');

This eliminates both proxy_buffering and (if you have nginx >= 1.5.6), fastcgi_buffering. The fastcgi bit is crucial if you're using php-fpm. The header is also far more convenient to do on an as-needed basis.

Docs on X-Accel-Buffering
Docs on fastcgi_buffering

只是我以为 2024-10-22 03:59:34

最终解决方案

这就是我发现的:

Flush 在 Apache 的 mod_gzip 或 Nginx 的 gzip 下不起作用,因为从逻辑上讲,它正在对内容进行 gzip 压缩,并且要做到这一点,它必须缓冲内容以对其进行 gzip。任何类型的 Web 服务器 gzip 压缩都会影响这一点。简而言之,在服务器端,我们需要禁用 gzip 并减小 fastcgi 缓冲区大小。所以:

  • 在 php.ini 中:

    。输出缓冲 = 关闭

    。 zlib.output_compression = Off

  • 在 nginx.conf 中:

    。 gzip 关闭;

    。 proxy_buffering off;

另外,请准备好以下几行,特别是如果您无法访问 php.ini:

  • @ini_set('zlib.output_compression',0);

  • @ini_set('implicit_flush',1);

  • @ob_end_clean();

  • set_time_limit(0);

最后,如果你有的话,注释下面的代码:

  • ob_start('ob_gzhandler');

  • ob_flush();

PHP 测试代码:

ob_implicit_flush(1);

for($i=0; $i<10; $i++){
    echo $i;

    //this is for the buffer achieve the minimum size in order to flush data
    echo str_repeat(' ',1024*64);

    sleep(1);
}

相关:

FINAL SOLUTION

So that's what I found out:

Flush would not work under Apache's mod_gzip or Nginx's gzip because, logically, it is gzipping the content, and to do that it must buffer content to gzip it. Any sort of web server gzipping would affect this. In short, at the server side, we need to disable gzip and decrease the fastcgi buffer size. So:

  • In php.ini:

    . output_buffering = Off

    . zlib.output_compression = Off

  • In nginx.conf:

    . gzip off;

    . proxy_buffering off;

Also have this lines at hand, specially if you don't have acces to php.ini:

  • @ini_set('zlib.output_compression',0);

  • @ini_set('implicit_flush',1);

  • @ob_end_clean();

  • set_time_limit(0);

Last, if you have it, coment the code bellow:

  • ob_start('ob_gzhandler');

  • ob_flush();

PHP test code:

ob_implicit_flush(1);

for($i=0; $i<10; $i++){
    echo $i;

    //this is for the buffer achieve the minimum size in order to flush data
    echo str_repeat(' ',1024*64);

    sleep(1);
}

Related:

韬韬不绝 2024-10-22 03:59:34

nginx 服务器上的简单解决方案:

fastcgi_keep_conn on; # < solution

proxy_buffering off;
gzip off;

Easy solution on nginx server:

fastcgi_keep_conn on; # < solution

proxy_buffering off;
gzip off;
氛圍 2024-10-22 03:59:34

我不想在某些特定情况下为整个服务器或整个目录关闭 gzip,而只是为了一些脚本。

在任何内容被回显之前,你所需要的就是这个:

header('Content-Encoding: none;');

然后像平常一样进行刷新:

ob_end_flush();
flush();

Nginx 似乎发现编码已被关闭,并且不进行 gzip。

I didn't want to have to turn off gzip for the whole server or a whole directory, just for a few scripts, in a few specific cases.

All you need is this before anything is echo'ed:

header('Content-Encoding: none;');

Then do the flush as normal:

ob_end_flush();
flush();

Nginx seems to pick up on the encoding having been turned off and doesn't gzip.

蓝礼 2024-10-22 03:59:34

您需要将 php 的缓冲区刷新到浏览器

foreach(range(1,9) as $n){
    echo $n."\n";
    flush();
    sleep(1);
}

请参阅: http://php.net/manual /en/function.flush.php

You need to flush the php's buffer to the browser

foreach(range(1,9) as $n){
    echo $n."\n";
    flush();
    sleep(1);
}

See: http://php.net/manual/en/function.flush.php

↘紸啶 2024-10-22 03:59:34

我发现您可以

header("Content-Encoding:identity");

在 php 脚本中设置:禁用 nginx gzipping,而无需修改 nginx.conf

I found that you can set:

header("Content-Encoding:identity");

in your php script to disable nginx gzipping without having to modify the nginx.conf

溇涏 2024-10-22 03:59:34

您可以通过在循环中间刷新输出缓冲区来实现此目的。

示例:

ob_start();
foreach(range(1,9) as $n){
    echo $n."\n";
    ob_flush();
    flush();
    sleep(1);
}

请注意,如果您打开了 zlib 压缩,您的 php.ini 设置可能会影响此功能是否有效

You can accomplish this by flushing the output buffer in the middle of the loop.

Example:

ob_start();
foreach(range(1,9) as $n){
    echo $n."\n";
    ob_flush();
    flush();
    sleep(1);
}

Note that your php.ini settings can affect whether this will work or not if you have zlib compression turned on

可爱咩 2024-10-22 03:59:34

我的 php-fpm 引擎遇到了 gzip 问题。
这段代码是唯一适合我的代码:

function myEchoFlush_init() {
    ini_set('zlib.output_compression', 0);
    ini_set('output_buffering', 'Off');
    ini_set('output_handler', '');
    ini_set('implicit_flush', 1);
    ob_implicit_flush(1);
    ob_end_clean();
    header('Content-Encoding: none;');

}

function myEchoFlush($str) {
    echo $str . str_repeat(' ', ini_get('output_buffering') * 4) . "<br>\n";
}

这是我的测试函数:它检查 max_execution_time :

public function timeOut($time = 1, $max = 0) {
    myEchoFlush_init();
    if ($max) ini_set('max_execution_time', $max);
    myEchoFlush("Starting infinite loop for $time seconds. It shouldn't exceed : " . (ini_get('max_execution_time')));
    $start = microtime(true);
    $lastTick = 1;
    while (true) {
        $tick = ceil(microtime(true) - $start);
        if ($tick > $lastTick) {
            myEchoFlush(microtime(true) - $start);
            $lastTick = $tick;
        }
        if ($tick > $time) break;
    }
    echo "OK";
}

I had a gzip problem comming from my php-fpm engine.
this code is the only one working for me :

function myEchoFlush_init() {
    ini_set('zlib.output_compression', 0);
    ini_set('output_buffering', 'Off');
    ini_set('output_handler', '');
    ini_set('implicit_flush', 1);
    ob_implicit_flush(1);
    ob_end_clean();
    header('Content-Encoding: none;');

}

function myEchoFlush($str) {
    echo $str . str_repeat(' ', ini_get('output_buffering') * 4) . "<br>\n";
}

This is my test function : it checks max_execution_time :

public function timeOut($time = 1, $max = 0) {
    myEchoFlush_init();
    if ($max) ini_set('max_execution_time', $max);
    myEchoFlush("Starting infinite loop for $time seconds. It shouldn't exceed : " . (ini_get('max_execution_time')));
    $start = microtime(true);
    $lastTick = 1;
    while (true) {
        $tick = ceil(microtime(true) - $start);
        if ($tick > $lastTick) {
            myEchoFlush(microtime(true) - $start);
            $lastTick = $tick;
        }
        if ($tick > $time) break;
    }
    echo "OK";
}
看透却不说透 2024-10-22 03:59:34

将 PHP Flush/Streaming 与 gzip 相结合(AWS ALB,仅限 nginx)

我对 PHP 流支持的兴趣是使浏览器能够尽早获取/重要资产,以最大限度地减少关键渲染路径。必须在 PHP 流式传输或 gzip 之间进行选择并不是真正的选择。过去,这在 Apache 2.2.x 中是可以实现的,但是当前版本似乎没有这样做。

我能够使用 PHP 7.4 和 Amazon Linux 2 (v3.3.x) 使其与 AWS Application Load Balancer 后面的 nginx 配合使用。并不是说它只适用于 AWS 堆栈,但是位于 nginx 前面的 ALB 改变了一些事情,我没有机会使用直接公开的实例来测试它。所以请记住这一点。

nginx

location ~ \.(php|phar)(/.*)?$ {
  
    # php-fpm config
    # [...]

    gzip            on;
    gzip_comp_level 4;
    gzip_proxied    any;
    gzip_vary       on;

    tcp_nodelay     on;
    tcp_nopush      off;
}

gzip_proxies & gzip_vary 是 gzipped 流的关键参数,tcp_ 参数用于禁用 nginx 缓冲/等待 200 毫秒(不确定这是否仍然是默认的 nginx 设置)。

就我而言,我只需要为 php 文件启用它,您应该能够将其移至服务器配置的更高位置。

php.ini

  output_buffering = Off
  zlib.output_compression = Off
  implicit_flush = Off

如果你想手动控制缓冲区何时发送到服务器/浏览器,请设置implicit_flush = Off并使用ob_flush(); lush() 和最后 ob_end_flush()。

Combining PHP Flush/Streaming with gzip (AWS ALB, nginx only)

My interest in PHP streaming support was to enable the browsers to fetch early/important assets early as to minimize the critical render path. Having to choose between either PHP streaming or gzip wasn't really an alternative. This used to be possible with Apache 2.2.x in the past, however it doesn't look like this is something that's being worked on for current versions.

I was able to get it to work with nginx behind an AWS Application Load Balancer using PHP 7.4 and Amazon Linux 2 (v3.3.x). Not saying it only works with the AWS stack, however the ALB sitting in front of nginx changes things and I didn't have a chance to test it with a directly exposed instance. So keep this in mind.

nginx

location ~ \.(php|phar)(/.*)?$ {
  
    # php-fpm config
    # [...]

    gzip            on;
    gzip_comp_level 4;
    gzip_proxied    any;
    gzip_vary       on;

    tcp_nodelay     on;
    tcp_nopush      off;
}

gzip_proxies & gzip_vary are the key parameters for gzipped streaming, the tcp_ parameters are to disable nginx buffering/waiting for 200ms (not sure if that's still a default nginx setting).

In my case I only needed to enable it for the php files, you should be able to move it higher into your server config.

php.ini

  output_buffering = Off
  zlib.output_compression = Off
  implicit_flush = Off

If you want to manually control when the buffer is sent to the server/browser, set implicit_flush = Off and use ob_flush(); flush() and finally ob_end_flush().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文