PHP Conference Japan 2024

headers_sent

(PHP 4, PHP 5, PHP 7, PHP 8)

headers_sent检查是否或在何处已发送标头

描述

headers_sent(string &$filename = null, int &$line = null): bool

检查是否或在何处已发送标头。

一旦标头块已发送,就不能再使用 header() 函数添加任何其他标头行。使用此函数,您至少可以防止出现与 HTTP 标头相关的错误消息。另一个选择是使用 输出缓冲

参数

filename

如果设置了可选的 filenameline 参数,headers_sent() 将把输出开始的 PHP 源文件名和行号放入 filenameline 变量中。

注意:

如果在执行 PHP 源文件之前已开始输出(例如由于启动错误),则 filename 参数将设置为空字符串。

line

输出开始的行号。

返回值

headers_sent() 如果尚未发送任何 HTTP 标头,则返回 false,否则返回 true

示例

示例 #1 使用 headers_sent() 的示例

<?php

// 如果没有发送标头,则发送一个
if (!headers_sent()) {
header('Location: http://www.example.com/');
exit;
}

// 使用可选的文件和行参数的示例
// 注意,$filename 和 $linenum 传递进来以供以后使用。
// 不要事先为它们赋值。
if (!headers_sent($filename, $linenum)) {
header('Location: http://www.example.com/');
exit;

// 你很可能会在这里触发错误。
} else {

echo
"标头已在 $filename$linenum 行发送\n" .
"目前无法重定向,请点击此 <a " .
"href=\"http://www.example.com\">链接</a> 代替\n";
exit;
}

?>

注释

注意:

只有在使用支持它们的 SAPI 时,才能访问和输出标头。

参见

  • ob_start() - 打开输出缓冲
  • trigger_error() - 生成用户级错误/警告/通知消息
  • headers_list() - 返回已发送(或准备发送)的响应标头列表
  • header() - 发送原始 HTTP 标头 有关所涉及问题的更详细讨论。

添加注释

用户贡献的注释 7 条注释

yesmarklapointe at hotmail dot com
16 年前
我难以理解所涉及的概念。这是我的困境和我得出的结论,以防万一它们可以帮助其他人

我正在使用 WAMPserver:Windows XP SP3 上的 PHP 5.2.6 和 Apache 2.2.8。如果这对您的复制很重要,
我在 WAMPserver 中找到了两个 php.ini 文件,其中 output_buffering 已设置为 4096。我将它们更改为 OFF 以进行此测试。

以下是如何复制我遇到的情况:使用 IE 7.0 转到工具…显示 ieHTTPheaders…并重复运行以下脚本并观察会发生什么

<?php
header
( 'Expires: Mon, 26 Jul 1998 05:00:00 GMT' );
//var_dump(headers_sent());
//print("whatever");
//flush();
//echo "whatever";
var_dump(headers_sent());
?>

结果:headers_sent() 函数的最终 var_dump 将
始终返回 FALSE,除非取消其上方任何一行或多行的注释。取消注释这些语句允许将输出发送给用户,而不仅仅是发送到他们的浏览器,之后最终的 var_dump 将返回 TRUE。令我困惑的是,即使所有输出行都被注释掉,ieHTTPheaders 工具也会显示标头正在发送到用户的浏览器。那么在这种情况下,headers_sent() 为什么返回 FALSE?因为您可以继续发送其他标头。headers_sent 函数旨在提醒人们何时无法再发送标头。我的测试表明,除非在标头之后还发送其他输出,否则它不会返回 true,从而表示“标头已发送并以用户输出结束。现在您无法再发送任何标头了”。

其他人在一个(错误的)错误报告中解决了这个问题:http://bugs.php.net/bug.php?id=30264
以下是专业人员回复的相关部分
“当您使用压缩时,整个页面都缓冲在内存中,直到请求结束。因此,您可以随时发送标头,因为当您打印它时,实际上没有任何数据被发送到用户。在 PHP 实际决定将任何页面输出发送给用户之前,您仍然可以发送其他标头,这就是 headers_sent() 函数返回 false 的原因。只有当输出开始发送给用户并且您不再可以发送任何其他标头时,它才会返回 true,表示标头已发送。”

总而言之,我的观点是,仅发送到浏览器的标头(其他标头可以跟在其后)与发送标头并以用户输出结束的标头之间存在差异。该函数应该被赋予更清晰的名称,例如 headers_concluded()。
Jakob B.
18 年前
<?php
function redirect($filename) {
if (!
headers_sent())
header('Location: '.$filename);
else {
echo
'<script type="text/javascript">';
echo
'window.location.href="'.$filename.'";';
echo
'</script>';
echo
'<noscript>';
echo
'<meta http-equiv="refresh" content="0;url='.$filename.'" />';
echo
'</noscript>';
}
}
redirect('http://www.google.com');
?>
php at fufachew dot REMOVEME dot com
20 年前
关于 antti at haapakangas dot net 的帖子

我已经更改了代码,以便如果未设置 $_SERVER['HTTP_HOST'],则使用 $_SERVER['SERVER_NAME']。$_SERVER['SERVER_NAME'] 不符合我的需求,但我认为回退到它是个好主意。我还修复了元刷新行中的一个问题 - 它缺少 content 属性的“url=”部分。

<?php
function server_url()
{
$proto = "http" .
((isset(
$_SERVER['HTTPS']) && $_SERVER['HTTPS'] == "on") ? "s" : "") . "://";
$server = isset($_SERVER['HTTP_HOST']) ?
$_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'];
return
$proto . $server;
}

function
redirect_rel($relative_url)
{
$url = server_url() . dirname($_SERVER['PHP_SELF']) . "/" . $relative_url;
if (!
headers_sent())
{
header("Location: $url");
}
else
{
echo
"<meta http-equiv=\"refresh\" content=\"0;url=$url\">\r\n";
}
}
?>
trevize (shtrudel) gmail.com
19年前
请注意,在IIS(至少在W2K服务器附带的版本中),服务器似乎进行了一些缓冲,因此即使您输出某些内容或导致警告,`headers_sent()` 的值也可能为false,因为标头尚未发送。

因此,这不是知道脚本中是否遇到警告的安全方法。
collectours at free dot fr
17年前
回复 K.Tomono 和 alexrussell101 at gmail dot com

是的,
即使您使用print()或header()向输出发送了一些内容,如果在您的php.ini中output_buffering不同于Off,并且您发送的内容长度不超过output_buffering的大小,`headers_sent()` 也会返回false。

要测试它,请使用php.ini中的这些值尝试以下代码:
1) output_buffering=32
2) output_buffering = 4096

[代码]
<?php
echo "Yo<br />";
echo
"Sent:",headers_sent(),"<br />";
echo
"enough text to feed the buffer until it overflows ;-)<br />";
echo
"Sent:",headers_sent(),"<br />";
?>
[/代码]

然后设置
3) output_buffering = Off
并尝试此代码:
[代码]
<?php
echo "Yo<br />";
echo
"Sent:",headers_sent(),"<br />";
?>
[/代码]
这次将无条件地说标头已发送。

这在php.ini注释中有所提及:
"输出缓冲允许您即使在发送正文内容后也能发送标头行(包括cookie),代价是稍微减慢PHP的输出层。"

注意:这与implicit_flush调整完全无关。
rojasredes at gmail dot com
6年前
记住以不带BOM的UTF-8格式保存源代码文件*.php。
如果使用UTF-8 BOM保存,则以下代码始终返回“true”

<?php
if headers_sent($source,$numline)
{
die(
"true");
}
else
{
die(
"false");
}
?>

即使$numline为1,并且在<?php
?>
之前和之后有任何字符。
不带BOM保存文件,一切都会正常。
Jase
15年前
试图描述标头行为的帖子数量越来越多,这正变得令人厌烦。

标头首先出现在发送到用户浏览器的数据中。

如果已使用header()函数调用标头,但尚未向输出缓冲区发送数据(使用echo,readfile等),则标头在脚本执行结束时发送,否则在缓冲区达到其限制并清空时发送。

很简单。

这意味着如果没有任何内容发送到输出缓冲区,`headers_sent()` 将返回false,因为标头将在脚本结束时发送。

这也不是错误,这是预期的行为。将标头保留到强制发送它们是一个好主意,因为可以采取某些措施,例如防止元注入等(header()中的选项用于替换尚未发送的标头)。

此外,`headers_sent()` 适用于您尝试发送标头但输出缓冲区已被清空的情况(例如在php错误处理中)。显然,如果缓冲区已清空,则发送标头将不起作用。
To Top