php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #30264 headers_sent() reporting incorrect value
Submitted: 2004-09-28 18:33 UTC Modified: 2004-12-06 01:00 UTC
Votes:6
Avg. Score:3.3 ± 1.4
Reproduced:3 of 4 (75.0%)
Same Version:2 (66.7%)
Same OS:1 (33.3%)
From: mpn at illearth dot net Assigned:
Status: No Feedback Package: Output Control
PHP Version: 4.3.9 OS: Win NT(2K)
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: mpn at illearth dot net
New email:
PHP Version: OS:

 

 [2004-09-28 18:33 UTC] mpn at illearth dot net
Description:
------------
When checking the value of headers_sent(), function is returning FALSE even though headers have clearly been sent.

Returned result does not change when output buffering is commented out or where output buffering is started (i.e before sending headers or after ).

I crammed the test code into 19 lines, so please excuse the formatting.

["SERVER_SOFTWARE"]=>  string(31) "Apache/2.0.49 (Win32) PHP/4.3.9" using sapi



Reproduce code:
---------------
<?php
ob_clean();
if ( stristr( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip' ) ) { ob_start( 'compressOutput' ); } else { ob_start(); }
header( 'Expires: Mon, 26 Jul 1997 05:00:00 GMT' );
header( 'Cache-Control: no-store, no-cache, must-revalidate' );
header( 'Cache-Control: post-check=0, pre-check=0', FALSE );
header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
header( 'Pragma: no-cache' );
echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' . "\n\n";
echo '<html><head>' . "\n";echo '<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />' . "\n";echo '<meta http-equiv="content-language"  content="en-GB" />' . "\n";
echo '</head><body>headers_sent() Returned Value Is: ' . "\n"; var_dump( headers_sent() ); echo '</body></html>' . "\n";
ob_end_flush();
function compressOutput( $str ) {
    $_output = gzencode( $str );
    if ( (bool)FALSE === $_output ) { return $str; }
    header( 'Content-Encoding: gzip' );
    return $_output;
} // End Function compressOutput
?>

Expected result:
----------------
var_dump( headers_sent() ); = (bool)true

Actual result:
--------------
var_dump( headers_sent() ); = (bool)false

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2004-09-29 15:35 UTC] mgf@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php

What makes you think headers should have been sent at the point where you call headers_sent()? I would not expect this to happen until the ob_end_flush() call.
 [2004-09-29 21:30 UTC] mpn at illearth dot net
I quote from the manual: http://us4.php.net/manual/en/function.ob-start.php

"While output buffering is active no output is sent from the script (other than headers), instead the output is stored in an internal buffer."

In particular "(other than headers)".

So according to the documentation, headers are sent prior to buffer flushing, which is also consistent with the documentation for headers: http://us4.php.net/manual/en/function.header.php

"Remember that header() must be called before any actual output is sent, either by normal HTML tags, blank lines in a file, or from PHP."

Please explain what use this function has when you can't use it until all the content has been sent to the browser, at which point (barring a shutdown function) the script normally exits?


Please try this test code:

----CUT----
blank<?php
error_reporting( E_ALL );
header( 'Expires: Mon, 26 Jul 1997 05:00:00 GMT' );
header( 'Cache-Control: no-store, no-cache, must-revalidate' );
header( 'Cache-Control: post-check=0, pre-check=0', FALSE );
header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
header( 'Pragma: no-cache' );
echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' . "\n\n";
echo '<html><head>' . "\n";echo '<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />' . "\n";echo '<meta http-equiv="content-language"  content="en-GB" />' . "\n";
echo '</head><body>headers_sent() Returned Value Is: ' . "\n"; var_dump( headers_sent() ); echo '</body></html>' . "\n";
flush();
header( 'Cache-Control: no-store, no-cache, must-revalidate' );
var_dump( headers_sent() );
?>
----END CUT----

The behavior of this code is consitent with what you have stated, headers aren't sent prior to the flush, however when trying to send headers after flushing, you trigger a warning: Warning: Cannot modify header information - headers already sent in W:\MPN\CVS\rc2-2\mpn188\html\_test_headers.php on line 12

So I fail to see where this function can be used??  The only good reason I can see for testing if headers have been sent is to determine if you can successfully send more headers.  As the above code shows, you cannot send anymore headers once flushing, which is the only location in the script that you get a TRUE return from headers_sent().

At the very least this qualifies as documentation problems or possibly add to the list of soon to be deprecated functions.
 [2004-09-29 21:57 UTC] mpn at illearth dot net
I might also note that the second test code results are also inconsistent with the manual with regard to headers().  According to the manual, the string "blank" before opening PHP should have triggered a warning and prevented headers from being sent.
 [2004-09-30 03:32 UTC] iliaa@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php

There is no bug here, at best perhaps a slightly unclear documentation.

When you use compression the entire page is buffered in memory, until end of the request. Consequently you can send headers at any time because no data is being actually sent to user when you print it. Until PHP actually decides to send any page output to the user you can still send additional headers which is why the headers_sent() function is returning false.
It will return true, indicating that headers have been sent only at a time when output began going to the user and you no longer can send any additional headers.
 [2004-09-30 06:34 UTC] mpn at illearth dot net
"When you use compression the entire page is buffered in memory, until end of the request."

The second test example does not use any compression and I stated in the first example that the returned result was the same regards of where output buffering was started, or for that matter even used.

I agree it is not a "bug" in that it's returning what it should based on the behavior of the test code.  However in the second test example, no buffering of output is taking place and yet the function is still returning false. Remove the buffering from test code example 1 and you get the same result.  This is NOT the behavior I would expect according to documentation.  In previous versions of PHP the second test example (and the first for that matter) would generate a warning, in at least vs. 4.3.9 it is not.

I understand the reasons for not sending headers until the script is complete (buffering or not), but I don't understand the need for a function that will always return false until a time when it is too late to send anymore headers, and why the documentation is clearly stating the opposite is true.  So why even bother testing if headers have been sent?
 [2004-09-30 16:11 UTC] mpn at illearth dot net
Let me put this into the context of the problem I am having.

I am using a custom error handler.  At the error threshold where script execution will exit I need to check if headers had been sent in order to determine if output compression needs to be enabled and buffers cleaned/shutoff.  Apparently stacking compressed output buffers (even if they have been "cleaned" of content) is restricted since it destroys the output (i.e. the browser shows compressed output).  This may be a bug in itself since according to documentation output buffers are stackable with no mention of any restrictions.

So let's take it step by step.

1) script excution starts
2) get support includes
3) start output (i.e. headers are set, ouput buffering started, output content printed/echoed).
4) Trigger a fatal exit error.
5) var_dump the return of headers_sent() and exit prior to sending any error messages to the browser or flushing any buffers.  

At this point the normal expected output, up to the point of the error, has been sent to the browser, however the value of headers_sent() is still FALSE even though I am looking at the expected output in the browser, with the variable dump value at the bottom of that output where the exit occurs.
 [2004-09-30 22:45 UTC] iliaa@php.net
If you are using default config you probably have output buffering enabled, which makes PHP buffer output data in 4096 chunks.
 [2004-10-01 05:12 UTC] mpn at illearth dot net
OK, yes output buffering in the ini is set to the default of 4096.  So based on what I am seeing (i.e. ouput in the browser), the buffer is being flushed at 4096 bytes, however the value of headers_sent() is still FALSE, even though it appears the buffer has been flushed at least once, if not several times at the point of the exit.  

Now what is even more quirky is I can clean and shutdown all the buffers prior to the exit in the error handler and I will not get any screen output in the browser.  When doing this the value of headers_sent() is still FALSE.  This suggests the buffer has not been flushed at it's default flush point.

So two senarios exist here:  

1) Do NOT clean and shutdown the buffers and I get output in the browser up to the point of the fatal error exit in the error handler.  The value of headers_sent() is FALSE.

2) Clean and shutdown all buffers at the point of the fatal error exit in the error handler, no output to the browser has been sent. The value of headers_sent() is FALSE.

In the first senario, the value of headers_sent() should be TRUE since I am seeing intended output in the browser.
 [2004-10-01 05:12 UTC] mpn at illearth dot net
OK, yes output buffering in the ini is set to the default of 4096.  So based on what I am seeing (i.e. ouput in the browser), the buffer is being flushed at 4096 bytes, however the value of headers_sent() is still FALSE, even though it appears the buffer has been flushed at least once, if not several times at the point of the exit.  

Now what is even more quirky is I can clean and shutdown all the buffers prior to the exit in the error handler and I will not get any screen output in the browser.  When doing this the value of headers_sent() is still FALSE.  This suggests the buffer has not been flushed at it's default flush point.

So two senarios exist here:  

1) Do NOT clean and shutdown the buffers and I get output in the browser up to the point of the fatal error exit in the error handler.  The value of headers_sent() is FALSE.

2) Clean and shutdown all buffers at the point of the fatal error exit in the error handler, no output to the browser has been sent. The value of headers_sent() is FALSE.

In the first senario, the value of headers_sent() should be TRUE since I am seeing intended output in the browser.
 [2004-11-28 14:34 UTC] tony2001@php.net
I can't reproduce your problem. 
headers_sent() reports correct value in any situation when running your reproduce script.
 [2004-12-06 01:00 UTC] php-bugs at lists dot php dot net
No feedback was provided for this bug for over a week, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sun Dec 22 11:01:30 2024 UTC