There are cases when session_start();
returns true even if it can't actually start the session. One can see that from the error log:
PHP Warning: session_start():
open(/var/lib/php5/sessions/sess_XXXXXXX, O_RDWR) failed:
Permission denied (13)
I've seen this happen if a programmer thinks he can use the same session ID on different websites, but they actually use different privileges and can't access each other files. And I can't say this programmer, like, hey, check what session_start()
returns and act accordingly because he'd tell me he checks and it reports all good.
One can simulate this problem by removing write privileges from a specific session file:
chmod a-w /var/lib/php5/sessions/sess_XXXXXXX
And then staring a session with the same ID:
session_start(); // returns true with a warning in the logs
// if it'd return false, there would be no question
// PHP thinks session is started: session_status() == PHP_SESSION_ACTIVE
What is the proper way to deal with such errors in software? E.g. how do I know that I have this kind of error but not by looking in the logs?
So far I've come to this:
set_error_handler(function ($errno, $errstr) {
// we got an error during session_start()
if (strpos($errstr, 'session_start') === 0) {
// forget previus session ID
session_regenerate_id();
// restore the handler for now
set_error_handler(null);
}
return false;
}, E_WARNING);
if (!session_start()) {
// et cetera
}
// session shall be running now
// restore the error handler
set_error_handler(null);
(My inspiration comes from phpMyAdmin, which also does something similar.)
You shouldn't try to resolve this with software, you should correct the server configuration. In this case, ensure the user the server is running as - either apache or www-data or nobody, has write permissions for the PHP session storage directory and files.
You can find out which user PHP is running under by using:
<?php echo `whoami`; ?>
Catching errors and warning are fun, but you never know if you got them right. What you really need is to check that you can actually save something to the session.
function verify_session_writable()
{
// if session has been started yet there's no canary
if (empty($_SESSION[__FUNCTION__]) &&
session_status() == PHP_SESSION_ACTIVE) {
// set the canary
$_SESSION[__FUNCTION__] = 1;
// write the session to a file
session_write_close();
// and load it once again
session_start();
// if there's no canary, it's an error
if (empty($_SESSION[__FUNCTION__])) {
// change session ID to make sure the write
// happens to a file with a different name
session_regenerate_id();
// set the canary to skip futher checks
$_SESSION[__FUNCTION__] = 1;
}
}
}
I call this function in every place I need to be sure I can save the session, like during a shopping cart update.