Recently I was working on a custom CMS, and I started by creating a simple login page and a restricted area, accessible only to the admins. The login page used PHP sessions to let an authenticated user in. It was nothing fancy, just basic stuff you find in any sessions tutorial.
- after successful login, call session_start() & save a session variable (like the admin’s user ID)
- redirect the user to some restricted page, like admin_home.php
- on every restricted page, call session_start() and check if the session variable is set
- die; if the variable isn’t set
Simple enough that nothing can go wrong, you might think. Well after uploading, I found out that the sessions were simply not working on the live production server. To be more precise, they were not persistent across pages. The session was created when the user logged in, but didn’t exist as soon as they navigated to any other restricted page.
So I started googling. What could be the cause of sessions only working on your development server? Here are the most common answers I came across:
- sessions are not enabled in php ini
- the temporary session directory is not writable (your script doesn’t have suffecient permissions to write data to it)
Sadly, none of these were my case. So I turned on error reporting with:
error_reporting(E_ALL); ini_set('display_errors', 'On');
…and here’s what I got:
Warning: session_start() [function.session-start]: Cannot send session cookie – headers already sent by (output started at session.php:2) in session.php on line 6
Warning: session_start() [function.session-start]: Cannot send session cache limiter – headers already sent (output started at session.php:2) in session.php on line 6
The cause: Whitespace
Output started? What is the error message talking about? Turns out I had whitespace before my opening PHP tag! This was something that my development server ignored, but my production server had considerable problems swallowing (maybe because of a different PHP version, or different configuration, I don’t know).
The session_start() function modifies the header of the HTTP request, which means it must be called before any HTML output – just like, for example, a redirect using header(“Location: destination.php”). And of course, the whitespace before <?php that I was overlooking IS considered a HTML output.