0

I'm trying to improve the session management for web applications. My major issue is the session expiration and how to deal with it. For that I'd like to find out if the session is still available or not. I'm using the default file based sessions (PHP 7.1, Apache 2.4, Fedora/RHEL) and it is cookie based.

What I've found out is that the session GC gets executed when session_start() is called. It is not with the begin or end of the script execution, it happens with this function. What seems odd to me is that if session_start() and the GC consider the session as expired and want to delete the corresponding session file, $_SESSION gets populated regularly first, then the file will be deleted. That's surprising.

With that behaviour only the next following request leads to an empty $_SESSION. I would expect this with the call before - the one that deletes the file. So if I'd like to know whether the session has expired in the current request I would have to check if the session file still exists after the session_start() call. That seems strange to me.

Are there any other or better ways to check that a session has expired than looking into the file system?

I thought I could just check if $_SESSION is empty to determine that the session was renewed - but that is obviously not possible.


Update: I've found the following bug reports dealing with the issue: this and that. There's also a SO entry about the expiration problem. Current PHP source: php_session_start calls php_session_initialize calls php_session_gc.


You may want to play with this script (unreal settings are just for testing purposes):

ini_set('session.gc_maxlifetime', 2); // Session gets expired after 2 seconds
ini_set('session.gc_divisor',     1); // Delete expired session files immediately
ini_set('session.save_path',      '/some/safe/path/for/testing'); // Must be accessible for the server
//ini_set('session.use_strict_mode', true); // Uncomment if the id should be renewed, what makes no difference here

echo "Session files before session_start call<br>";
listSessionFiles();

session_start();

echo "Session files after session_start call<br>";
listSessionFiles();

echo "<hr>";

echo "Session id: "      . session_id() . "<br>";
echo "Session content: " . print_r($_SESSION, true);
$_SESSION['x'] = time(); // Populate the session with something 


function listSessionFiles() {
    echo "<ul>";
    $none = true;
    $dir  = dir(ini_get('session.save_path'));        
    while ($entry = $dir->read()) {
        if (preg_match('/^sess_/', $entry)) {
            echo "<li>" . $entry . "</li>";
            $none = false;
        }
    }
    $dir->close();
    if ($none) echo "<li>None</li>";
    echo "</ul>";
}

Just reload the page some times. Wait at least more than two seconds. Otherwise the session does not expire.

robsch
  • 9,358
  • 9
  • 63
  • 104
  • Setting the GC to run on every single request is rather nonsense. PHP sessions do not have an actual expiry, they only have a minimum lifetime. If you want a _max_ lifetime, then you should implement this yourself - store the last access time in the session, and on the next access compare with the current time, and decide whether you want to continue or kill this session. – CBroe Apr 16 '18 at 15:01
  • @CBroe That script was just to play around. Of course I don't use these settings. No, I don't want a max lifetime. I just want to find out if the session has expired or not. – robsch Apr 16 '18 at 15:05
  • indeed like @CBroe says `Setting the GC to run on every single request is rather nonsense.` Besides it can cause lag because of the disk i/o needed. – Raymond Nijland Apr 16 '18 at 15:08
  • @RaymondNijland I know. Script was just for trying it out. However, the problem doesn't get affected by these settings. – robsch Apr 16 '18 at 15:09
  • _"What I've found out is that the session GC gets executed when session_start() is called. It is not with the begin or end of the script execution, it happens with this function."_ - is that verified fact (by checking the PHP source code), or just an assumption, because it "feels like it" from what you are seeing? A lifetime of 2 seconds might also skew your results/observations, I think. Unless this is tested under halfway realistic conditions, I don't think this proves anything much at all right now. – CBroe Apr 16 '18 at 16:06
  • @CBroe From my understanding it is that way: https://github.com/php/php-src/blob/master/ext/session/session.c#L1490 – robsch Apr 16 '18 at 16:23

1 Answers1

0

One way to circumvent the problem is to use cookies with a certain lifetime (below the session lifetime). If the cookie expires it won't be sent to the server. PHP will then create a new session when session_start() is called, so $_SESSION will be empty.

This might be enough to find out that the session is not available. Although one cannot distinguish in PHP if the session has expired or anything went wrong. You can just tell that no session data is available and do appropiate things then (amongst other also destroy the newly created empty session).

robsch
  • 9,358
  • 9
  • 63
  • 104