How to fix "Headers already sent" error in PHP
itemprop="text">
When running my
script, I am getting several errors like
this:
Warning:
Cannot modify header information - headers already sent by (output started
at /some/file.php:12) in /some/file.php on
line
23
The
lines mentioned in the error messages contain rel="noreferrer">header()
and href="http://php.net/setcookie"
rel="noreferrer">setcookie()
calls.
What could be the reason for this? And
how to fix it?
itemprop="text">
No output
before sending headers!
Functions that
send/modify HTTP headers must be invoked before any output is
made.
href="https://stackoverflow.com/a/8028979/345031">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 or after
?>
- The href="http://en.wikipedia.org/wiki/Byte_order_mark" rel="noreferrer">UTF-8 Byte Order
Mark specifically
- Previous error messages or
notices
Intentional:
print
,
echo
and other functions producing
output
- Raw
sections
prior code.
Why
does it happen?
To understand why headers must
be sent before output it's necessary
to look at a typical href="http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol"
rel="noreferrer">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
PHP page output
page
Content
Some more output follows...
and src=internal-icon-delayed>
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
,
) it will
flush all
collected headers. Afterwards 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
occured?
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
and echo
statements will
terminate
the opportunity to send HTTP headers. The application flow
must
be restructured to avoid that. Use href="http://php.net/function" rel="noreferrer">functions
and
templating schemes. Ensure header()
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 a header()
call must be
noted
before any raw
blocks.
html>
// 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 for "script.php line
1" warnings
If the warning
refers to output in line 1
, then
it's mostly
leading whitespace, text or HTML
before the opening
token.
#
There's a SINGLE space/newline before it.
Similarly
it can occur for appended scripts or script
sections:
?>
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 which can
cause this. Most famously the
href="http://en.wikipedia.org/wiki/Byte_order_mark"
rel="noreferrer">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:
src="https://i.stack.imgur.com/aXgWY.png" width="590" height="140" alt="joes editor
showing UTF-8 BOM placeholder, and MC editor a
dot">
There it's easy to recognize the
problem early on. Other editors may identify
its presence in a file/settings
menu (Notepad++ on Windows can identify and
href="https://stackoverflow.com/questions/3589358/fix-utf8-bom">remedy the
problem),
Another option to inspect the BOMs presence is resorting
to an hexeditor.
On *nix systems href="http://linux.die.net/man/1/hexdump"
rel="noreferrer">hexdump
is usually
available,
if not a graphical variant which simplifies auditing
these and other issues:
src="https://i.stack.imgur.com/QyqUr.png" width="560" height="87" alt="beav hexeditor
showing utf-8 bom">
An easy fix is to set the
text editor to save files as "UTF-8 (no BOM)"
or similar such nomenclature.
Often newcomers otherwise resort to creating new
files and just
copy&pasting the previous code back
in.
Correction utilities src="https://i.stack.imgur.com/wnAS9.gif" width="30"
height="20">
There are also
automated tools to examine and rewrite text files
( href="https://stackoverflow.com/questions/1068650/using-awk-to-remove-the-byte-order-mark">sed
/awk
or recode
).
For PHP specifically there's the href="http://freshcode.club/projects/phptags"
rel="noreferrer">phptags
tag tidier.
It
rewrites close and open tags into long and short forms, but also easily
fixes
leading and trailing whitespace, Unicode and UTF-x BOM
issues:
phptags --whitespace
*.php
It's sane to use
on a whole include or project
directory.
Whitespace
after ?>
If the
error source is mentioned as behind the
href="https://stackoverflow.com/questions/4410704/php-closing-tag">closing
?>
then this is where some whitespace or
raw text got written out.
The PHP end marker does not terminate script
executation at this
point. Any text/space characters after it will be written
out as page content
still.
It's
commonly advised, in particular to newcomers, that trailing
?>
PHP
close tags should be omitted.
This eschews a small portion of these cases.
(Quite
commonly include()d
scripts are the
culprit.)
Error source mentioned as
"Unknown on line 0"
It's typically a PHP
extension or php.ini setting if no error source
is
concretized.
- It's
occasionally the gzip
stream encoding setting
href="https://stackoverflow.com/questions/622192/php-warning-headers-already-sent-in-unknown">or
the
ob_gzhandler
.
- But
it could also be any doubly loaded extension=
module
generating an implicit PHP startup/warning
message.
Preceding
error messages
If another PHP statement or
expression causes a warning message or
notice being printeded out, that also
counts as premature output.
In this case you
need to eschew the error,
delay the statement execution, or suppress the
message with e.g.
rel="noreferrer">isset()
or href="http://php.net/@" rel="noreferrer">@()
-
when either doesn't obstruct debugging later
on.
No error
message
If you have
error_reporting
or display_errors
disabled per php.ini
,
then no warning will show up.
But ignoring errors won't make the problem go
away. Headers still can't be
sent after premature output.
So when
header("Location: ...")
redirects silently fail it's
very
advisable to probe for warnings. Reenable them with two simple
commands
atop the invocation
script:
error_reporting(E_ALL);
ini_set("display_errors",
1);
Or
set_error_handler("var_dump");
if all else
fails.
Speaking of redirect headers,
you should often use an idiom like
this for final code
paths:
exit(header("Location:
/finished.html"));
Preferrably
even a utility function, which prints a user message
in case of
header()
failures.
Output buffering as
workaround
PHPs href="http://www.php.net/manual/en/intro.outcontrol.php" rel="noreferrer">output
buffering
is a workaround to alleviate this issue. It often works
reliably, but shouldn't
substitute for proper application structuring and
separating output from control
logic. Its actual purpose is minimizing chunked
transfers to the
webserver.
The
rel="noreferrer">output_buffering=
setting
nevertheless can help.
Configure it in the href="http://www.php.net/manual/en/configuration.file.php"
rel="noreferrer">php.ini
or via href="http://www.php.net/manual/en/configuration.changes.php"
rel="noreferrer">.htaccess
or even href="http://php.net/manual/en/configuration.file.per-user.php"
rel="noreferrer">.user.ini on
modern FPM/FastCGI setups.
/>Enabling it will allow PHP to buffer output instead of passing it to the
webserver
instantly. PHP thus can aggregate HTTP
headers.
It can likewise be engaged
with a call to rel="noreferrer">ob_start();
atop the
invocation script. Which however is less reliable for multiple
reasons:
Even if
starts the first script, whitespace
or a
BOM might get shuffled before, href="https://stackoverflow.com/questions/2168956/php-header-problem-even-i-use-ob-start-and-ob-end-flush">rendering
it
ineffective.
It
can conceal whitespace for HTML output. But as soon as the application
logic
attempts to send binary content (a generated image for example),
the buffered
extraneous output becomes a problem. (Necessitating
ob_clean()
as furher
workaround.)
The buffer is limited in
size, and can easily overrun when left to defaults.
And that's not a rare
occurence either, href="https://stackoverflow.com/questions/17643837/php-headers-already-sent-error-depending-on-output-length">difficult
to track down
when it
happens.
Both
approaches therefore may become unreliable - in particular when switching
between
development setups and/or production servers. Which is why output
buffering is
widely considered just a crutch / strictly a
workaround.
See also the href="http://www.php.net/manual/en/outcontrol.examples.basic.php"
rel="noreferrer">basic usage example
in the manual, and for more
pros and cons:
But it
worked on the other server!?
If you
didn't get the headers warning before, then the href="http://php.net/manual/en/outcontrol.configuration.php" rel="noreferrer">output
buffering
php.ini setting
has changed. It's likely
unconfigured on the current/new
server.
Checking with
headers_sent()
You can
always use rel="noreferrer">headers_sent()
to probe
if
it's still possible to... send headers. Which is useful to conditionally
print
an info or apply other fallback
logic.
if
(headers_sent()) {
die("Redirect failed. Please click on this link: href=...>");
}
else{
exit(header("Location:
/user.php"));
}
Useful
fallback workarounds
are:
HTML
tag
If
your application is structurally hard to fix, then an easy (but
somewhat
unprofessional) way to allow redirects is injecting a
HTML
tag. A redirect can be achieved
with:
http-equiv="Location"
content="http://example.com/">
Or
with a short delay:
http-equiv="Refresh" content="2;
url=../target.html">
This
leads to non-valid HTML when utilized past the
section.
Most browsers still accept
it.
JavaScript
redirect
As alternative a href="https://stackoverflow.com/questions/503093/how-can-i-make-a-redirect-page-in-jquery-javascript">JavaScript
redirect
can be used for page
redirects:
While
this is often more HTML compliant than the
workaround,
it incurs a reliance on JavaScript-capable
clients.
Both
approaches however make acceptable fallbacks when genuine HTTP header()
calls
fail. Ideally you'd always combine this with a user-friendly message
and
clickable link as last resort. (Which for instance is what the href="http://php.net/http_redirect"
rel="noreferrer">http_redirect()
PECL extension
does.)
Why setcookie()
and session_start()
are also
affected
Both
setcookie()
and session_start()
need
to send a Set-Cookie:
HTTP header.
The same
conditions therefore apply, and similar error messages will be generated
for
premature output situations.
(Of
course they're furthermore affected by disabled cookies in the browser,
or
even proxy issues. The session functionality obviously also depends on
free
disk space and other php.ini settings,
etc.)
Further
links
No comments:
Post a Comment