Solution:1
No output before sending headers!
Functions that send/modify HTTP headers must be invoked before any output is made. summary ⇊ Otherwise the call fails:
Warning: Cannot modify header information – headers already sent (output started at script:line)
Some functions modifying the HTTP header are:
Output can be:
- Unintentional:
- Whitespace before
<?php
or after?>
- The UTF-8 Byte Order Mark specifically
- Previous error messages or notices
- Whitespace before
- Intentional:
print
,echo
and other functions producing output- Raw
<html>
sections prior<?php
code.
Why does it happen?
To understand why headers must be sent before output it’s necessary to look at a typical HTTP response. PHP scripts mainly generate HTML content, but also pass a set of HTTP/CGI headers to the webserver:
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>
The page/output always follows the headers. PHP has to pass the headers to the webserver first. It can only do that once. After the double linebreak it can nevermore amend them.
When PHP receives the first output (print
, echo
, <html>
) it will flush all collected headers. Afterward it can send all the output it wants. But sending further HTTP headers is impossible then.
How can you find out where the premature output occurred?
The header()
warning contains all relevant information to locate the problem cause:
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 “line 100” refers to the script where the header()
invocation failed.
The “output started at” note within the parenthesis is more significant. It denominates the source of previous output. In this example, it’s auth.php
and line 52
. That’s where you had to look for premature output.
Typical causes:
-
Print, echo
Intentional output from
print
andecho
statements will terminate the opportunity to send HTTP headers. The application flow must be restructured to avoid that. Use functions and templating schemes. Ensureheader()
calls occur before messages are written out.Functions that produce output include
print
,echo
,printf
,vprintf
trigger_error
,ob_flush
,ob_end_flush
,var_dump
,print_r
readfile
,passthru
,flush
,imagepng
,imagejpeg
among others and user-defined functions.
-
Raw HTML areas
Unparsed HTML sections in a
.php
file are direct output as well. Script conditions that will trigger aheader()
call must be noted before any raw<html>
blocks.<!DOCTYPE html> <?php // Too late for headers already.
Use a templating scheme to separate processing from output logic.
- Place form processing code atop scripts.
- Use temporary string variables to defer messages.
- The actual output logic and intermixed HTML output should follow last.
-
Whitespace before
<?php
for “script.php line 1” warningsIf the warning refers to output inline
1
, then it’s mostly leading whitespace, text or HTML before the opening<?php
token.<?php # There's a SINGLE space/newline before <? - Which already seals it.
Similarly it can occur for appended scripts or script sections:
?> <?php
PHP actually eats up a single linebreak after close tags. But it won’t compensate multiple newlines or tabs or spaces shifted into such gaps.
-
UTF-8 BOM
Linebreaks and spaces alone can be a problem. But there are also “invisible” character sequences that can cause this. Most famously the UTF-8 BOM (Byte-Order-Mark) which isn’t displayed by most text editors. It’s the byte sequence
EF BB BF
, which is optional and redundant for UTF-8 encoded documents. PHP however has to treat it as raw output. It may show up as the characters
in the output (if the client interprets the document as Latin-1) or similar “garbage”.In particular graphical editors and Java-based IDEs are oblivious to its presence. They don’t visualize it (obliged by the Unicode standard). Most programmer and console editors however do: