如何在 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
How to disable output buffering in PHP
提问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:
做两件事:
Disable the userspace output buffer, either...
Globally, by either...
- Turning off
output_buffering
in your php.ini, or Turning off
output_buffering
in your Apache config usingphp_flag "output_buffering" Off
- Turning off
or for just the script you care about, by either...
- calling
ob_end_flush()
, or - calling
ob_end_clean()
- calling
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 everyecho
statement or other statement that adds output to the response body
- calling
禁用用户空间输出缓冲区,或者...
在全球范围内,无论是...
output_buffering
在你的 php.ini 中关闭,或者output_buffering
在您的 Apache 配置中使用关闭php_flag "output_buffering" Off
或仅针对您关心的脚本,通过...
- 打电话
ob_end_flush()
, 或 - 打电话
ob_end_clean()
- 打电话
此外,通过以下任一方式,尽可能多地禁用服务器级输出缓冲区:
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_buffering
option in php.ini.
PHP 文档通常将第一层称为“输出缓冲区”。这层缓冲只影响输出到HTTP 响应的正文,而不影响标头。您可以使用 开启输出缓冲ob_start()
,使用ob_end_flush()
或关闭它ob_end_clean()
。您还可以使用output_buffering
php.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_buffering
to Off
in your php.ini file (or using
您可以通过在 php.ini 文件中设置output_buffering
为Off
(或使用
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 echo
anything (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_flush
etc. 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_start
,ob_flush
等等。然而,情况并非如此;ob_implicit_flush()
和 一样flush()
,会影响服务器级输出缓冲区,并且不会以任何方式与其他ob_
函数控制的输出缓冲区交互。
The second is to globally enable implicit flushing by setting the implicit_flush
flag to On
in 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
回答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.config
to 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>