讨论事项:
- 标头
- 这些是什么?
- PHP与标头有什么关系?
- 为什么只能在任何输出之前发送它们?
- 常见原因
- 调用一种函数,该函数在通过print(),echo()等发送输出后,将标头信息发送给浏览器。
- 调用将标头信息发送到HTML文件中的浏览器的函数
- 不常见/难以定位(最烦人)的原因
- 打开PHP解析器之前的空白(<?php)
- 物料清单
- 解决方案
- 将标题发送功能移到任何输出之前
- 输出缓冲
本文是一系列(希望如此)许多文章的第一期。
由PHP专家在bytes.com上撰写的这些文章希望涵盖PHP新手经常以清晰简洁的方式遇到的常见的陷阱,并随后在bytes.com论坛上提出。
1.已发送标题警告:无法修改标头信息-第14行的C:\ xampp \ htdocs \ site \ php \ index.php中已经发送过的标头(输出从C:\ xampp \ htdocs \ site \ php \ index.php:1开始)
- 常见错误消息。标头 是什么?
当您给朋友写一封信时,在将该信发送给邮局之前,您需要在信封的正面提供一组详细信息:姓名,地址等。然后,邮局就可以使用该地址来向信到正确的位置。 是你吗
如果不提供此信息,邮局将不太确定如何处理这封信(而且很有可能最终会落在垃圾箱中,但这在此无关紧要)。从这个意义上讲,标题是您打算写信的人的地址:邮局(网络浏览器)的一组信息/说明,它可以据此操作。
因此,远离类推:标头是提供给网络浏览器的一组信息/指令,以便它可以对它们起作用。
您最可能知道的常见标头是'mime-type'标头,如下所示:
内容类型:text / html 。 此标头指示浏览器将其后(标头之后)的任何内容呈现为HTML文本。 如果您发送标头Content-type:text / xml ,那么浏览器将知道将文本呈现为XML (例如,在Firefox中 ,XML将以整洁的格式显示)。 PHP与它们有什么关系? PHP凭借其名称( PHP:超文本预处理器)非常与标头有关。 如果您曾经使用过C编程语言,那么您肯定会听说过C预处理程序 。 该工具将解析您的.c文件,并根据您的规则对其进行任何更改。 如果您#define IMG_X 100 ,预处理器将使用100更改所有出现的IMG_X 。 这实际上也是PHP所做的。 这与标题有什么关系? 好吧,这是在包含标头(或可以这样做)的预处理之后发生的事情。 PHP将驻留在其缓冲区中的所有数据推送到Web浏览器。 因此,PHP能够将标头发送到浏览器。 为什么标头只能在输出之前发送/为什么不能在输出后进行修改?答案很简单:浏览器收到标头后,将无法识别任何后续标头,因此进行任何尝试都是毫无意义的。
您可能还会问:
好吧,这听起来并不那么危险-为什么PHP对此大惊小怪? 答案很简单:PHP核心中的某些功能依赖于将标头信息发送到浏览器的需要。 在介绍这些功能时,我们将对其进行更详细的介绍。 原因对于每个出现的问题,总是至少有两个原因,并且总是存在那些使自己更难发现的原因。
常见原因。- session_start()
根据我的经验,导致标题错误的最常见原因是在将输出发送到浏览器后调用session_start()函数。 令人反感的代码通常如下所示:
session_start()函数是上述那些依赖于向浏览器发送标头信息的函数之一。<html> <head></head> <body> <h1>Starting session...</h1> <?php session_start(); ?> </body> </html>
为了实现会话,PHP需要在客户端的浏览器上创建一个cookie,该cookie将存储会话ID。 但是,正如我们之前发现的那样,如果输出已经发送到浏览器,则PHP无法将cookie标头发送到浏览器,因此对session_start()的调用失败。
但是,session_start()不是具有此行为的唯一函数。 其他功能包括(不完整列表):
*另一个常见错误是在发送输出后调用header()函数来重定向用户。 以下是另一位常犯:<html> <head></head> <body> <h1>Redirecting in 5 seconds...</h1> <?php header("refresh: 5; url=/page.html"); // Or header("location: /page.html"); ?> </body> </html>
- 另一个常见原因,实际上只是前面提到的原因的重复,是调用echo() *或print() *之类的函数,然后调用与标头相关的函数。 就像session_start()和header()示例一样,由于完全相同的原因,这将导致错误/警告。 一旦调用echo()或print(),就会发送标头(即第一次调用该函数),因此,您无法通过调用session_start()或header()等再次发送标头。
*从技术上讲,这些是语言构造而不是功能 -但这既不是这里也不是那里。<?php print 'This call to print() implicitly flushes the headers to the browser.'; session_start(); // :( ?>
通常,调试是一项冗长而繁琐的任务。 程序员的调试技能可能是调试问题的最大能力。[...]
-维基百科: 调试 。
- BOM(字节顺序标记)
字节顺序标记是一个字符序列,表示字节的排序方式。 要对其进行详细说明,将超出本文的讨论范围(并且不离题)。
您需要知道的是,各种程序(通常是基于Windows的程序)将此字符序列添加到文件的开头 。 当PHP打开此文件时,它会看到字符并认为自己可以,我们有一些输出要发送到浏览器! 然后头被隐式刷新,然后发送内容。
因此,如果您在该文件中有任何对诸如header()之类的函数的调用,您将遇到该熟悉的错误。 - 打开PHP标记前的空白
这是一个比BOM表问题更常见的问题,并且更容易发现,但仍然令人沮丧,尽管错误的产生原因完全相同:打开PHP标记(<?php) 之前的任何内容都将被视为输出并发送至浏览器,从而也刷新标题。
实际上,解决方案非常简单,并且通常是相同的。
正如我们从所有原因中看到的那样,当内容被有意或无意地发送到浏览器时,就会出现错误。 由此我们可以推断出解决方案是
发送标头之前不发送任何输出。 考虑以下示例:- session_start()
我们之前看到在输出一些HTML之后开始会话会导致问题:
如果将对session_start()的调用移到文件的开头,则不会看到任何错误!<html> <head></head> <body> <h1>Starting session...</h1> <?php session_start(); ?> </body> </html>
<?php session_start(); ?> <html> <head></head> <body> <h1>Starting session...</h1> </body> </html>
- 打开PHP标记前的空白
一个非常简单的解决方法-删除空格! 有时它并不明显,所以一定要仔细看!<?php // notice there _is_ a space before the opening PHP tag. session_start(); ?>
- 物料清单
因此,解决方案不像简单地删除任何空格或将函数调用移动到文件的开头那样简单,因为将这些字符放入文件中的文本编辑器也使它们不可见! 另外,所有文本编辑器的解决方案也不相同。 因此,我将为您提供Google的搜索关键字: 删除BOM <在此处插入文本编辑器名称>
有时您可能会发现,在大型代码库上,重组代码以减轻这些错误可能会非常耗时。 因此,您需要快速修复。
输出缓冲可能正是您所需要的。输出缓冲的功能与锡盒上所说的一样:缓冲(存储)您的输出,直到准备好刷新(发送)它为止。 使用这种技术,您可以像这样缓冲一块代码:
<?php
/** Kick start output buffering */
ob_start();
/** Send some output */
print 'Sending output!';
/** Call a header-dependant function */
session_start();
/** flush the buffer contents */
ob_end_flush();
现在,您可能已经想好了,PHP也不会缓冲标头吗?
答案是:不会。
输出缓冲功能不会影响需要发送头的任何功能,这就是它的美!
结论
所以,你去了。 我知道这篇文章比我预期的要全面,但是没关系。
愿消息来源与您同在,
马克·斯基贝克(Mark Skilbeck)。
附言:请提及所有拼写/语法错误以及任何不正确的信息。
From: https://bytes.com/topic/php/insights/876324-php-common-newbie-pitfalls-1-headers-already-sent