PHP Closing Tags Stealing Your Cookies?
As a professional PHP developer who enjoys helping others learn about the language, I have noticed several phases of PHP skill development. One of the first phases is when one stops piling all of their code into one file and starts storing their classes and specialized logic into reusable files. For some, this change brings on a wave of problems that may be very difficult to track down.
The Problem
At some point, many PHP developers run into an inexplicable White Page of Death or at least stubborn cookies and headers that won’t change when they should. A common cause is include files with white space after the PHP closing tag. Your web server might send these characters to the browser before you process your header() or setcookie() calls, causing them to fail. PHP allows for a single newline after a PHP closing tag before it starts interpreting characters as output.
Solutions
Omit PHP closing tags
The PHP closing tag is useful when you embed PHP into a page that already contains other content such as an HTML template. However, if you only intend to have PHP logic in a page and nothing else, you can omit the final PHP closing tag:
<?php
$test = new testClass();
$test->helloWorld();
// End of PHP script. No closing tag needed.
This approach does not incur any additional resource penalty to the server.
Output Buffering
If you feel that you need to send output before processing headers and cookies, you should use output buffering. The ob_* class of PHP functions are very useful in these circumstances, but be aware that it comes at the cost of an increased memory footprint and slightly slower processing.
Error Logging
Instead of silently failing or dying with a white page of death, error logging would tell you exactly what is failing and why:
[24-Oct-2008 15:17:31] PHP Warning: Cannot modify header information - headers already sent by (output started at /websites/demo/htdocs/whitespace.php:5) in /websites/demo/htdocs/cookie.php on line 8
I suggest everyone who develops in PHP do so with log_errors enabled. If develop with logging on from the beginning of your project, you will quickly capture potential problems before they grow too great in number and become overwhelming.
I prefer to set my error_reporting level to “E_ALL & E_STRICT” because many standards and best practices are enforced with these messages. (E_STRICT will be included as part of E_ALL in PHP 6)
Once you have logging enabled, you can SSH into your server and “tail” your error log for real-time error output:
[ian@devbox]~ tail -f /tmp/php.log
Using the “-f” flag will follow the log and give continuous output as it appears in the log file.
Please note that logging should be used sparingly (at least at a higher error_reporting level) in production servers. Also, I advise against using PHP’s display_errors in any case, especially production servers. In a production environment, this argument can provide dangerous information to site visitors. You may find it useful in development, but I find that not all errors will be visible or readable when output within your page. However, your log files will never let you down.
October 26th, 2008 at 8:35 pm
Good one.
October 27th, 2008 at 10:55 am
Interesting post, never knew this. Thanks.
October 30th, 2008 at 10:06 am
great post, ian - i would post this link to the PHP Meetup - i’m sure lots of people would find it useful.
November 27th, 2008 at 7:08 pm
Good idea with the error logging. I have encountered this problem before, but I usually develop with error reporting on, so it throws a ‘headers already sent’ error.
December 5th, 2008 at 11:05 pm
Hi I put your post into our Wiki at http://www.phpmeeting.com/wiki/PHP_Closing_Tags_Stealing_Your_Cookies%3F