views:

159

answers:

4

A question with respect to Session Expiration in PHP.

I need my server to throw away session information if that user has been inactive for a while (for testing purposes, 5 seconds).

I've looked at this question and particular at the answer by Gumbo (+28 votes) and I've been wondering about the feasibility of this answer with respect to inactive users. On my site I already implemented this suggestion and it works fine, so long as the user requests some data at least once after the session expired. But the problem with inactive users is that they don't request new data. So the expiration code is never called.

I've been looking at session.gc_maxlife and associated parameters in my PHP.ini, but I couldn't make this work the way I wanted it to.

Any suggestions on this problem?

A: 

The garbage collector isn't called per-session, the garbage collector has a change to be called based on tge gc_* values, which can invalidate multiple sessions. So as long as someone triggers it, other people can be logged out. If you need a more reliable method, if your timeout is in minutes use a cronjob, if your timeout is in seconds you'll have to use some kind of daemon process.

Wrikken
+1  A: 

If you need to call specific expiration logic (for example, in order to update a database) and want independence from requests then it would make sense to implement an external session handler daemon that looks at access times of session files. The daemon script should execute whatever necessary for every session file that has not been accessed for a specified time.

This solution has two prerequisites: the server's filesystem supports access times (Windows does not) and you can read files from session save path.

Saul
+2  A: 

The session expiration logic I mentioned does already do what you’re expecting: The session cannot be used once it has expired.

That the session data is still in the storage doesn’t matter as it cannot be used after expiry; it will be removed when the garbage collector is running the next time. And that happens with a probability of session.gc_probability divided by session.gc_divisor on every session_start call (see also How long will my session last?).


Edit    Since you want to perform some additional tasks on an expired session, I would rather recommend to use a custom session save handler.

When using a class for the session save handler, you could write two classes, one for the basics save handler and one with a extended garbage collector that performs the additional tasks, e.g.:

interface SessionSaveHandler {
    public function open();
    public function close();
    public function read($id)
    public function write($id, $data);
    public function destroy($id);
    public function gc($callback=null);
}
class SessionSaveHandler_WithAdditionalTasks implements SessionSaveHandler {
    // …
    public function gc($callback=null) {
        if (!is_null($callback) && (!is_array($callback) || !is_callable($callback))) return false;
        while (/* … */) {
            if ($callback) $callback[0]::$callback[1]($id);
            // destroy expired sessions
            // …
        }
    }
    public static function doAdditionalTasksOn($id) {
        // additional tasks with $id
    }
}
session_set_save_handler(array('SessionSaveHandler_DB_WithAdditionalTasks', 'open'),
                         array('SessionSaveHandler_DB_WithAdditionalTasks', 'close'),
                         array('SessionSaveHandler_DB_WithAdditionalTasks', 'read'),
                         array('SessionSaveHandler_DB_WithAdditionalTasks', 'write'),
                         array('SessionSaveHandler_DB_WithAdditionalTasks', 'destroy'),
                         array('SessionSaveHandler_DB_WithAdditionalTasks', 'gc')
                         );
Gumbo
A: 

One way you can do this is using javascript to refresh the page a little after the timeout period. Granted your users will have to have Javascript enabled for this to work. You can also add extra features like having javascript pop up a timeout notice with a count down, etc. So essential what happens the session is expired due to your settings, then the refresh hits, clean up runs and your done.

<html>
<head>
<script type="text/JavaScript">
<!--
function timedRefresh(timeoutPeriod) {
    setTimeout("location.reload(true);",timeoutPeriod);
}
//   -->
</script>
</head>
<body onload="JavaScript:timedRefresh(5000);">
</body>
</html>
Grayslin
Yup, using a heartbeat is an option but in your example the "onUnload" event needs a good-bye function. And even then the expiry event would not be guaranteed if the useragent simply drops the connection. But judging from the accepted answer, Timo was not looking for a bulletproof way to execute custom code on the server when a session expires. I gather he was simply worried about session destruction.
Saul