session_start() issues regarding illegal characters, empty session ID and failed session

The problem:

session_start() relies on $_COOKIE[session_name()], so, if you edit the cookie value to something like #$#$FDSFSR#"#"$"#$" or simply empty it (not delete the cookie) and refresh a page with your code:

if (!session_id()) {
    session_start();
}

The following warning is generated:

PHP Warning: session_start(): The session id is too long or contains illegal characters, valid characters are a-z, A-Z, 0-9 and '-,' in /home/username/public_html/session_start.php on line 7

This happens because php is checking if session_id() exists and, in fact, it exists, but contains illegal characters not allowed as session_id name.

A valid session id may contain only digits, letters A to Z (both upper and lower case), comma and dash ([-,a-zA-Z0-9]) between 1 and 128 characters.


My solution:

Check if $_COOKIE[session_name()] is set and contains a valid session_id prior to session_start(), otherwise, delete the session cookie and only then session_start(), something like:

function safeSession() {
    if (isset($_COOKIE[session_name()]) AND preg_match('/^[-,a-zA-Z0-9]{1,128}$/', $_COOKIE[session_name()])) {
        session_start();
    } elseif (isset($_COOKIE[session_name()])) {
        unset($_COOKIE[session_name()]);
        session_start(); 
    } else {
        session_start(); 
    }
}

start the session:

safeSession();

NOTES:

1 - session_name is defined on your php.ini as session.name = SOMETHING (default is PHPSESSID), so, you may be looking for a cookie matching session.name. You can use the session_name() function to retrieve it.

2 - Session cookie manipulation can be used by hackers to dump information from your server (username and path) if ini_set('display_errors', 1); is set.

3 - session_regenerate_id(true) works but, because it checks the current session_id prior to assign a new one, generates warnings.

4 - I've tested the code with several invalid session names and no errors or warnings were generated, everything worked and intended.


References:

session.c Source Code


My bet would be, you were under attack at this time. This means someone manipulated your session cookie for example.

Since session_start(); is a system function, I don't think it would generate invalid ids.

In my opinion, option 2 is the best. But if I remember correct, you need to set a custom error handler for this.

This answer seems better for me:

$ok = @session_start();
if(!$ok){
   //Hello Hacker ;)
   session_regenerate_id(true); // replace the Session ID
   session_start(); 
}