Custom PHP5 Session Handler
So, after reading several posts — and then assessing the needs of our system, we have moved to a custom session handler for our websites. I initially read about this in PHP Security by Chris Shiflett and decided to research more. There are several benefits to this method, and the implementation is rather simple.
I have adapted some code and processes I have seen from other places to fit my needs.
This creates a session class, which handles the custom functions in the constructor. The only thing I am passing through is our PDO Database connection, which is already opened prior to the session. This eliminates the need to open/close the database, but true still needs to be returned.
This is in it’s initial phase and everything is working well so far. More tweaks will be made in the near future. Implementation is simple. We have a global configuration that calls:
session-file.php
$sh = new session( $database_handle );
The database setup:
database.sql
CREATE TABLE 'sessions' ('id' varchar(32) NOT NULL default '','access' int(10) unsigned default NULL,'data' text,PRIMARY KEY ('id')) TYPE=InnoDB
And the sessions work as normal after that point.
class.session.php
class session{private $_session;public $maxTime;private $db;public function __construct(PDO $database){$this->db = $database;$this->maxTime['access'] = time();$this->maxTime['gc'] = get_cfg_var('session.gc_maxlifetime');session_set_save_handler(array($this, '_open'),array($this, '_close'),array($this, '_read'),array($this, '_write'),array($this, '_destroy'),array($this, '_clean'));register_shutdown_function('session_write_close');session_start();}public function _open(){return true;}public function _close(){$this->_clean($this->maxTime['gc']);return true;}public function _read($id){$getData = $this->db->prepare("SELECT 'data'FROM 'sessions' AS 'Session'WHERE 'Session'.'id' = ?");$getData->bindParam(1, $id);$getData->execute();$allData = $getData->fetch(PDO::FETCH_ASSOC);$totalData = count($allData);$hasData = (bool) $totalData >= 1;return $hasData ? $allData['data'] : '';}public function _write($id, $data){$getData = $this->db->prepare("REPLACE INTO'sessions'VALUES (?, ?, ?)");$getData->bindParam(1, $id);$getData->bindParam(2, $this->maxTime['access']);$getData->bindParam(3, $data);return $getData->execute();}public function _destroy($id){$getData = $this->db->prepare("DELETE FROM'sessions'WHERE 'id' = ?");$getData->bindParam(1, $id);return $getData->execute();}public function _clean($max){$old = ($this->maxTime['access'] - $max);$getData = $this->db->prepare("DELETE FROM'sessions'WHERE 'access' < ?");$getData->bindParam(1, $old);return $getData->execute();}}
I initially had a few problems, but resolved those by turning off session.auto_start in php.ini and everything worked fine.
13 Comments Add your comment
Hamidof June 3rd, 2006
$this->_clean($this->maxTime[’gc’]);
I think instead of this line you should just delete the current session, since its fresh and maybe its lifetime still remains!
Cheers
Hamidof June 4th, 2006
Sorry, my mistake:)
Nate Klaiber June 5th, 2006
Hamidof,
No problem :)
iQ.mind January 26th, 2007
Nice idea, Nate! Thanx!
Evolic April 13th, 2007
Why do you selecting records in _clean() function,
instead of deleting them?
Best regards
Nate Klaiber April 14th, 2007
RE: Evolic
Wow, I am surprised I hadn't caught that yet - You are correct, it should be 'DELETE' instead of 'SELECT'.
Thanks for bringing it to my attention - it has been fixed.
Amit June 11th, 2007
Two questions:
1.) Close database doesn't really close database but just clears gc's maxlifetime.
2.) What is the idea of playing with gc's maxlifetime and clearing it in first place?
Amit June 11th, 2007
EDIT: 1.) Close database doesn’t really close database but just clears gc’s maxlifetime. -- So what's happening there?
Jeffery Fernandez July 22nd, 2007
Does anyone know how I can retrieve the session data and utilise them for show list of online users ?
In earlier versions of PHP I used to be able to see the session data as a serialised string. However in PHP 5.2.3 which I am currently using, I just see a long string. Does anyone know what format the string is in ?
mark October 18th, 2007
one question:
how is the database connection passed over to the class?
especially if you got (like me) an own mysql-class which is initialized at the beginning of the script - like this:
$db = new db_MySQL;
$db->Connect();
$mver = $db->Version();
Thanks! Mark
Phil October 23rd, 2007
Mark, if I read this right, the DB is passed into the class using the constructor.
$db = new db_MySQL;
$db->Connect();
$session = new session( $db );
You might have to tweak his DB code in the class to work with your DB object...
Willy February 22nd, 2008
Hello, this is my situation:
I have a Login system.
The session expires after 24 minutes. (1440=>session.gc_maxlifetime)
I need that after 30 minutes of inactivity the user be desactivated, then when logging in again, be redirected to the last page visited. (only the password required this time).
But after 60 minutes of inactivity the user be disconnected at all. (username and pass required to log in again).
The problem is that after 24 min. the session expires.
How can i do?? It works on localhost, but not on-line.
Thanks.
Unreality June 19th, 2008
I wouldn't call _clean everytime a session is closed. Too much performance needed. In php the gc probability is set to 1%. So every 100 Sessions the gc is called, that's more then enought