I'm intermittently getting this issue in my PHP scripts (PHP 5.6, Apache 2.2):
Warning: Cannot modify header information - headers already sent in /path/to/index.php on line 55
This warning doesn't have the "sent by" portion that I've seen in other questions about this, so I added this code just before the offending header()
and setcookie()
calls:
if (headers_sent($filename, $linenum)){
echo("Output buffer: #" . ob_get_contents() . "#");
echo "Headers already sent in $filename on line $linenum: ";
print_r(headers_list());
}
Here's the output I got when the issue occurred:
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
)
(Side note: I have output_buffering set to 4096 bytes in php.ini, so shouldn't the 63 characters in these two headers be buffered up and waiting for more, rather than being sent prematurely?)
This issue arises the first time I spin up a Docker container containing the webserver. After that, it only (but not always) occurs when I access my site for the first time in a while (maybe one or two hours), when I call header()
and setcookie()
to log a user in or to redirect to the login page.
I've read and reread this answer to the general "Headers already sent" error, and, to the best of my ability, I've ruled out these possible causes :
print
, echo
, etc. before my calls to setcookie()
or header()
auto_prepend_file
php.ini settinggzip
stream encoding - zlib is installed, but zlib.output_compression
is Offextension=
php.ini settingsThat answer mentions that
It's typically a PHP extension or php.ini setting if no error source is concretized.
So, I'm now looking through my extensions... get_loaded_extensions
gives me a 51-length Array with these entries:
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
I'm not using all of these, so I plan to go through and remove the unused ones, and hope one of those was causing the problem.
Worst-case scenario, I'll try bumping my output_buffering
value or use ob_start()
and ob_end_flush()
to the starts and ends of my files. I don't know why this would fix it when my current output_buffering
value of 4096 doesn't, and I understand that this workaround comes with its own issues.
What am I missing here—are there other possible causes I need to check for? Should I try a different PHP version, or perhaps run a subset of my code on a clean PHP install with no extensions?
EDIT: Added the ob_get_contents()
call and output, and information about being able to consistently reproduce this by spinning up new Docker containers. Removed info about my error_reporting
value; changing this only uncovered an always_populate_raw_post_data
deprecation notice, fixing which had no effect on the issue described here.
The headers_sent() function is an inbuilt function in PHP which is used to determines whether the header is successfully sent or not. The headers_sent() function returns True if header sent successfully and False otherwise.
php file are rendered as a direct output. If an HTML element is placed before a header call, it can cause the “Cannot Modify Header Information – Headers Already Sent By” error. To fix the error, place the HTML block after the header statement.
The header() function in PHP sends a raw HTTP header to a client or browser. Before HTML, XML, JSON, or other output is given to a browser or client, the server sends raw data as header information with the request (particularly HTTP Request).
I have seen the problem arise due to line ending format in the past. Are you moving files from one operating system environment to another?
Sometimes a hidden carriage return (/r) or an other special white-space character can cause this but not be visible in the files.
It can be UTF8 BOM character, or wrong newline, non printable characters, wrong php close tag (i don`t use them, to prevent endline problems). Even if there was no such problem, it can ( and will ) occur later even if you do everything to prevent it. Problems can be with FTP servers, text editors, wrong PHP configurations, encodings, wrong cgi configurations. To prevent all of them i use empty output buffer, just start buffreing in first php file
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);
in php5 and php7 output buffering has few differences, also output buffering can be configured in php.ini and has differences in cgi and apache mod configurations. You shuld not relay on "default" configuration. To handle warning messages, use set_error_handler() you will strip them too with ob_end_clean()
if you start new project look at symfony components, i use a lot of them in my CMS. That is your chance to prevent sleepless nights with strange PHP bugs.
After taking out some unused legacy code—including require_once
calls to a file that was all legacy code—this problem is no longer occurring. It may recur under the "intermittent" conditions I initially observed, but my method for reproducing it no longer exhibits this problem.
I don't know why this seems to have helped - the removed lines were completely within <php? ?>
tags, and I checked the removed file for whitespace outside tags, BOMs, and CRLFs.
I also don't know why this issue was intermittent; if it had something to do with the removed code or files, it should have happened every time.
Thanks to all for the comments and answers!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With