php5.6获取文件名,关于http标头:PHP 5.6:headers_sent间歇性地返回true,空文件名和第0行...

我在我的PHP脚本(PHP 5.6,Apache 2.2)中间歇性地遇到了这个问题:

Warning: Cannot modify header information - headers already sent in /path/to/index.php on line 55

此警告没有我在其他问题中看到的"发送者"部分,所以我在违规的header()和setcookie()调用之前添加了此代码:

if (headers_sent($filename, $linenum)){

echo("Output buffer: #" . ob_get_contents() ."#");

echo"Headers already sent in $filename on line $linenum:";

print_r(headers_list());

}

这是问题发生时我得到的输出:

Output buffer: ##Headers already sent in on line 0:

Array (

[0] => X-Powered-By: PHP/5.6.23

[1] => Content-type: text/html; charset=UTF-8

)

(旁注:我在php.ini中将output_buffering设置为4096字节,所以这两个标题中的63个字符是否应该被缓存并等待更多,而不是过早发送?)

第一次启动包含Web服务器的Docker容器时出现此问题。之后,当我第一次访问我的网站时(可能是一两个小时),当我调用header()和setcookie()来记录用户或重定向到登录页面。

我已阅读并重读了一般"已发送标题"错误的答案,并且尽我所能,我已排除了这些可能的原因:

在我调用setcookie()或header()之前,HTML阻止或调用print,echo等

我的PHP标签之外的空格

物料清单

auto_prepend_file php.ini设置

gzip流编码 - 已安装zlib,但zlib.output_compression已关闭

重复extension= php.ini设置

答案提到了这一点

It's typically a PHP extension or php.ini setting if no error source is concretized.

所以,我现在正在查看我的扩展... get_loaded_extensions给了我一个51长度的数组,其中包含以下条目:

Core, date, ereg, libxml, openssl,

pcre, zlib, filter, hash, Reflection,

SPL, session, standard, apache2handler, bz2,

calendar, ctype, curl, dom, exif,

fileinfo, ftp, gd, gettext, iconv,

mysqlnd, PDO, Phar, posix, shmop,

SimpleXML, snmp, soap, sockets, sqlite3,

sysvmsg, sysvsem, sysvshm, tokenizer, xml,

xmlwriter, xsl, mysql, mysqli, pdo_mysql,

pdo_sqlite, wddx, xmlreader, json, zip, mhash

我没有使用所有这些,所以我打算通过并删除未使用的,并希望其中一个导致问题。

在最坏情况下,我会尝试碰撞output_buffering值或使用ob_start()和ob_end_flush()来查看文件的开头和结尾。我不知道为什么当我当前的output_buffering值为4096时,这会解决它,并且我知道这种解决方法带有自己的问题。

我在这里缺少什么 - 我还需要检查其他可能的原因吗?我应该尝试不同的PHP版本,或者在没有扩展的干净PHP安装上运行我的代码子集?

编辑:添加了ob_get_contents()调用和输出,以及有关能够通过旋转新的Docker容器一致地重现这一点的信息。删除了有关我的error_reporting值的信息;更改此项仅发现了always_populate_raw_post_data弃用通知,修复了对此处描述的问题没有影响。

请提供您设置的完整PHP文件代码并检查其中的标题。我想这是一个index.php?如果包含它,那么请提供包括索引文件在内的整个包含链源。

您是否在入口点脚本的最开头调用ob_start()?你的问题并不清楚,但没有ob_get_contents()将不起作用。另外,尝试使用var_dump(ob_get_contents())。我认为它比简单地回显值更好,因为它会说出字符串的长度。

你是如何确定修复always_populate_raw_post_data的东西并没有解决问题的?这当然是一个原因。另一方面 - 看成功加载的扩展程序无济于事;很可能是错误会被触发 - 无法加载扩展。如果它表示第0行,您可以确定它与代码无关,但在PHP本身初始化时会触发某些内容。

@GustavoStraube啊,我假设ob_get_contents()可以在php.ini中使用我的output_buffering设置。也许我从根本上误解了输出缓冲。

@ChristosLytras文件是封闭源文件,但如果有必要,我会看到发布它们。

@Narf我在php.ini中有这一行:always_populate_raw_post_data = -1。感谢关于扩展的提示;我将寻找方法来识别任何无法加载的扩展(但我??希望看到这种效果的日志)。

在取出一些未使用的遗留代码(包括require_once)调用所有遗留代码的文件后,此问题不再发生。它可能会在我最初观察到的"间歇"条件下重现,但我复制它的方法不再表现出这个问题。

我不知道为什么这似乎有帮助 - 删除的行完全在标签内,我检查了删除的文件,以查找标签,BOM和CRLF之外的空白区域。

我也不知道为什么这个问题是断断续续的;如果它与删除的代码或文件有关,那么它应该每次都发生。

感谢所有的评论和答案!

它可以是UTF8 BOM字符,或错误的换行符,不可打印的字符,错误的php关闭标记(我不使用它们,以防止终止问题)。即使没有这样的问题,即使你做了所有事情来阻止它,它也可以(并且将会)发生。问题可能出在FTP服务器,文本编辑器,错误的PHP配置,编码,错误的cgi配置上。为了防止所有这些我使用空输出缓冲区,只需在第一个php文件中启动buffreing

index.php文件:

if(version_compare(PHP_VERSION, '7.0.0') >= 0 || ob_get_level() < 1)

ob_start();

HtmlResponce.php:

ob_end_clean();

echo $this->getRenderedContent();

FileResponce.php:

ob_end_clean();

readfile($this->content);

在php5和php7输出缓冲有一些差异,也可以在php.ini中配置输出缓冲,并具有cgi和apache mod配置的差异。你不要在"默认"配置上进行中继。要处理警告消息,请使用set_error_handler(),您也可以使用ob_end_clean()去除它们

如果你开始新的项目看看symfony组件,我在我的CMS中使用了很多。这是你用奇怪的PHP漏洞防止不眠之夜的机会。

正如我在回答中所提到的,我排除了你所描述的常见问题(尽我所能),并且出于性能原因我想尽可能避免使用ob_start。 感谢您的建议; 如果/当我开始一个新的PHP项目时,我肯定会检查symfony组件。

在这种情况下没有性能松散。 输出前缓冲关闭。 没有双缓冲 - 没有增加内存使用量。

在做了一些研究之后,看起来我认为输出缓冲与性能优势相关是错误的。 对于巨大的输出(例如超过200 KB)来说这是一个坏主意,但这不适用于我的情况。 谢谢你让我直截了当!

我已经看到由于过去的行结束格式而出现问题。您是否将文件从一个操作系统环境移动到另一个?

有时隐藏的回车符(/ r)或其他特殊的空白字符可能会导致这种情况,但在文件中不可见。

谢谢你的提示; 我正在将文件从Windows移动到PHP并返回。 但是,我没有使用这里描述的几个方法找到任何CRLF:stackoverflow.com/q/73833/877682

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值