This error must be the most asked in the history of the Internet. This answer is a more complete and explanatory translation of another originally posted in Stackoverflow in English made by a community colleague.
Additionally I have revised a lot of the translation (including grammar) and obviously re-formatted all the formatting for the markdown used in/by Stack Overflow. But still, if there is (in) an error(s), feel free to correct or complement.
Does not emit output before sending the headers!
Functions that send/modify headers HTTP must be called before any output be done. Otherwise the call will fail.
Warning: Cannot Modify header information - headers already sent (output Started at file:line)
Some functions that modify the headers HTTP are:
Output can be:
Accidental
Intentional:
- print, echo and other emitting functions output, as
var_dump()
- Code
<html>
before the code within <?php
.
Why does this happen?
To understand why the headers must be sent before the output, it is necessary to look at a typical HTTP Response. Scripts PHP mainly generate HTML content, but also pass a few headers HTTP/CGI to server.
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=about:note> ...
The page/output always follows the headers. PHP is required to pass the headers to the server first. It can only do this once. And after double line break (sending of output to simplify), it can not add more headers.
When PHP gets the first output (print, echo, ), he will send the headers collected. Later, it can upload all the contents of output you want. But, it is not possible to send new headers from this moment on.
How can you find out where the output occurred?
The Warning of function header()
contains all relevant information to locate the root of the problem:
Warning: Cannot Modify header information - headers already sent by (output Started at /www/usr2345/htdocs/auth.php:52) in /www/usr2345/htdocs/index.php on line 100
Here, the line 100 refers to the line of script where the function call header()
failed.
The message within the parentheses is more important. It mentions that the line 52 of the archive auth.php is the root of output. One of the most popular causes of this error are:
Print, echo
Output intentional print and echo executions will end the opportunity to send headers HTTP. The application flow must be restructured to prevent this. Use function and templates. Check if calls to the function header()
occur before messages are sent.
Functions they can send output include but are not limited to: print, echo, printf()
, trigger_error()
, vprintf()
, ob_flush()
, var_dump()
, readfile()
, passthru()
, among others. And also functions defined by you.
HTML code
HTML codes that are not interpreted in a file . php are outputs also. Codes that will call the function header()
should be done before any code .
<!DOCTYPE html> <?php // Já não é possível enviar *headers*.
White spaces before <?php
when ".php file line 1" is mentioned.
If the message says the error is on line 1, then it is usually whitespace, text or HTML before opening tag <?php
.
<?php # Há um espaço/linha em branco antes de <?php
May also occur with scripts "together".
?> <?php
PHP actually puts a line break after closing the tags.
UTF-8 GOOD
Line breaks and spaces can be a problem. But there are also strings of "invisible" characters that can cause this. the most popular is UTF-8 GOOD (Byte-Order-Mark) that is not displayed by most text editors. It is a byte sequence, which is optional and redundant for UTF-8.
But the PHP interpreter treats it as output. It can also show as characters  in the output (if the client interprets the document in Latin-1) or some similar "garbage".
Particularly, some graphic editors and Ides Java-based do not notice their presence. They do not see this thanks to the Unicode standard. However, some editors and consoles show:
It is not easy to recognize the problem early on. Without such an editor available or Notepad++ on Windows (which can solve the problem), another solution would be a Hexeditor. Programmers should have one, as they simplify the identification of these problems:
The easy solution is to define the text editor used to save files as UTF-8 (in the GOOD) or some other similar or translated nomenclature. Many new programmers create new files by copying/pasting the old ones, only changing their content later.
Correction utilities
There are automated tools for rewriting text files. For PHP, specifically, there is the phptags tag tidier. It rewrites opening and closing tags into long and short tags, but also easily solves whitespace AND GOOD:
phptags --whitespace *.php
It is wise to use in a complete directory or in the project directory.
Blanks after ?>
If the root of the error is mentioned after the closure of ?>
, so that’s where there’s some blank space or written text.
To tag PHP closure does not finish executing the script at this point. Any characters after it will be printed as output.
It is commonly said to beginners that the tag closure should be omitted. This avoids a significant part of these cases. Includes are usually the culprits.
Again, phptags --whitespace *.php
resolve this quickly.
Likewise, the command phptags --unclosed ./includes
can remove tags ?>
redundant of scripts.
Root of the error mentioned as "Unknown on line 0"
Typically happens when PHP extensions or php.ini define whether the root of the error is not specified. This mainly happens with the gzip stream or the ob_gzhandler()
.
However, this could also be any module loaded twice, which leave a message from Warning implicit.
Previous error messages
If any other PHP command causes a Warning or notice being displayed, this also counts as output. In this case, you need to correct the error, delay the execution of the command or delete the error with isset()
or @ - when this did not obstruct the debugging later on.
No error message
If you have error_reporting or display_errors disabled by php.ini, then no Warning will be displayed. But ignoring errors will not solve the problem ( the/). Still, the headers may not be sent after the output.
So when header("Location: ...")
the redirect fails silently, it is good to examine the warnings. Enable them again with two simple commands (at the beginning of the script):
error_reporting(E_ALL); ini_set("display_errors", 1);
Or if all else fails:
set_error_handler("var_dump");
Speaking of redirects, you should use something like this for code paths at the end.
exit(header("Location: /finished.html"));
Or even a function, which prints a message when a call header()
fail.
Exit control as gambiarra ☠
The output control of PHP is suitable to alleviate this problem. This is not so reliable, but should be considered a valid gambiarra. Its real purpose is to minimize fragmented transfers to the server. Restructure the application to avoid output is preferable.
However set up output_buffering help. Configure this in php.ini or via .htaccess or even .user ini.. With this enabled, the content is stored in a buffer and is not instantly passed to the server. So headers HTTP can be aggregated.
This can also be done with a call to ob_start()
at the top of script. This, however, is less reliable for some reasons:
- Even if
<?php ob_start(); ?>
start the first script, white spaces or a problem of GOOD can be caused before, making this technique inefficient.
- This can hide blanks for output HTML; but to the extent that application logic attempts to send binary content (an image generated, for example), the irrelevant spaces stored in buffer become a problem. Even if
ob_clean()
be another valid gambiarra.
- The buffer has a size limit. Although usually a hypothetical problem, it may nevertheless happen - which would not be easy to discover/examine.
See also a basic example for use in the manual.
But this worked on another server!?
If you didn’t have warnings before, then the configuration of the php.ini changed. The output control was then enabled on the other server, but not on the current one. See previous section.
Checking with headers_sent()
You can always use headers_sent()
to examine whether it is still possible to send headers. This is useful for conditionally displaying information or applying some other logic.
if (headers_sent()) {
die("O redirecionamento falhou. Por favor, clique neste link: <a href=...>");
}
else{
exit(header("Location: /user.php"));
}
Gambiarra with the HTML tag
If your application’s structure is difficult to fix, then an easy (but amateur) way to create a redirect is by injecting HTML. A redirect can be done like this:
<meta http-equiv="Location" content="http://example.com/">
Or with a simple delay (the nephew approves!):
<meta http-equiv="Refresh" content="2; url=../target.html">
This will make your site invalid (even with fake XHTML) when inserted outside the . Most browsers still accept this. Alternatively, a redirect in Javascript could be done:
<script> location.replace("target.html"); </script>
It is an acceptable approach if this is used as a fallback by the specialized redirect functions, which should first attempt to send a header()
but to use the meta tag and a friendly message and a link as a last resort.
Why setcookie() and session_start() are also affected
Both the setcookie()
as to the session_start()
need to send a header Set-Cookie. The same conditions therefore apply and similar error messages will be displayed.
Problems of output of headers are not the only cause for non-functionality with them, of course. Cookies disabled in the browser or even proxy issues should always be checked. The functionality of the Session also depends on the free disk space and other settings of the php.ini.
Additional links
a forum colleague? I almost died now :D
– Jorge B.
I was almost going crazy because I wanted a simple redirect to the home through my script, no matter the case. Nothing worked until your javascript example
echo '<script> location.replace("/"); </script>';
solved!!! Thank you very much!!!– Rogério Dec
I’m glad you could help :)
– Bruno Augusto
Helped me too much, man, thank you so much!
– Alisson Diel
What a great answer !
– Gato de Schrödinger