处理session_start()失败但仍返回true的情况

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.