php 错误Cannot modify header information – headers already sent by

PHP 的输出缓存

先明确一下PHP的输出顺序
1.打开了php输出缓存: echo,print -> php output_buffring -> server buffering -> browser buffering -> browser display
2.未打开php输出缓存: echo,print -> server buffering -> browser buffering -> browser display

另外浏览器的输出缓存:IE为256Bytes, Chrome与FireFox为1000Bytes,只有输出数据达到了这个长度或者脚本结束浏览器才会将数据输出在页面上

buffer
buffer是 一个内存地址空间,Linux系统默认大小一般为4096(4kb),即一个内存页。主要用于存储速度不同步的设备或者优先级不同的设备之间传办理数据的 区域。通过buffer,可以使进程这间的相互等待变少。这里说一个通俗一点的例子,你打开文本编辑器编辑一个文件的时候,你每输入一个字符,操作系统并 不会立即把这个字符直接写入到磁盘,而是先写入到buffer,当写满了一个buffer的时候,才会把buffer中的数据写入磁盘,当然当调用内核函 数flush()的时候,强制要求把buffer中的脏数据写回磁盘。

同样的道理,当执行echo,print的时候,输出并没有立即通过server传给客户端浏览器显示, 而是将数据写入php buffer。php output_buffering机制,意味在server buffer之前,建立了一新的队列,数据必须经过该队列。当一个php buffer写满的时候,脚本进程会将php buffer中的输出数据交给系统内核交由server传给浏览器显示。所以,数据会依次写到这几个地方:echo/print -> php buffer -> server buffer -> browser

php output_buffering
默 认情况下,php buffer是开启的,而且该buffer默认值是4096,即4kb。你可以通过在php.ini配置文件中找到output_buffering配 置.当echo,print等输出用户数据的时候,输出数据都会写入到php output_buffering中,直到output_buffering写满,会将这些数据通过server传送给浏览器显示。你也可以通过 ob_start()手动激活php output_buffering机制,使得即便输出超过了4kb数据,也不真的把数据交给server传给浏览器,因为ob_start()将php
buffer空间设置到了足够大。只有直到脚本结束,或者调用ob_end_flush函数,才会把数据发送给客户端浏览器。
我们将php.ini 中的 output_buffering 设置成为On就表明设置了无限大的buffer空间。

假设我们设置的output_buffering 为Off 那么php代码:

echo "php";
header("content-type:text/html;charset='utf-8'");
echo 'ok';

是会出错的提示:Cannot modify header information - headers already sent by

根据以上内容分析原因:

php在echo ‘php'时已经向浏览器发送一个头信息,当再出现header("content-type:text/html;charset='utf-8'");
又看到一个头信息,这时已经打回了上面的头信息,无法更改便出错了。

解决上述问题可以通过以下方法解决:
1. 检查是否有在header 输出之前输出的内容
2. 使用
<?php ob_start(); ?>
... HTML codes ...
<?php
... PHP codes ...
header ("Location: ....");
ob_end_flush();
?>方法解决
3. error_reporting(E_ERROR | E_PARSE); 这里不要显示E_WARNING即可
不显示错误(但是错误还在)
4. 有权限编辑php.ini 则
设置 output_buffering =为on或者具体大小。
5. 将该文件转为UTF-8 without BOM编码的文件

今天修改magento代码 提交到服务器上的时候在log文件中发现错误:
 HEADERS ALREADY SENT...
检查发现错误记录在文件
appcodecoreMageCoreControllerResponseHttp.php

if (!$this->canSendHeaders()) {
            Mage::log('HEADERS ALREADY SENT: '.mageDebugBacktrace(true, true, true));
            return $this;
        }

追踪函数canSendHeaders
在libZendControllerResponseAbstract.php中

 public function canSendHeaders($throw = false)
    {
        $ok = headers_sent($file, $line);
        if ($ok && $throw && $this->headersSentThrowsException) {
            #require_once 'Zend/Controller/Response/Exception.php';
            throw new Zend_Controller_Response_Exception('Cannot send headers; headers already sent in ' . $file . ', line ' . $line);
        }

        return !$ok;
    }

可以看到使用了 headers_sent函数。 我们也可以通过这个函数配合get_include_files 找出错误出现在那里
其实这个错误和php 提示错误Cannot modify header information - headers already sent by
应该是一个问题
我找到php.ini 修改
output_buffering =4096 为On 错误解决了,
但是这里的问题是我的 output_buffering 是打开的但是还发生这种错误?难道大小不够
我索性尝试给了1024000即1M 结果错误也没有。
那么我的猜测是:(知道的麻烦帮下忙告诉下,具体原因。拜谢!)
输出的内容比较大,php 缓冲区大小是4kb 那么写满了以后要输出到browser, 但是在这4kb后面
还有头部信息的修改例如header() 函数但是头信息已经发送了,于是报错。而如果修改buffer大小
为On 表示无限大则错误消失。

-----------------------------------------------------------------是这样吗?---------------------------------------------------------------------

---------------------------------------------------------------- 更新-----------------------------------------------------------------------------

正解在这里 ("▔□▔)/

http://blog.csdn.net/m0sh1/article/details/46124089

参考资料:

http://blog.csdn.net/besily/article/details/5396268
http://www.jb51.net/article/38363.htm
http://www.jb51.net/article/39774.htm
http://www.jb51.net/article/38365.htm
http://stackoverflow.com/questions/4670031/magento-debug-headers-already-sent-error

此文章通过 python 爬虫创建,原文是自己的csdn 地址: php 错误Cannot modify header information - headers already sent by



发表评论

电子邮件地址不会被公开。