如何在 PHP 中禁用输出缓冲

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8882383/
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-26 05:42:10  来源:igfitidea点击:

How to disable output buffering in PHP

phphttpmjpeg

提问by Ioncannon

I wrote a simple relay script that connects to a web camera and reads from the socket, and outputs this data using the print function. The data is MJPG data with boundaries already setup. I just output the data that is read.

我编写了一个简单的中继脚本,它连接到网络摄像头并从套接字读取,并使用打印功能输出这些数据。数据是已设置边界的 MJPG 数据。我只是输出读取的数据。

The problem is PHP seems to be buffering this data. When I set the camera to 1 FPS, the feed will freeze for 7-8 seconds, then quickly display 8 frames. If I set the resolution to a huge size, the camera move at more or less 1 frame per second. I assume then some buffering is happening (since huge sizes fill the buffer quickly, and low sizes don't), and I can't figure out how to disable this buffering. Does anyone know how to?

问题是 PHP 似乎正在缓冲这些数据。当我将相机设置为 1 FPS 时,Feed 会冻结 7-8 秒,然后快速显示 8 帧。如果我将分辨率设置为很大,相机会以每秒 1 帧的速度移动。我假设然后发生了一些缓冲(因为大尺寸会快速填充缓冲区,而小尺寸不会),我不知道如何禁用这种缓冲。有谁知道怎么做?

Code:

代码:

ignore_user_abort(false);

$boundary = "myboundary";

//Set this so PHP doesn't timeout during a long stream
set_time_limit(0);

$socketConn = @fsockopen ("192.168.1.6", 1989, $errno, $errstr, 2);
if (!$socketConn)
exit();
stream_set_timeout($socketConn, 10);
fputs ($socketConn, "GET /mjpeg HTTP/1.0\r\n\r\n");

//Setup Header Information
header("Cache-Control: no-cache");
header("Cache-Control: private");
header("Pragma: no-cache");
header("Content-type: multipart/x-mixed-replace; boundary=$boundary");

@ini_set('implicit_flush', 1);
for ($i = 0; $i < ob_get_level(); $i++)
ob_end_flush();
ob_implicit_flush(1);

stream_set_blocking($f2, false);

//Send data to client
while (connection_status() == CONNECTION_NORMAL)
{
    $chunk = fread($socketConn, 128);
    print $chunk;   
}

fclose($socketConn);

回答by Mark Amery

tl;dr version

tl;博士版本

Do two things:

做两件事:

  1. Disable the userspace output buffer, either...

    • Globally, by either...

      • Turning off output_bufferingin your php.ini, or
      • Turning off output_bufferingin your Apache config using

        php_flag "output_buffering" Off
        
    • or for just the script you care about, by either...

      • calling ob_end_flush(), or
      • calling ob_end_clean()
  2. Also, disable the server-level output buffer as much as you possibly can, by either:

    • calling ob_implicit_flush()at the start of your script, or
    • calling flush()after every echostatement or other statement that adds output to the response body
  1. 禁用用户空间输出缓冲区,或者...

    • 在全球范围内,无论是...

      • output_buffering在你的 php.ini 中关闭,或者
      • output_buffering在您的 Apache 配置中使用关闭

        php_flag "output_buffering" Off
        
    • 或仅针对您关心的脚本,通过...

      • 打电话ob_end_flush(), 或
      • 打电话 ob_end_clean()
  2. 此外,通过以下任一方式,尽可能多地禁用服务器级输出缓冲区:

    • ob_implicit_flush()在脚本开始时调用,或
    • flush()echo将输出添加到响应正文的每个语句或其他语句之后调用

Longer version

更长的版本

Confusingly, there are two layers of buffering that may be relevant and the PHP documentation does a poor job of distinguishing between the two.

令人困惑的是,有两层缓冲可能是相关的,PHP 文档在区分这两者方面做得很差。

The output buffer

输出缓冲器

The first layer is usually referred to by the PHP docs as the 'output buffer'. This layer of buffering only affects output to the bodyof the HTTP response, not the headers. You can turn on output buffering with ob_start(), and turn it off with ob_end_flush()or ob_end_clean(). You can also have all your scripts automatically start with output buffering on using the output_bufferingoption in php.ini.

PHP 文档通常将第一层称为“输出缓冲区”。这层缓冲只影响输出到HTTP 响应的正文,而不影响标头。您可以使用 开启输出缓冲ob_start(),使用ob_end_flush()或关闭它ob_end_clean()。您还可以使用output_bufferingphp.ini 中的选项让所有脚本自动启动输出缓冲。

The default value of this option for production versions of php.iniis 4096, which means that the first 4096 bytes of output will be buffered in the output buffer, at which point it will be flushed and output buffering is turned off.

php.ini 的生产版本的这个选项的默认值是 4096,这意味着输出的前 4096 个字节将缓冲在输出缓冲区中,此时它将被刷新并关闭输出缓冲。

You can disable this layer of buffering globally by setting output_bufferingto Offin your php.ini file (or using

您可以通过在 php.ini 文件中设置output_bufferingOff(或使用

php_flag "output_buffering" Off

in your Apache config, if you're using Apache). Alternatively, you can disable it for a single script by calling ob_end_clean()or ob_end_flush()at the start of the script.

在您的 Apache 配置中,如果您使用的是 Apache)。或者,您可以通过调用ob_end_clean()ob_end_flush()在脚本开头为单个脚本禁用它。

The write buffer, and the webserver buffer

写缓冲区和网络服务器缓冲区

Beyond the output buffer is what the PHP manual refers to as the 'write buffer', plus any buffering system your web server has. If you're using PHP with Apache through mod_php, and are not using mod_gzip, you can call flush()to flush these; with other backends, it might work too, although the manual is cagey about giving assurances:

除了输出缓冲区之外,还有 PHP 手册中称为“写入缓冲区”的内容,以及您的 Web 服务器拥有的任何缓冲系统。如果您通过 Apache 使用 PHP mod_php,并且没有使用mod_gzip,您可以调用flush()来刷新这些;对于其他后端,它也可能有效,尽管手册对提供保证持谨慎态度:

Description

void flush ( void )

Flushes the write buffers of PHP and whatever backend PHP is using (CGI, a web server, etc). This attempts to push current output all the way to the browser with a few caveats.

flush()may not be able to override the buffering scheme of your web server and it has no effect on any client-side buffering in the browser. It also doesn't affect PHP's userspace output buffering mechanism. This means you will have to call both ob_flush()and flush()to flush the ob output buffers if you are using those.

描述

void flush ( void )

刷新 PHP 的写入缓冲区以及 PHP 正在使用的任何后端(CGI、Web 服务器等)。这会尝试将当前输出一直推送到浏览器,但有一些警告。

flush()可能无法覆盖您的 Web 服务器的缓冲方案,并且它对浏览器中的任何客户端缓冲都没有影响。它也不影响 PHP 的用户空间输出缓冲机制。这意味着如果您正在使用它们,您将必须同时调用ob_flush()flush()来刷新 ob 输出缓冲区。

There are also a couple of ways you can make PHP automatically call flush()every time you echoanything (or do anything else that echoes output to the response body).

还有几种方法可以让 PHP 在flush()每次echo执行任何操作时自动调用(或执行其他任何将输出回显到响应主体的操作)。

The first is to call ob_implicit_flush(). Note that this function is deceptively named; given its ob_prefix, any reasonable person would expect that it would affect the 'output buffer', as do ob_start, ob_flushetc. However, this is not the case; ob_implicit_flush(), like flush(), affects the server-level output buffer and does not interact in any way with the output buffer controlled by the other ob_functions.

第一个是打电话ob_implicit_flush()。请注意,此函数的名称具有欺骗性;给定它的ob_前缀,任何有理智的人都会期望它会影响“输出缓冲区”,就像这样ob_startob_flush等等。然而,情况并非如此;ob_implicit_flush()和 一样flush(),会影响服务器级输出缓冲区,并且不会以任何方式与其他ob_函数控制的输出缓冲区交互。

The second is to globally enable implicit flushing by setting the implicit_flushflag to Onin your php.ini. This is equivalent to calling ob_implicit_flush()at the start of every script. Note that the manual advises against this, cryptically citing "serious performance implications", some of which I explore in this tangentially related answer.

第二个是通过在 php.ini 中设置implicit_flush标志来全局启用隐式刷新On。这相当于ob_implicit_flush()在每个脚本的开头调用。请注意,手册建议不要这样做,隐晦地引用了“严重的性能影响”,我在这个相关的答案中探讨了其中的一些问题

回答by DaveRandom

Rather than disabling output buffering, you can just call flush()after every read operation. This avoids having to mess with the server configuration and makes your script more portable.

您可以flush()在每次读取操作后调用,而不是禁用输出缓冲。这避免了必须弄乱服务器配置并使您的脚本更具可移植性。

回答by Yehosef

Output buffering can be layered and I've had cases where earlier code had made multiple levels. This will clear them all.

输出缓冲可以分层,我也遇到过早期代码已经创建多个级别的情况。这将清除它们。

while (ob_get_level()) ob_end_clean(); 
// or ob_end_flush() if you want the contents of the buffer.

回答by Binod Kalathil

We can give the below code in the .htaccess file for disabling output buffering in PHP

我们可以在 .htaccess 文件中给出以下代码来禁用 PHP 中的输出缓冲

php_flag "output_buffering" off

回答by Solomon Closson

I know this question is a bit old, but coming back to this question, you can turn off output buffering on a script to script basis, like this:

我知道这个问题有点老了,但是回到这个问题,您可以在脚本到脚本的基础上关闭输出缓冲,如下所示:

if (ob_get_level())
   ob_end_clean();

This should turn off all output buffering for any script that follows it.

这应该关闭它后面的任何脚本的所有输出缓冲。

回答by Aleksey Kuznetsov

For Windows IIS-servers none of solutions above doesn't works, because IIS manages its own buffers, which should be disabled too.

对于 Windows IIS 服务器,上述解决方案都不起作用,因为 IIS 管理自己的缓冲区,也应该禁用它。

Just add following web.configto your folder with PHP scripts to disable buffering. In example below used PHP v7.3.7, but you may replace the name to another version.

只需web.config使用 PHP 脚本将以下内容添加到您的文件夹中即可禁用缓冲。在下面的示例中使用了 PHP v7.3.7,但您可以将名称替换为其他版本。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <handlers>
            <clear />
            <add name="php-7.3.7" path="*.php" verb="GET,HEAD,POST" modules="FastCgiModule" scriptProcessor="C:\Program Files\PHP\v7.3\php-cgi.exe" resourceType="Either" requireAccess="Script" responseBufferLimit="0" />
        </handlers>
    </system.webServer>
</configuration>