PHP:关闭输出流


PHP: close output stream

是否可以关闭PHP脚本的输出流?我有一个脚本需要做一些后处理,但在后处理期间和之后,它不会再向客户端发送任何数据,所以我想在后处理之前关闭连接。

编辑:在我的应用程序中,我有一个缓存,需要不时重建。但是,我不想降低用户的速度。我想要的是在脚本结束时确定是否需要重建缓存。所以我想先关闭输出流,这样用户就可以获得它的数据,然后我想重建缓存。这样做并不重要,但我认为最好先关闭连接,这样,如果需要很长时间,用户就不会注意到缓存正在重建。

更新

处理这种情况的方法是输出缓冲和适当的HTTP头的组合。

来自HTTP/1.1规范第14.10节:

HTTP/1.1定义了发件人的"关闭"连接选项发出信号,表示连接将在完成后关闭回答

因此,如果我们除了传递连接:关闭之外,还传递HTTP内容长度标头,则浏览器知道在收到指定的响应长度后关闭连接:

  1. 缓冲所有脚本输出,以便保留发送标头的能力
  2. 一旦获得了完整的输出数据,就向客户端发送适当的标头
  3. 继续处理。。。但不要尝试发送输出,否则会收到错误,因为已经发送了标头

此外,要小心,因为如果处理过多,可能会在web服务器SAPI中遇到脚本执行时间限制。最后,您应该告诉PHP使用ignore_user_abort()忽略这个特定脚本中的"用户中止",因为浏览器会因为您所做的操作而关闭连接,并且您希望PHP继续处理。

<?php
ignore_user_abort();
ob_start();
// do stuff, generate output
// get size of the content
$length = ob_get_length();
// tell client to close the connection after $length bytes received
header('Connection: close');
header("Content-Length: $length");
// flush all output
ob_end_flush();
ob_flush();
flush();
// close session if you have one ...
// continue your processing tasks ...
?>

您可以查看关于连接处理docs的PHP手册部分。

或者,为什么不启动输出缓冲?然后你可以捕获所有将要发送的输出,然后再决定你是否真的想用它做任何事情

<?php
echo 'before output buffering';
ob_start();
echo 'after output buffering';
$output = ob_get_contents();
// script's only output to this point will be 'before output buffering'
// I changed my mind, send the output ...
ob_end_flush();
?>

fclose(STDOUT):http://php.net/manual/en/features.commandline.io-streams.php

我没有足够的声誉发表评论,但我想在@rdlowrey回答中分享这一点gzip可能是个问题。

如果启用了gzip,则Transfer encoding标头始终设置为chunked(即使您尝试使用header("Transfer-encoding: none");更改它),因此它不会发送Content Length标题。

我可以解决这个问题的方法是使用之前的下一个:

<?
@ini_set('zlib.output_compression', 'Off');
@ini_set('output_buffering', 'Off');
@ini_set('output_handler', '');
@apache_setenv('no-gzip', 1);
?>

然后是解决方案:

<?
ignore_user_abort();
ob_start();
// do stuff, generate output
// get size of the content
$length = ob_get_length();
// tell client to close the connection after $length bytes received
header('Connection: close');
header("Content-Length: $length");
// flush all output
ob_end_flush();
flush();
// close session if you have one ...
// continue your processing tasks ...
?>