请注意,如果您在 ob_start 和 ob_end_clean 或 ob_end_flush 之间更改 zlib 输出压缩设置,您将收到错误:ob_end_flush() 无法删除缓冲区 zlib 输出压缩
示例
<?php
ob_start();
$output = ob_get_contents();
ini_set('zlib.output_compression', '1');
ob_end_clean();
?>
在此示例中,ob_end_clean(); 将引发错误。
(PHP 4, PHP 5, PHP 7, PHP 8)
ob_end_clean — 清除(擦除)活动输出缓冲区的内容并将其关闭
此函数调用输出处理程序(使用PHP_OUTPUT_HANDLER_CLEAN
和 PHP_OUTPUT_HANDLER_FINAL
标志),丢弃其返回值,丢弃活动输出缓冲区的内容并关闭活动输出缓冲区。
如果没有使用PHP_OUTPUT_HANDLER_REMOVABLE
标志启动的活动输出缓冲区,则ob_end_clean() 将失败。
即使ob_end_clean() 是在没有PHP_OUTPUT_HANDLER_CLEANABLE
标志的情况下启动的,它也会丢弃活动输出缓冲区的内容。
此函数没有参数。
如果函数失败,它将生成一个E_NOTICE
。
以下示例展示了一种简单的方法来消除活动输出缓冲区的内容
示例 #1 ob_end_clean() 示例
<?php
ob_start();
echo '不会显示的文本.';
ob_end_clean();
?>
请注意,如果您在 ob_start 和 ob_end_clean 或 ob_end_flush 之间更改 zlib 输出压缩设置,您将收到错误:ob_end_flush() 无法删除缓冲区 zlib 输出压缩
示例
<?php
ob_start();
$output = ob_get_contents();
ini_set('zlib.output_compression', '1');
ob_end_clean();
?>
在此示例中,ob_end_clean(); 将引发错误。
请注意,如果您使用回调启动了 ob_start 调用,即使您使用 ob_end_clean 丢弃了 OB,该回调仍将被调用。
因为一旦设置了回调就无法从 OB 中删除它,所以阻止回调函数产生任何影响的唯一方法是执行以下操作:
<?php
$ignore_callback = false;
ob_start('my_callback');
...
if($need_to_abort) {
$ignore_callback = true;
ob_end_clean();
...
}
function my_callback(&$buffer) {
if($GLOBALS['ignore_callback']) {
return "";
}
...
}
?>
如果不确定输出缓冲区(已启用或未启用),
您可以尝试这些防护措施
<?php
while (ob_get_level() !== 0) {
ob_end_clean();
}
// 或
while (ob_get_length() !== false) {
ob_end_clean();
}
?>
您可能希望阻止脚本在客户端已拥有最新版本时执行。
您可以这样做
ob_start();
$mtime=filemtime($_SERVER["SCRIPT_FILENAME"])-date("Z");
$gmt_mtime = date('D, d M Y H:i:s', $mtime) . ' GMT';
$headers = getallheaders();
if(isset($headers["If-Modified-Since"])) {
if ($headers["If-Modified-Since"] == $gmt_mtime) {
header("HTTP/1.1 304 Not Modified");
ob_end_clean();
exit;
}
}
$size=ob_get_length();
header("Last-Modified: ".$gmt_mtime);
header("Content-Length: $size");
ob_end_flush();
您可以当然查询数据库或获取任何其他与脚本结果修改相关的日期,而不是将 If-Modified-Since-Header 与脚本最后修改日期进行比较。
例如,您可以使用此技术动态生成图像。如果用户通过 If-Modified-Since-Header 指出他已经拥有图像版本,则无需生成它并让服务器最终将其丢弃,因为服务器只有在那时才会解释 If-Modified-Since-Header。
这节省了服务器负载并缩短了响应时间。
关于之前的评论
您还可以依赖 ETag 并简单地使用 time()
<?php
$time = time();
$mins = 1;
if (isset($_SERVER['HTTP_IF_NONE_MATCH']) and str_replace('"', '', $_SERVER['HTTP_IF_NONE_MATCH'])+($mins*60) > $time)
{
header('HTTP/1.1 304 Not Modified');
exit();
}
else
{
header('ETag: "'.$time.'"');
}
echo 'Caching for ', $mins*60, 'secs<br/>', date('G:i:s');
?>
请注意,ob_end_clean()确实会丢弃头信息。
如果您想清除输出缓冲区,但不清除头信息(因为您使用的是 firephp 等),那么这就是解决方案
<?php
...
$headers = array();
if ( !headers_sent() ) {
$headers = apache_response_headers();
}
ob_end_clean();
ob_start();
if ( !empty( $headers ) ) {
foreach ( $headers as $name => $value ) {
header( "$name: $value" );
}
}
...
?>
我在 Web 应用程序中的通用异常处理程序中使用它,在那里我清除缓冲区(但不清除包含调试信息的 header),并使用 readfile() 发送 500 错误页面。
PHP编程愉快!
塔马斯。
请记住,mrfritz379 的示例(#49800)只是一个示例。您可以通过更有效的方式实现该示例的结果,而无需使用输出缓冲函数。
echo "<p>搜索运行中。请耐心等待……";
$output = "<p>文件列表:</p>\n";
if (is_dir($dir)) {
$dh = opendir($dir);
while (($fd = readdir($dh)) != false) {
echo " .";
$output .= $fd;
}
}
echo "</br>搜索完成!</p>\n";
echo $output;
除了John Smith的评论(#42939),即使调用ob_end_clean(),ob_gzhandler()也可能仍然将HTTP头“Content-Encoding”设置为“gzip”或“deflate”。这将在以下情况下导致问题:
1. 调用ob_gzhandler()。
2. 输出 "Some content"。
3. 调用ob_end_clean()。
4. 输出 "New content"。
在上述情况下,浏览器可能会接收到“Content-Encoding: gzip”HTTP头,并尝试解压缩未压缩的“New content”。浏览器将失败。
在以下情况下,此行为将不会被注意到:
1. 调用ob_gzhandler()。
2. 输出 "Some content"。
3. 调用ob_end_clean()。
4. 调用ob_gzhandler()。
5. 输出 "New content"。
这是因为第二个ob_gzhandler()将掩盖第一个ob_gzhandler()的缺失。
一个解决方案是编写一个包装器,就像John Smith那样,为ob_gzhandler()编写一个包装器。
如果在使用“register_shutdown_function”注册的函数中调用ob_end_clean,那就太晚了,任何缓冲区都已经被发送到客户端。
关于<geoff at spacevs dot com>所说的,“如果在使用'register_shutdown_function'注册的函数中调用ob_end_clean,那就太晚了,任何缓冲区都已经被发送到客户端”,我提出了一种解决方法。
<?php
function ClearBuffer($Buffer) {
return "";
}
function Shutdown() {
ob_start("ClearBuffer");
}
register_shutdown_function("Shutdown");
?>
这将清除所有输出缓冲区的内容。基本上它与“STDOUT > /dev/null”相同。
这可能已发布在其他地方,但我还没见过。
要在程序运行时运行进度指示器而无需输出输出缓冲区,可以使用以下方法:
echo "<p>搜索运行中。请耐心等待……";
$output = "<p>文件列表:</p>\n";
if (is_dir($dir)) {
$dh = opendir($dir);
while (($fd = readdir($dh)) != false) {
echo " .";
ob_start();
echo $fd;
$output .= ob_get_contents();
ob_end_clean();
}
}
echo "</br>搜索完成!</p>\n";
echo $output;
程序将继续打印“.”,而不打印文件列表。然后将打印“搜索完成”消息,然后是缓冲的文件列表。