A session handling class.

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
User avatar
daedalus__
DevNet Resident
Posts: 1925
Joined: Thu Feb 09, 2006 4:52 pm

A session handling class.

Post by daedalus__ »

I would like to write a session handling class. The only reason I can think of at the moment is just to do it.

I was wondering what makes a session handling class useful. What kind of methods should be built-in? What are the advantages and disavantages of using a database, files, or cookies to store session information?

I don't know quite what to ask here but I suppose I am trying to figure out what a session handling class should and shouldn't do. I am looking a bunch of stuff up right now but would really appreciate everyones opinion.

:D
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

I have actually started a few threads on this myself... found out some really interesting stuff.

viewtopic.php?t=53162&highlight=session+class
viewtopic.php?t=49608&highlight=session+class

A few things I have found to be crucially important are basically what arborint pointed out:

Lazy Load
Do not start session until it will actually be needed. Call session->start() within your get/set methods, and in your session->start class, just do a check to see if there is already a session id, and if not, create one (session_start())

Namespaces
This is one I have found to be PARTICULARLY useful. Make your session class abstract, and then classes that inherit from it just need to set $this->namespace to their particular namespace, and now name conflicts are no longer a problem.... very cool

Ability to store session data in multiple mediums
Setting up a session class allows you to the ability to work with session data without any need to know where it is being stored (you could build separate classes for different storage mediums)

There are actually quite a lot of reasons why session handling would be well suited for a class. Use a little imagination... Image
User avatar
daedalus__
DevNet Resident
Posts: 1925
Joined: Thu Feb 09, 2006 4:52 pm

Post by daedalus__ »

observers and registry be useful for class that handles session? :D

P.S. This sounds like it is going to be amazing fun. :P
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

I'd be happy to post what I am using ATM. It could use some rework... perhaps we can bounce some ideas off eachother and maybe come up with a KILLER session handling class. The only reason I ask before just posting it is that some people prefer to try to design a class with a blank slate

EDIT: Aww screw it... here is what I'm using. There are methods in this that I don't use and are just left over from something I was trying to implement... I really wouldn't call these classes complete either. I am in process of finishing them

Code: Select all

<?php
class Registry{
	protected $entries = array();
	public function register($name, $value){
		$this->entries[$name] = $value;
	}
	public function unregister($name){
		unset($this->entries[$name]);
	}
	public function get($name){
		return isset($this->entries[$name]) ? $this->entries[$name] : null;
	}
	public function has($name){
		return $name ? isset($this->entries[$name]) : false;
	}
	public function wipe(){
		unset($this->entries);
		$this->entries = array();
	}
	public function __get($name){
		return $this->get($name);
	}
	public function __set($name, $value){
		$this->register($name, $value);
	}
}
?>

Code: Select all

class Session extends Registry{
	
	protected static $id; 
	protected $namespace;			
	protected $regenerate;		// Set to true if you would like for session's id to be regenerated
	
	function __construct($namespace='Session', $regenerate=false) {
		
        $this->namespace = $namespace;
        $this->regenerate = $regenerate;
        
    }
    
    // Execute this method in all other methods you want to be able to lazy-start the session
    public function start(){
	    
        if (!self::$id) {
	        
	        // TODO: Research this functionality a little more
	        // If browser is Internet Explorer
            if (strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
                session_cache_limiter('must-revalidate');
            }
            session_start();
            if ($this->regenerate) {
                session_regenerate_id();
            }
            self::$id = session_id();
       }
       
    }
    
    public function register($name, $value){
	    $this->start();
	    $_SESSION[$this->namespace][$name] = $value;
    }
    
    public function get($name){
	    $this->start();
	    return isset($_SESSION[$this->namespace][$name]) ? $_SESSION[$this->namespace][$name] : false;
    }
    
	public function unregister($name){
        $this->start();
		unset($_SESSION[$this->namespace][$name]);
	}
	
    public function has($name) {
        $this->start();
        return isset($_SESSION[$this->namespace][$name]);
    } 
    
    public function wipe(){
        $this->start();
		session_unset();
		session_destroy();
    }
	
	public function clearGlobal(){
		$this->wipe();
	}
	
	public function clearLocal(){
		$this->start();
		unset($_SESSION[$this->namespace]);
	}
    
    public function close(){
        session_write_close();
    }
}
Last edited by Luke on Sun Aug 20, 2006 2:32 am, edited 1 time in total.
User avatar
daedalus__
DevNet Resident
Posts: 1925
Joined: Thu Feb 09, 2006 4:52 pm

Post by daedalus__ »

I usually do but I have become comfortable with the members of this forum and generally trust the things that they say and code. :D
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

Well you are free to use whatever you like from those classes... take what you like and leave the rest. Maybe together we can knock out a killer class or set of classes!
User avatar
daedalus__
DevNet Resident
Posts: 1925
Joined: Thu Feb 09, 2006 4:52 pm

Post by daedalus__ »

After reading those threads I really was thinking of some sort of registry/observer thing happening.

I'm going to take some time to think about it while I make my database class.

I really like the idea of namespaces.

I'll post some ideas in this thread when I have them. :D
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

Yes the namespace thing is DEFINATELY the coolest feature so far. It basically allows me to create subclasses of the session class for use in just about anything, and when I am done with the session data specific to that particular area, I can destroy the session data within that particular class and not worry about whether I destroyed imortant info somewhere else. Like so...

Code: Select all

class User_Session extents Session{
        // Do stuff specific to user's session
}
class User extends Active_Record{
	public function __construct(){
		$this->session = new User_Session(get_class($this));
                $this->session->register('user_id', $this->id);
	}
        public function clear(){
                // We can safely wipe this session without worry of wiping general session data
                $this->session->wipe();
        }
}
User avatar
daedalus__
DevNet Resident
Posts: 1925
Joined: Thu Feb 09, 2006 4:52 pm

Post by daedalus__ »

That looks hawt and like just what I need it to do.

I probably wont' post again tonight cause i am too tired to thinke.

let ya know where im at tomorrow or monday
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

Image yea, I'm nodding off too. I will be working on PHP classes all day tomorrow, so maybe we'll work on it tomorrow a little bit. G'night!
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

This is the one I am currently using:

Code: Select all

<?php

class jmt_Session
{
    private static $db;
    private static $link;
    
    public static function setDb(array $db)
    {
        self::$db = $db;
    }
    
    public static function open ()
    {
        if (self::$link = mysql_connect(self::$db['HOST'], self::$db['USER'], self::$db['PASS'])) {
            return mysql_select_db(self::$db['DATABASE'], self::$link);
        } else {
            return false;
        }
    }
    
    public static function close ()
    {
        return mysql_close(self::$link);
    }
    
    public static function read ($id)
    {   
        $id = mysql_real_escape_string($id, self::$link);
        $sql = "SELECT `data` FROM `session` WHERE `sessionId` = '$id'";
        
        if (($result = mysql_query($sql, self::$link)) && ($row = mysql_fetch_assoc($result))) {
            return $row['data'];
        } else {
            return '';
        }
    }
    
    public static function write($id, $data) 
    { 
        $access = time();
        
        $id = mysql_real_escape_string($id, self::$link);
        $data = mysql_real_escape_string($data, self::$link);
          
        $sql = "REPLACE  
                INTO `session` (`sessionId`, `access`, `data`)
                VALUES('$id', '$access', '$data')"; 
        return mysql_query($sql, self::$link);
    }
    
    public static function destroy ($id)
    {
        $id = mysql_real_escape_string($id, self::$link);
        $sql = "DELETE FROM `session` WHERE `sessionId` = '$id'";
        
        return mysql_query($sql, self::$link);
    }
    
    public static function clean ($max) 
    {     
        $old = time() - $max; 
     
        $sql = "DELETE 
                FROM   `session` 
                WHERE  `access` < '$old'"; 
     
        return mysql_query($sql, self::$link); 
    }
}

?>
To initialise the connection etc. I use:

Code: Select all

jmt_Session::setDb(array('HOST' => 'localhost', 'USER' => 'username', 'PASS' => 'password', 'DATABASE' => 'db'));
before calling session_set_save_handler()
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

and then you just assign session vars with

Code: Select all

$_SESSION['foo'] = 'bar';
?

I am going to rewrite my session class so that the main class just has the responsibility of setting and retreiving values. It will have a method called getData() or something that will create a new object called SessionDataFile, or SessionDataDatabase and then these classes will have the responsibility of storage.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

correct.

I should add, this is the table structure:

Code: Select all

DROP TABLE IF EXISTS `session`;
CREATE TABLE `session` (
  `sessionId` varchar(50) NOT NULL default '',
  `userId` int(10) unsigned NOT NULL default '0',
  `data` longtext NOT NULL,
  `access` int(10) unsigned NOT NULL default '0',
  PRIMARY KEY  (`sessionId`)
) ENGINE=InnoDB;
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

I'm rewriting my session class right now. I will post the first working solution I come up with. Probably be within the hour
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

alright... I have posted the class here:
viewtopic.php?t=54059&highlight=
Post Reply