Location: PHPKode > projects > Movim > movim-0.5/system/Jaxl/core/jaxl.session.php
<?php

/**
 * @file Session.php
 * This file is part of MOVIM.
 *
 * @brief Class that manages session variables with minimal lock time.
 *
 * @author Guillaume Pasquet <hide@address.com>
 *
 * Yes, this class is again a singleton. But this is justified by the fact that
 * there can only be one active session that is locked down.
 *
 * @version 1.0
 * @date 26 April 2011
 *
 * Copyright (C)2011 MOVIM
 *
 * See COPYING for licensing information.
 */

if(!class_exists('Session')):

class Session
{
    protected $db;
    protected static $instances = array();
    protected static $sid = null;
    protected $container;
    protected $container_id;
    protected $max_age = 3600;

    /**
     * Loads and immediately closes the session variables for the namespace
     * $name.
     */
    protected function __construct($name)
    {
        $db_file = (($_SERVER['DOCUMENT_ROOT'] == "")? dirname(__FILE__) : $_SERVER['DOCUMENT_ROOT']).'/session.db';

        if(defined('SESSION_DB_FILE')) {
            $db_file = SESSION_DB_FILE;
        }

        if(defined('SESSION_MAX_AGE')) {
            $this->max_age = SESSION_MAX_AGE;
        }

        // Do we create the schema?
        $create = true;
        if(!file_exists($db_file)) {
            $create = true;
        }
        $this->db = new SQLite3($db_file);

        $this->container = $this->db->escapeString($name);

        if($create) { // Creating the session schema.
            $this->db->exec('CREATE TABLE IF NOT EXISTS sessions(hash VARCHAR(64) PRIMARY KEY, timestamp INTEGER)');
            $this->db->exec(
                'CREATE TABLE IF NOT EXISTS session_containers('.
                'id INTEGER PRIMARY KEY AUTOINCREMENT, '.
                'hash VARCHAR(64) REFERENCES sessions(hash) ON DELETE CASCADE, '.
                'name VARCHAR(128))'
                );
            $this->db->exec(
                'CREATE TABLE IF NOT EXISTS session_vars('.
                'container INTEGER REFERENCES session_containers(id) ON DELETE CASCADE, '.
                'name VARCHAR(128), '.
                'value TEXT)'
                );
        }

        if(self::$sid == null && isset($_COOKIE['PHPFASTSESSID'])) {
            $sessid = $this->db->escapeString($_COOKIE['PHPFASTSESSID']);
            $session = $this->db->querySingle('SELECT * FROM sessions WHERE hash="'.$sessid.'"', true);

            if(count($session) == 0) {
                $this->regenerate();
            }
            else if($session['timestamp'] + $this->max_age < time()) {
                echo 'expired! ' . ($session['timestamp'] + $this->max_age) . ' < ' . time();
                $sql = 'DELETE FROM sessions WHERE hash="'.$sessid.'"';
                echo $sql;
                $this->db->exec($sql);
                $this->regenerate();
            }
            else {
                self::$sid = $sessid;
            }
        }
        else if(self::$sid == null) {
            $this->regenerate();
        }

        // Does the container exist?
        $num_container = $this->db->querySingle('SELECT id FROM session_containers WHERE hash="'.self::$sid.'" AND name="'.$this->container.'"');
        if(!$num_container) {
            $this->db->exec('INSERT INTO session_containers(hash, name) VALUES("'.self::$sid.'", "'.$this->container.'")');
            $this->container_id = $this->db->lastInsertRowID();

            // fallback...
            if(!$this->container_id) {
                $this->container_id = $this->db->querySingle('SELECT id FROM session_containers WHERE hash="'.self::$sid.'" AND name="'.$this->container.'"');
            }
        } else {
            $this->container_id = $this->db->escapeString($num_container);
        }
    }
    
    protected function regenerate()
    {
        // Generating the session cookie's hash.
        $hash_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $hash = "";

        $exists = true;
        $sessions_tbl = $this->db->query('SELECT hash FROM sessions');
        $sessions = array();
        while($row = $sessions_tbl->fetchArray()) {
            $sessions[] = $row['hash'];
        }

        while($exists) {
            for($i = 0; $i < 64; $i++) {
                $r = rand(0, strlen($hash_chars) - 1);
                $hash.= $hash_chars[$r];
            }

            $exists = in_array($hash, $sessions);
        }

        self::$sid = $this->db->escapeString($hash);
        $sql = 'INSERT INTO sessions(hash, timestamp) VALUES("'.self::$sid.'", "'.time().'")';
        $this->db->exec($sql);
        setcookie('PHPFASTSESSID', self::$sid, time() + $this->max_age);
    }

    /**
     * Gets a session handle.
     */
    public static function start($name)
    {
        if(!isset(self::$instances[$name])) {
            self::$instances[$name] = new self($name);
        }

        return self::$instances[$name];
    }

    /**
     * Commits the session upon destruction.
     */
/*    public function __destruct()
    {
        $this->db->close();
        }*/

    /**
     * Gets a session variable. Returns false if doesn't exist.
     */
    public function get($varname)
    {
        $data = $this->db->querySingle(
            'SELECT * FROM session_vars WHERE container="'.$this->container_id.'" AND name="'.$this->db->escapeString($varname).'"',
            true);
        if(count($data) > 0) {
            return unserialize(base64_decode($data['value']));
        } else {
            return false;
        }
    }

    /**
     * Sets a session variable. Returns $value.
     */
    public function set($varname, $value)
    {
        $value = base64_encode(serialize($value));
        
        // Does the variable exist?
        $sql = 'SELECT COUNT(name) FROM session_vars '.
            'WHERE container="'.$this->container_id.'" AND name="'.$varname.'"';
        $num_vars = $this->db->querySingle($sql);
        
        if($num_vars > 0) {
            $sql = 'UPDATE session_vars '.
                'SET value="'.$this->db->escapeString($value).'" '.
                'WHERE container="'.$this->container_id.'" AND name="'.$varname.'"';
        } else {
            $sql = 'INSERT INTO session_vars(container, name, value) '.
                'VALUES("'.$this->container_id.'", "'.$this->db->escapeString($varname).'", "'.
                $this->db->escapeString($value).'")';
        }
        
        $this->db->exec($sql);

        return $value;
    }

    /**
     * Deletes a variable from the session.
     */
    public function remove($varname)
    {
        return $this->db->exec(
            'DELETE FROM session_vars '.
            'WHERE container="'.$this->container_id.'" '.
            'AND name="'.$this->db->escapeString($varname).'"');
    }

    public function delete_container()
    {
        return $this->db->exec('DELETE FROM session_containers WHERE id="'.$this->container_id.'"');
    }

    /**
     * Deletes all this session container (not the session!)
     */
    public static function dispose($name)
    {
        if(isset(self::$instances[$name])) {
            self::$instances[$name]->delete_container();
            unset(self::$instances[$name]);
            return true;
        } else {
            return false;
        }
    }
}

endif;

?>
Return current item: Movim