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 标头,以详细讨论所涉及的事项。

添加笔记

用户贡献笔记 12 笔记

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

我正在使用 WAMPserver:PHP 5.2.6 和 Apache 2.2.8 在 Windows XP SP3 上。如果它对您的复制很重要,
我在 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,表示标头已发送,只有在输出开始发送到用户并且您不再可以发送任何其他标头时才会返回 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 年前
RE:antti at haapakangas dot net 的帖子

我更改了代码,以便在未设置 $_SERVER['HTTP_HOST'] 时使用 $_SERVER['SERVER_NAME']。$_SERVER['SERVER_NAME'] 不符合我的需求,但我认为回退到它是好的。我还修复了 meta refresh 行中的一个问题 - 它缺少 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
18 年前
请注意,在 IIS(或至少在 W2K 服务器附带的版本中),服务器似乎会进行一些缓冲,因此即使您输出某些内容或导致警告,headers_sent() 的值也可能是 false,因为标头尚未发送。

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

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

要测试它,请使用 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 />";
?>
[/code]

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

这在 php.ini 注释中有所说明
"输出缓冲允许您在发送主体内容之后发送标头行(包括 cookie),以牺牲稍微降低 PHP 输出层的速度为代价。"

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

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

即使 $numline 为 1,并且在 <?php
?>
之前和之后有任何字符。
然后,请将文件保存为无 BOM 格式,一切都会正常。
szczepan.krol[et]gmail[*]com
13 年前
这是一个函数,用于检查是否已发送任何其他输出
<?php

function output_send(){
if (!
headers_sent() && error_get_last()==NULL ) {
return
false;

}
return
true;
}
?>
Jase
15 年前
尝试描述标头行为的帖子数量正在变得令人讨厌

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

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

简单

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

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

此外,headers_sent() 适用于您尝试发送标头但输出缓冲区已清空的情况(例如,在 PHP 错误处理的情况下)。显然,如果缓冲区已清空,则发送标头将不起作用。
vasnake at gmail dot com
17 年前
在我的情况下,当我将 PHP 5.2.1 安装在 Apache 2.2.3(在 windows 2003 SP2 上)下的 CGI 模式下时,
函数 sent_headers() 始终返回 false。flash()、ob_end_flash() 等等,无论如何。
我认为,Apache 将所有 PHP 输出缓冲到 exit()
Terry
19 年前
对于习惯使用 Perl 的程序员来说,请注意,在 PHP 中发送相对的“Location:”标头会向浏览器发送重定向,这与 Perl 不同,Perl 会尝试使用内部子请求调用相对 URL 并将该页面返回给浏览器,而不会进行重定向。如果您想在 PHP 中执行相同的技巧,请使用 include() 或 virtual()。
antti at haapakangas dot net
20 年前
回复:php at fufachew dot com

这是一个很好的例子,说明如何在正确的方式(使用 absoluteURI)实现 Location 标头。我见过的 95% 的脚本都只使用 relativeURI,这是错误的。某些浏览器(例如 lynx)实际上会通知用户有关不完整的 Location 标头的消息。但是,使用 $_SERVER['SERVER_NAME'] 而不是 $_SERVER['HTTP_HOST'] 可能更安全。Host 标头是 HTTP/1.1 功能,如果您希望与 HTTP/1.0 实现具有互操作性,则不能依赖它。
loaded67 at hotmail dot com
16 年前
非常实用的函数!

使用 GD 时,我做了一些类似的事情

<?php
class image{

/**
* show
* 将图像发送到浏览器,如果标头未发送,则销毁资源。
* 使用 php 常量 IMAGETYPE_GIF、IMAGETYPE_JPEG、IMAGETYPE_PNG
*
* @final
* @static
* @access public
* @param resource $resource
* @param int $type
*/
final static public function show($resource, $type){
if(!
headers_sent()){
header('Cache-control: private');
switch(
$type){
case
IMAGETYPE_GIF : header('Content-type: image/gif');
header('Content-Disposition: filename='.basename(__FILE__).'.gif');
imagegif($resource);
break;
case
IMAGETYPE_JPEG : header('Content-type: image/jpeg');
header('Content-Disposition: filename='.basename(__FILE__).'.jpg');
imagejpeg($resource, NULL, 99);
break;
case
IMAGETYPE_PNG : header('Content-type: image/png');
header('Content-Disposition: filename='.basename(__FILE__).'.png');
imagepng($resource, NULL, 0, NULL);
break;
}
imagedestroy($resource);
exit;
}
}
}
?>

这样,如果您正在调试... 并刷新输出... 则不会得到已发送标头的无穷无尽的列表错误...

希望对您有所帮助... ;)
To Top