Page 1 of 1

A session handling class.

Posted: Sun Aug 20, 2006 1:30 am
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

Posted: Sun Aug 20, 2006 1:54 am
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

Posted: Sun Aug 20, 2006 2:01 am
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

Posted: Sun Aug 20, 2006 2:21 am
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();
    }
}

Posted: Sun Aug 20, 2006 2:29 am
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

Posted: Sun Aug 20, 2006 2:33 am
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!

Posted: Sun Aug 20, 2006 2:37 am
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

Posted: Sun Aug 20, 2006 2:49 am
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();
        }
}

Posted: Sun Aug 20, 2006 3:10 am
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

Posted: Sun Aug 20, 2006 3:15 am
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!

Posted: Sun Aug 20, 2006 9:06 am
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()

Posted: Sun Aug 20, 2006 11:56 am
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.

Posted: Sun Aug 20, 2006 3:20 pm
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;

Posted: Sun Aug 20, 2006 3:23 pm
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

Posted: Mon Aug 21, 2006 3:43 am
by Luke
alright... I have posted the class here:
viewtopic.php?t=54059&highlight=