Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP 5.6: headers_sent intermittently returns true, empty file name, and line 0

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 :

  1. HTML blocks or calls to print, echo, etc. before my calls to setcookie() or header()
  2. whitespace outside my PHP tags
  3. BOMs
  4. auto_prepend_file php.ini setting
  5. gzip stream encoding - zlib is installed, but zlib.output_compression is Off
  6. Duplicate extension= php.ini settings

That 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.

like image 984
Aaron Avatar asked Mar 16 '17 07:03

Aaron


People also ask

What does the function Headers_sent () in PHP return?

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.

How do you fix PHP warning Cannot modify header information headers already sent by?

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.

What is the use of header () function in PHP?

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).


3 Answers

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.

like image 146
Patrick Kelly Avatar answered Oct 17 '22 05:10

Patrick Kelly


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.

like image 37
El' Avatar answered Oct 17 '22 05:10

El'


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!

like image 31
Aaron Avatar answered Oct 17 '22 04:10

Aaron