**这个问题的答案是社区的努力。编辑现有答案以改进此帖子。它目前不接受新的答案或互动。
在运行脚本时,我会遇到如下错误:警告:无法修改标头信息-标头已由(输出开始于/some/file)发送。php:12)在第23行的/some/file.php中错误消息中提到的行包含 header() 以及 setcookie() 电话。为什么会这样?如何修复?
header()
setcookie()
r7xajy2e1#
在进行任何输出之前,必须调用发送/修改http头的函数。摘要⇊ 否则调用失败:警告:无法修改标头信息-标头已发送(输出开始于script:line)一些修改http头的函数有: header /header_remove session_start /session_regenerate_id setcookie / setrawcookie 输出可以是:无意的:前空格 <?php 或之后 ?> utf-8字节顺序标记以前的错误消息或通知有意的: print , echo 以及其他产生输出的功能生的 <html> 前一节 <?php 代码。
header
session_start
setcookie
setrawcookie
<?php
?>
print
echo
<html>
为了理解为什么在输出之前必须发送头,有必要查看一个典型的http响应。php脚本主要生成html内容,但也会将一组http/cgi头传递给Web服务器:
HTTP/1.1 200 OK Powered-By: PHP/5.3.7 Vary: Accept-Encoding Content-Type: text/html; charset=utf-8 <html><head><title>PHP page output page</title></head> <body><h1>Content</h1> <p>Some more output follows...</p> and <a href="/"> <img src=internal-icon-delayed> </a>
页面/输出始终跟随标题。php必须首先将头文件传递给web服务器。它只能这样做一次。在双线中断之后,它再也不能修改它们了。当php收到第一个输出时( print , echo , <html> )它将刷新所有收集的标头。之后,它可以发送它想要的所有输出。但是发送更多的http头是不可能的。
这个 header() 警告包含查找问题原因的所有相关信息:警告:无法修改标头信息-标头已由发送(输出从/www/usr2345/htdocs/auth开始)。php:52)在/www/usr2345/htdocs/index.php第100行这里的“第100行”是指 header() 调用失败。括号内的“output started at”注解更为重要。它表示先前输出的来源。在这个例子中 auth.php 和线 52 . 这就是你必须寻找过早产出的地方。典型原因:
auth.php
52
有意输出 print 以及 echo 语句将终止发送http头的机会。必须重新构造应用程序流以避免这种情况。使用函数和模板方案。确保 header() 调用发生在消息写出之前。产生输出的函数包括 print , echo , printf ,vprintf trigger_error , ob_flush , ob_end_flush , var_dump ,print_r readfile , passthru , flush , imagepng , imagejpeg 以及用户定义的函数。
printf
trigger_error
ob_flush
ob_end_flush
var_dump
readfile
passthru
flush
imagepng
imagejpeg
中未分析的html节 .php 文件也可以直接输出。脚本条件将触发 header() 在任何原始数据之前必须记录调用 <html> 阻碍。
.php
<!DOCTYPE html> <?php // Too late for headers already.
使用模板方案将处理与输出逻辑分开。将表单处理代码放在脚本上。使用临时字符串变量延迟消息。实际的输出逻辑和混合的html输出应该紧跟其后。
如果警告是指行中的输出 1 ,则在开始之前主要是前导空格、文本或html <?php 代币。
1
<?php # There's a SINGLE space/newline before <? - Which already seals it.
类似地,附加脚本或脚本节也会发生这种情况:
?> <?php
php实际上会在关闭标记之后吃掉一个换行符。但它不会补偿多个换行符、制表符或空格移到这样的间隙中。
换行符和空格本身就是一个问题。但也有“看不见的”字符序列可能导致这种情况。最著名的是utf-8bom(字节顺序标记),大多数文本编辑器都不显示它。是字节序列 EF BB BF ,这对于utf-8编码的文档是可选的和冗余的。然而,php必须将其视为原始输出。它可能表现为  在输出中(如果客户机将文档解释为拉丁语-1)或类似的“垃圾”。尤其是图形编辑器和基于java的ide对它的存在一无所知。他们没有将其可视化(受unicode标准的约束)。但是,大多数程序员和控制台编辑器会:在那里,很容易在早期就认识到这个问题。其他编辑器可能会在文件/设置菜单中识别它的存在(windows上的notepad++可以识别并解决这个问题),另一个检查boms存在的选项是求助于hexeditor。on*nix系统 hexdump 如果不是简化审核这些问题和其他问题的图形变体,则通常可用:一个简单的解决方法是将文本编辑器设置为将文件保存为“utf-8(无bom)”或类似的术语。通常新来者会以其他方式创建新的文件,并将以前的代码复制粘贴回原处。
EF BB BF

hexdump
也有自动工具来检查和重写文本文件( sed / awk 或者 recode ). 特别是对于php,有 phptags 标签更整洁。它将关闭和打开标记重写为长格式和短格式,但也可以轻松修复前导和尾随空格、unicode和utf-x bom问题:
sed
awk
recode
phptags
phptags --whitespace *.php
在整个include或project目录中使用是明智的。
如果错误源被称为关闭后 ?> 然后这就是一些空白或原始文本被写出来的地方。php结束标记此时不终止脚本执行。之后的任何文本/空格字符仍将作为页面内容写出。人们通常建议,尤其是对新来者来说 ?> 应该省略php close标记。这就避免了一小部分这种情况(相当普遍 include()d 脚本是罪魁祸首。)
include()d
如果没有具体化错误源,则通常是php扩展或php.ini设置。偶尔是 gzip 流编码设置或 ob_gzhandler .但它也可能是双重负载的 extension= 生成隐式php启动/警告消息的模块。
gzip
ob_gzhandler
extension=
如果另一个php语句或表达式导致打印出警告消息或通知,这也算作过早输出。在这种情况下,您需要避免错误,延迟语句的执行,或者使用。 isset() 或者 @() -任何一个都不会妨碍以后的调试。
isset()
@()
如果你有 error_reporting 或者 display_errors 根据禁用 php.ini ,则不会显示任何警告。但是忽略错误并不能解决问题。过早输出后仍无法发送标头。那什么时候 header("Location: ...") 自动重定向失败非常明智的做法是探测警告。在调用脚本顶部使用两个简单命令重新启用它们:
error_reporting
display_errors
php.ini
header("Location: ...")
error_reporting(E_ALL); ini_set("display_errors", 1);
或者 set_error_handler("var_dump"); 如果一切都失败了。说到重定向头,您应该经常对最终代码路径使用这样的习惯用法:
set_error_handler("var_dump");
exit(header("Location: /finished.html"));
更可取的是一个实用函数,它在 header() 失败。
phps输出缓冲是缓解这个问题的一种解决方法。它通常工作可靠,但不应取代正确的应用程序结构和将输出与控制逻辑分离。它的实际目的是最小化到web服务器的分块传输。这个 output_buffering= 尽管如此,设置还是有帮助的。在php.ini或via.htaccess甚至在现代fpm/fastcgi设置中的.user.ini中配置它。启用它将允许php缓冲输出,而不是立即将其传递给web服务器。因此,php可以聚合http头。它也可以通过呼叫 ob_start(); 在调用脚本顶部。然而,由于多种原因,它的可靠性较低:即使 <?php ob_start(); ?> 开始第一个脚本时,空格或bom可能会被洗牌,使其无效。它可以隐藏html输出的空白。但是一旦应用程序逻辑尝试发送二进制内容(例如生成的图像),缓冲的无关输出就成为一个问题(必要的 ob_clean() 作为进一步的解决办法。)缓冲区的大小是有限的,当保留为默认值时,很容易溢出。而且这种情况也不少见,发生时很难追踪。因此,这两种方法都可能变得不可靠—特别是在开发设置和/或生产服务器之间切换时。这就是为什么输出缓冲被广泛地认为只是一个拐杖/严格地说是一个解决方法。另请参见手册中的基本用法示例,有关更多优缺点:什么是输出缓冲?为什么在php中使用输出缓冲?使用输出缓冲被认为是一种不好的做法吗?输出缓冲作为“已发送头”的正确解决方案的用例
output_buffering=
ob_start();
<?php ob_start(); ?>
ob_clean()
如果之前没有收到headers警告,那么输出缓冲php.ini设置已经更改。它可能在当前/新服务器上未配置。
你可以随时使用 headers_sent() 调查是否还有可能。。。发送邮件头。这对于有条件地打印信息或应用其他回退逻辑非常有用。
headers_sent()
if (headers_sent()) { die("Redirect failed. Please click on this link: <a href=...>"); } else{ exit(header("Location: /user.php")); }
有用的后备解决方法包括:
如果您的应用程序在结构上很难修复,那么允许重定向的一种简单(但有些不专业)方法是注入一个html <meta> 标签。重定向可以通过以下方式实现:
<meta>
<meta http-equiv="Location" content="http://example.com/">
或短暂延迟:
<meta http-equiv="Refresh" content="2; url=../target.html">
这会导致在过去使用时产生无效的html <head> 部分。大多数浏览器仍然接受它。
<head>
作为一个
1条答案
按热度按时间r7xajy2e1#
发送头之前没有输出!
在进行任何输出之前,必须调用发送/修改http头的函数。摘要⇊ 否则调用失败:
警告:无法修改标头信息-标头已发送(输出开始于script:line)
一些修改http头的函数有:
header
/header_remove
session_start
/session_regenerate_id
setcookie
/setrawcookie
输出可以是:无意的:
前空格
<?php
或之后?>
utf-8字节顺序标记以前的错误消息或通知
有意的:
print
,echo
以及其他产生输出的功能生的
<html>
前一节<?php
代码。为什么会这样?
为了理解为什么在输出之前必须发送头,有必要查看一个典型的http响应。php脚本主要生成html内容,但也会将一组http/cgi头传递给Web服务器:
页面/输出始终跟随标题。php必须首先将头文件传递给web服务器。它只能这样做一次。在双线中断之后,它再也不能修改它们了。
当php收到第一个输出时(
print
,echo
,<html>
)它将刷新所有收集的标头。之后,它可以发送它想要的所有输出。但是发送更多的http头是不可能的。如何找出过早输出发生在哪里?
这个
header()
警告包含查找问题原因的所有相关信息:警告:无法修改标头信息-标头已由发送(输出从/www/usr2345/htdocs/auth开始)。php:52)在/www/usr2345/htdocs/index.php第100行
这里的“第100行”是指
header()
调用失败。括号内的“output started at”注解更为重要。它表示先前输出的来源。在这个例子中
auth.php
和线52
. 这就是你必须寻找过早产出的地方。典型原因:
打印,回音
有意输出
print
以及echo
语句将终止发送http头的机会。必须重新构造应用程序流以避免这种情况。使用函数和模板方案。确保header()
调用发生在消息写出之前。产生输出的函数包括
print
,echo
,printf
,vprintf
trigger_error
,ob_flush
,ob_end_flush
,var_dump
,print_r
readfile
,passthru
,flush
,imagepng
,imagejpeg
以及用户定义的函数。原始html区域
中未分析的html节
.php
文件也可以直接输出。脚本条件将触发header()
在任何原始数据之前必须记录调用<html>
阻碍。使用模板方案将处理与输出逻辑分开。
将表单处理代码放在脚本上。
使用临时字符串变量延迟消息。
实际的输出逻辑和混合的html输出应该紧跟其后。
“script.php line 1”警告前面的空格
如果警告是指行中的输出
1
,则在开始之前主要是前导空格、文本或html<?php
代币。类似地,附加脚本或脚本节也会发生这种情况:
php实际上会在关闭标记之后吃掉一个换行符。但它不会补偿多个换行符、制表符或空格移到这样的间隙中。
utf-8物料清单
换行符和空格本身就是一个问题。但也有“看不见的”字符序列可能导致这种情况。最著名的是utf-8bom(字节顺序标记),大多数文本编辑器都不显示它。是字节序列
EF BB BF
,这对于utf-8编码的文档是可选的和冗余的。然而,php必须将其视为原始输出。它可能表现为
在输出中(如果客户机将文档解释为拉丁语-1)或类似的“垃圾”。尤其是图形编辑器和基于java的ide对它的存在一无所知。他们没有将其可视化(受unicode标准的约束)。但是,大多数程序员和控制台编辑器会:
在那里,很容易在早期就认识到这个问题。其他编辑器可能会在文件/设置菜单中识别它的存在(windows上的notepad++可以识别并解决这个问题),另一个检查boms存在的选项是求助于hexeditor。on*nix系统
hexdump
如果不是简化审核这些问题和其他问题的图形变体,则通常可用:一个简单的解决方法是将文本编辑器设置为将文件保存为“utf-8(无bom)”或类似的术语。通常新来者会以其他方式创建新的文件,并将以前的代码复制粘贴回原处。
校正实用程序
也有自动工具来检查和重写文本文件(
sed
/awk
或者recode
). 特别是对于php,有phptags
标签更整洁。它将关闭和打开标记重写为长格式和短格式,但也可以轻松修复前导和尾随空格、unicode和utf-x bom问题:在整个include或project目录中使用是明智的。
后面有空格?>
如果错误源被称为关闭后
?>
然后这就是一些空白或原始文本被写出来的地方。php结束标记此时不终止脚本执行。之后的任何文本/空格字符仍将作为页面内容写出。人们通常建议,尤其是对新来者来说
?>
应该省略php close标记。这就避免了一小部分这种情况(相当普遍include()d
脚本是罪魁祸首。)错误源被称为“第0行未知”
如果没有具体化错误源,则通常是php扩展或php.ini设置。
偶尔是
gzip
流编码设置或ob_gzhandler
.但它也可能是双重负载的
extension=
生成隐式php启动/警告消息的模块。前面的错误消息
如果另一个php语句或表达式导致打印出警告消息或通知,这也算作过早输出。
在这种情况下,您需要避免错误,延迟语句的执行,或者使用。
isset()
或者@()
-任何一个都不会妨碍以后的调试。无错误信息
如果你有
error_reporting
或者display_errors
根据禁用php.ini
,则不会显示任何警告。但是忽略错误并不能解决问题。过早输出后仍无法发送标头。那什么时候
header("Location: ...")
自动重定向失败非常明智的做法是探测警告。在调用脚本顶部使用两个简单命令重新启用它们:或者
set_error_handler("var_dump");
如果一切都失败了。说到重定向头,您应该经常对最终代码路径使用这样的习惯用法:
更可取的是一个实用函数,它在
header()
失败。作为解决方法的输出缓冲
phps输出缓冲是缓解这个问题的一种解决方法。它通常工作可靠,但不应取代正确的应用程序结构和将输出与控制逻辑分离。它的实际目的是最小化到web服务器的分块传输。
这个
output_buffering=
尽管如此,设置还是有帮助的。在php.ini或via.htaccess甚至在现代fpm/fastcgi设置中的.user.ini中配置它。启用它将允许php缓冲输出,而不是立即将其传递给web服务器。因此,php可以聚合http头。
它也可以通过呼叫
ob_start();
在调用脚本顶部。然而,由于多种原因,它的可靠性较低:即使
<?php ob_start(); ?>
开始第一个脚本时,空格或bom可能会被洗牌,使其无效。它可以隐藏html输出的空白。但是一旦应用程序逻辑尝试发送二进制内容(例如生成的图像),缓冲的无关输出就成为一个问题(必要的
ob_clean()
作为进一步的解决办法。)缓冲区的大小是有限的,当保留为默认值时,很容易溢出。而且这种情况也不少见,发生时很难追踪。
因此,这两种方法都可能变得不可靠—特别是在开发设置和/或生产服务器之间切换时。这就是为什么输出缓冲被广泛地认为只是一个拐杖/严格地说是一个解决方法。
另请参见手册中的基本用法示例,有关更多优缺点:
什么是输出缓冲?
为什么在php中使用输出缓冲?
使用输出缓冲被认为是一种不好的做法吗?
输出缓冲作为“已发送头”的正确解决方案的用例
但在另一台服务器上成功了!?
如果之前没有收到headers警告,那么输出缓冲php.ini设置已经更改。它可能在当前/新服务器上未配置。
正在检查邮件头\u sent()
你可以随时使用
headers_sent()
调查是否还有可能。。。发送邮件头。这对于有条件地打印信息或应用其他回退逻辑非常有用。有用的后备解决方法包括:
html标记
如果您的应用程序在结构上很难修复,那么允许重定向的一种简单(但有些不专业)方法是注入一个html
<meta>
标签。重定向可以通过以下方式实现:或短暂延迟:
这会导致在过去使用时产生无效的html
<head>
部分。大多数浏览器仍然接受它。javascript重定向
作为一个