#native_company# #native_desc#
#native_cta#

Session MySQL

By Minc Damon
on August 29, 2003

Version: 0.3.0

Type: Class

Category: Databases

License: GNU General Public License

Description: MySQL Database session management

<?php
# +----------------------------------------------------------------------------+
# | Copyright (c) 2002 - 2003 Undone, Labs.                                    |
# +----------------------------------------------------------------------------|
# | This library is free software; you can redistribute it and/or modify it    |
# | under the terms of the GNU Lesser General Public License as published by   |
# | the Free Software Foundation; either version 2.1 of the License, or        |
# | (at your option) any later version.                                        |
# |                                                                            |
# | This library is distributed in the hope that it will be useful, but        |
# | WITHOUT ANY WARRANTY; without even the implied warranty of                 |
# | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser   |
# | General Public License for more details.                                   |
# |                                                                            |
# | You should have received a copy of the GNU Lesser General Public           |
# | License along with this library; if not, write to the Free Software        |
# | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  |
# |                                                                            |
# | For new version, support, bugs, commercial use or related subjects,        |
# | please contact the author.                                                 |
# +----------------------------------------------------------------------------|
# | Author: Minc <[email protected]>                                         |
# +----------------------------------------------------------------------------+

define('SESSION_VIA_COOKIE', 1);
define('SESSION_VIA_GET',    2);
define('SESSION_VIA_PATH',   3);

/**
 * Session management using MySQL Database
 *
 * @author   Minc <[email protected]> $
 * @version  $id: Session_MySQL.php,v 0.3.0 2003/08/29 17:06:56 minc Exp $
 * @package  session
 */
class Session_MySQL {
    // {{{ Properties

    // ---BEGIN CLASS CONFIGURATION VARIABLES---
    /**
     * Default session method, one of
     * SESSION_VIA_COOKIE, SESSION_VIA_GET, SESSION_VIA_PATH
     * @var integer
     * @access private
     */
    var $method = SESSION_VIA_GET;

    /**
     * Fallback on failed or die(), this property actually needed if using cookie
     * @var boolean TRUE if fallback, else FALSE
     * @access private
     */
    var $fallback_on_failed = false;

    /**
     * Default fallback method, this property actually needed if using cookie
     * @var integer
     * @access private
     */
    var $fallback_method = SESSION_VIA_GET;

    /**
     * Session name (only use if method via cookie or via get)
     * @var string
     * @access private
     */
    var $name = 'sid';

    /**
     * An array contains register variables
     * @var array
     * @access private
     */
    var $vars = array();

    /**
     * Use to save session id
     * @var string
     * @access private
     */
    var $id = null;

    /**
     * Storeable vars value delimiter
     * @var string
     * @access private
     */
    var $delimiter_value = '=>';

    /**
     * Storeable vars delimiter
     * @var string
     * @access private
     */
    var $delimiter = '|';

	/**
	 * Object variable delimiter
	 * @var string
	 * @access private
	 */
	var $ob_delimiter = '>>';

	/**
	 * Method for userialize object
	 * @var string
	 * @access private
	 */
	var $incmethod = 'include';
	
    // ---END CLASS CONFIGURATION VARIABLES---

    // ---BEGIN MySQL CONFIGURATION VARIABLES--- 
    /**
     * MySQL username
     * @var string
     * @access private
     */
    var $mysql_username = 'session';

    /**
     * MySQL user password
     * @var string
     * @access private
     */
    var $mysql_password = '';
    
    /**
     * MySQL server address
     * @var string
     * @access private
     */
    var $mysql_server = 'localhost';

    /**
     * MySQL link resource
     * @var resource
     * @access private
     */
    var $mysql_link = null;

    /**
     * MySQL database name
     * @var string
     * @access private
     */
    var $mysql_dbname = null;

    /**
     * MySQL table name
     * @var string
     * @access private
     */
    var $mysql_tbname = 'session';

    // ---END MySQL CONFIGURATION VARIABLES---

    // ---BEGIN SESSION CONFIGURATION VARIABLES---

    /**
     * number of minutes when data will seen as garbage 
     * @var integer default is 24 hours
     * @access private
     */
    var $gc_maxlifetime = 1440;

    /**
     * Cookie lifetime (use when using session via cookie)
     * @var integer default is 0 seconds or until the end of session
     * @access private
     */
    var $cookie_lifetime = 0;

    /**
     * Cookie path
     * @var string
     * @access private
     */
    var $cookie_path = "/";

    /**
     * Cookie domain
     * @var string
     * @access private
     */
    var $cookie_domain = "";

    /**
     * Cookie secure
     * @var integer
     * @access private
     */
    var $cookie_secure = 0;

    /**
     * Cache limiter
     * @var string one of 'private', 'public', 'no'
     * @access private
     */
    var $cache_limiter = 'private';

    /**
     * Cache expire
     * @var integer number of minutes
     * @access private
     */
    var $cache_expire = 1440;
    // ---END SESSION CONFIGURATION VARIABLES---

    // }}}
    // {{{ Constructor
    /**
     * Create new instance Session object
     *
     * @param string $mysql_dbname
     * @param (optional) string  $mysql_username
     * @param (optional) string  $mysql_password
     * @param (optional) string  $mysql_hostname
     * @param (optional) mixed   $mysql_port
     * @param (optional) string  $name
     * @param (optional) integer $method
     * @param (optional) string  $save_path
     *
     * @access public
     */
    function Session_MySQL($mysql_dbname, $mysql_username = null, $mysql_password = null, $mysql_hostname = null,
                           $mysql_port = null)
    {
        $this->mysql_dbname   = $mysql_dbname;
        if (isset($mysql_username)) $this->mysql_username  = $mysql_username;
        if (isset($mysql_password)) $this->mysql_password  = $mysql_password;
        if (isset($mysql_host)    ) $this->mysql_server    = $mysql_hostname;
        if (isset($mysql_port)    ) $this->mysql_server   .= ':' . $mysql_port;
    }
    // }}}

    /**
     * Sets session parameters
     *
     * @param (optional) string  $name
     * @param (optional) integer $method
     * @param (optional) integer $fallback_method
     *
     * @access public
     */
    function setParameters($name = null, $method = null, $fallback_method = null) {
        if (!empty($name)           ) $this->name            = $name;
        if (!empty($method)         ) $this->method          = $method;
        if (!empty($fallback_method)) $this->fallback_method = $fallback_method;
    }

    /**
     * Register vars to session
     *
     * @param string $varname Variable name
     * @access public
     */
    function register($varname) {
            if (!empty($varname)) $this->vars[$varname] = null;
    }

    /**
     * Find the whether var is registered
     *
     * @param string $varname Variable name
     * @return boolean
     * @access public
     */
    function is_registered($varname) {
        if (isset($this->vars[$varname])) return true;
        
        return false;
    }

    /**
     * Unregister vars from the session
     *
     * @param string $varname Variable name
     * @access public
     */
    function unregister($varname) {
        if (!empty($varname) && isset($this->vars[$varname])) unset($this->vars[$varname]);
    }
                
    /**
     * Open new session
     *
     * @access private
     */
    function open() {
        // try to get session id
        $session_id = $this->getID($this->method);
        if ($session_id == null) {
            $this->id = $this->randID();
        } else {
            $this->id = $session_id;
        }

        
        @ini_set('track_errors', true);
        $this->mysql_link = @mysql_connect($this->mysql_server, $this->mysql_username, $this->mysql_password);

        @ini_restore('track_errors');
        if (empty($this->mysql_link)) {
            $err = (@mysql_error($this->mysql_link) != '') ? $err : $php_errormsg;
            $this->halt(E_USER_ERROR, @mysql_errno($this->mysql_link), $err);
        }
        
        if (!@mysql_select_db($this->mysql_dbname, $this->mysql_link)) {
            $this->halt(E_USER_ERROR, mysql_errno($this->mysql_link), mysql_error($this->mysql_link));
        }

        if (!$this->is_table_exist($this->mysql_dbname, $this->mysql_tbname))  {
            $this->halt(E_USER_ERROR, 1, 'Session table is not exists, please create before');
        } else {
            $this->tbintrospection();
        }

        return true;
    }

    /**
     * Insert into database table
     *
     * @param string $sess_data Session data
     * @access private
     */
    function write($sess_data) {
        if ($this->is_session_exists($this->id)) {
            $sql = "UPDATE " . $this->mysql_tbname . " SET session_data='" . $sess_data . "', session_time=" . $this->timestamp2mysql(time()) . " "
                  ."WHERE session_id='" . $this->id . "'";
        } else {
            $sql = "INSERT INTO " . $this->mysql_tbname . " VALUES('" . $this->id . "', '" . $sess_data . "', " . $this->timestamp2mysql(time()) . ")";
        }

        if (!@mysql_query($sql, $this->mysql_link)) {
            $this->halt(E_USER_ERROR, mysql_errno($this->mysql_link), mysql_error($this->mysql_link));
        }
    }

    /**
     * Read data from database table
     *
     * @access private
     */
    function read() {
        if (($result = @mysql_query("SELECT session_data FROM " . $this->mysql_tbname . " WHERE session_id='" . $this->id . "'", $this->mysql_link)) === false) {
            $this->halt(E_USER_ERROR, mysql_errno($this->mysql_link), mysql_error($this->mysql_link));
        }

        $row = mysql_fetch_assoc($result);
        return $row['session_data'];
    }

    /**
     * Find the whether table is already exist
     *
     * @param string $dbname Database name
     * @param string $tbname Table name
     *
     * @access private
     */
    function is_table_exist($dbname, $tbname) {
        if (($result = mysql_list_tables($dbname, $this->mysql_link)) === false) {
            return false;
        }
    
        while ($row = mysql_fetch_row($result)) {
            if ($row[0] == $tbname) {
                mysql_free_result($result);
                return true;
            }
        }

        return false;
    }

    /**
     * Get fields table structure information
     *
     * @param string $tbname
     * @access private
     */
    function getTbStructure($tbname) {
        if (($result = @mysql_query("SELECT * FROM " . $tbname, $this->mysql_link)) === false) {
            $this->halt(E_USER_ERROR, mysql_errno($this->mysql_link), mysql_error($this->mysql_link));
        }

        $fields = array();
        for ($i = 0; $i < mysql_num_fields($result); $i++) {
            $name = mysql_field_name($result, $i);
            $fields[$name]['type'] = mysql_field_type($result, $i);
            $fields[$name]['len']  = mysql_field_len($result, $i);
            $fields[$name]['flag'] = mysql_field_flags($result, $i);
        }

        return $fields;
    }

    /**
     * Introspection existing session table structure
     *
     * @access private
     */
    function tbintrospection() {
        $fields = $this->getTbStructure($this->mysql_tbname);

        if (!isset($fields['session_id'])) {
            if (!@mysql_query("ALTER TABLE " . $this->mysql_tbname . " ADD session_id VARCHAR(32) NOT NULL FIRST")) {
                $this->halt(E_USER_ERROR, mysql_errno($this->mysql_link), mysql_error($this->mysql_link));
            }

            if (!@mysql_query("ALTER TABLE " . $this->mysql_tbname . " ADD UNIQUE(session_id)", $this->mysql_link)) {
                $this->halt(E_USER_ERROR, mysql_errno($this->mysql_link), mysql_error($this->mysql_link));
            }

        } else {
            if ($fields['session_id']['type'] != 'string' || $fields['session_id']['len']  != 32 ||
                !ereg('not_null',   $fields['session_id']['flag']))
            {
                if(!mysql_query("ALTER TABLE " . $this->mysql_tbname . " CHANGE session_id session_id VARCHAR(32) NOT NULL", $this->mysql_link)) {
                    $this->halt(E_USER_ERROR, mysql_errno($this->mysql_link), mysql_error($this->mysql_link));
                }

                if(!ereg('primary_key', $fields['session_id']['flag'])) {
                    if (!@mysql_query("ALTER TABLE " . $this->mysql_tbname . " ADD UNIQUE (session_id)", $this->mysql_link)) {
                        $this->halt(E_USER_ERROR, mysql_errno($this->mysql_link), mysql_error($this->mysql_link));
                    }
                }
            }
        }
        

        if (!isset($fields['session_data'])) {
            if (!@mysql_query("ALTER TABLE " . $this->mysql_tbname . " ADD session_data TEXT AFTER session_id", $this->mysql_link)) {
                $this->halt(E_USER_ERROR, mysql_errno($this->mysql_link), mysql_error($this->mysql_link));
            }
        } else {
            if ($fields['session_data']['type'] != 'blob') {
                if (!@mysql_query("ALTER TABLE " . $this->mysql_tbname . " CHANGE session_data session_data TEXT")) {
                    $this->halt(E_USER_ERROR, mysql_errno($this->mysql_link), mysql_error($this->mysql_link));
                }
            }
        }

        if (!isset($fields['session_time'])) {
            if (!@mysql_query("ALTER TABLE " . $this->mysql_tbname . " ADD session_time TIMESTAMP(14) AFTER session_data", $this->mysql_link)) {
                $this->halt(E_USER_ERROR, mysql_errno($this->mysql_link), mysql_error($this->mysql_link));
            }
        } else {
            if ($fields['session_time']['type'] != 'timestamp' || $fields['session_time']['len'] != 14) {
                if (!@mysql_query("ALTER TABLE " . $this->mysql_tbname . " CHANGE session_time session_time TIMESTAMP(14)", $this->mysql_link)) {
                    $this->halt(E_USER_ERROR, mysql_errno($this->mysql_link), mysql_error($this->mysql_link));
                }
            }
        }

        $fields = $this->getTbStructure($this->mysql_tbname);

        if (count($fields != 3)) {
            reset($fields);
            for($i = 0; $i < 3; $i++) {
                next($fields);
            }

            while(list($field, $atts) = each($fields)) {
                if (!@mysql_query("ALTER TABLE " . $this->mysql_tbname . " DROP " . $field, $this->mysql_link)) {
                    $this->halt(E_USER_ERROR, mysql_errno($this->mysql_link), mysql_error($this->mysql_link));
                }
            }
        }
    }

    /**
     * find the wheter session is exists
     *
     * @access private
     */
    function is_session_exists($id) {
        if (($result = @mysql_query("SELECT session_id FROM " . $this->mysql_tbname . " WHERE session_id='" . $this->id . "'", $this->mysql_link)) === false) {
                $this->halt(E_USER_WARNING, mysql_errno($this->mysql_link), mysql_error($this->mysql_link));
        }

        if (mysql_num_rows($result) != 0) {
            mysql_free_result($result);
            return true;
        }

        mysql_free_result($result);
        return false;
    }

    /**
     * Convert php timestamp to mysql timestamp
     *
     * @param integer $ts
     * @access private
     */
    function timestamp2mysql($ts) 
    { 
        $d=getdate($ts);
        
        $yr=$d["year"];
        $mo=$d["mon"];
        $da=$d["mday"];
        $hr=$d["hours"];
        $mi=$d["minutes"];
        $se=$d["seconds"]; 

        return sprintf("%04d%02d%02d%02d%02d%02d",$yr,$mo,$da,$hr,$mi,$se); 
    }

    /**
     * Start session via cookie
     *
     * @access private
     */
    function start_via_cookie() {
        $session_id = $this->getID(SESSION_VIA_COOKIE);
        if ($session_id == null) {
            return $this->sendcookie($this->name, $this->id, $this->cookie_lifetime, $this->cookie_path,
                                     $this->cookie_domain, $this->cookie_secure);
        }

        return true;
    }

    /**
     * Start session via get
     *
     * @access private
     */
    function start_via_get() {
        $session_id = $this->getID(SESSION_VIA_GET);
        if ($session_id == null) {
            $getvars = array();
            if (!empty($_GET)) {
                $getvars = $_GET;
            }
            
            $getvars[$this->name] = $this->id;
            $newquery = $this->array2querystring($getvars);
            $destination = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] . '?' . $newquery;
            $this->redirect($destination);
        }

        return true;
    }

    /**
     * Start session via path
     *
     * @access private
     */
    function start_via_path() {
        $session_id = $this->getID(SESSION_VIA_PATH);
        if ($session_id == null) {
            $destination = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . '/' . $this->id;
            $this->redirect($destination);
        }

        return true;
    }

    /**
     * Generate random id
     *
     * @return string
     */
    function randID() {
        return( md5( uniqid( mt_rand() ) ) );
    }

    /**
     * Make hexadecimal 32 bit for this session id
     *
     * @return string Hexadecimal representation
     * @access private
     */
    function key4id() {
        $digest = pack('H*', $this->id);
        $result = array();
        for ($i = 0; $i < 4; $i++) {
            $result[$i] = $digest[$i + 1] ^ $digest[($i + 1) + 4];
            $result[$i] = $result[$i] ^ $digest[($i + 1) + 8];
        }

        return(bin2hex(implode('', $result)));
    }

    /**
     * Get session id, if sets
     *
     * @param integer $method Session via method
     * @access private
     */
    function getID($method) {
        $id = null;
        switch($method) {
            case SESSION_VIA_COOKIE:
                if (isset($_COOKIE[$this->name]) && ereg("[0-9a-z]{32}", $_COOKIE[$this->name])) $id = $_COOKIE[$this->name];
            break;
            case SESSION_VIA_PATH:
                if (ereg("/([0-9a-z]{32})", $_SERVER['REQUEST_URI'], $regs)) $id = $regs[1];
            break; 
            default:
                if (isset($_GET[$this->name]) && ereg("[0-9a-z]{32}", $_GET[$this->name])) $id = $_GET[$this->name];
            break;
        }

        return $id;
    }
    

        /**
     * Put the session ID via method
     *
     * @access private
     * @return boolean
     */
    function putID() {
        switch  ($this->method) {
            case SESSION_VIA_COOKIE:
                return $this->start_via_cookie();
            break;
            case SESSION_VIA_PATH:
                return $this->start_via_path();
            break;
            default:
                return $this->start_via_get();
            break;
        }
    }

    /**
     * Turn in array to query string
     *
     * @param array $array
     * @return string
     * @access private
     */
    function array2querystring($array) {
        if (!is_array($array)) return;

        reset($array);
        $queries = array();
        while(list($key, $val) = each($array)) {
            $queries[] = sprintf("%s=%s", $key, urlencode($val));
        }

        return(implode('&', $queries));
    }

    /**
     * Browser redirect
     *
     * @param string $url
     *
     * @access private
     */
    function redirect($url) {
        $serversoftware = '';

        // against a IIS 5.0 bug
        if (isset($_SERVER) && !empty($_SERVER['SERVER_SOFTWARE'])) {
            $serversoftware = $_SERVER['SERVER_SOFTWARE'];
        } elseif (isset($HTTP_SERVER_VARS) && !empty($HTTP_SERVER_VARS['SERVER_SOFTWARE'])) {
            $serversoftware = $HTTP_SERVER_VARS['SERVER_SOFTWARE'];
        }

        if (!empty($serversoftware) && $serversoftware == 'Microsoft-IIS/5.0') {
            header('Refresh=0; url=' . $url);
        } else {
            header('Location: ' . $url);
        }
    }

    /**
     * Send a cookie variable and try to get information about cookie
     *
     * @param string  $name
     * @param string  $value
     * @param integer $expire
     * @param string  $path
     * @param string  $domain
     * @param integer $secure
     *
     * @access private
     * @return boolean True if cookie accepted, otherwise false
     * @see setcookie()
     * @see redirect()
     * @see array2querystring()
     */
    function sendcookie($name, $value = null, $expire = 0, $path = null, $domain = null , $secure = 0) {
        $status = false;

        if (!isset($_GET['cookiesent'])) {
            setcookie($name, $value, $expire, $path, $domain, $secure);

            $getvars = array();
            if (!empty($_GET)) {
                $getvars = $_GET;
            }

            $getvars['cookiesent'] = 1;
            $newquery = $this->array2querystring($getvars);

            $destination = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] .'?' . $newquery;
            $this->redirect($destination);
        }

        if (isset($_GET['cookiesent'])) {
            if (isset($_COOKIE[$name])) {
                $status = true;
            }
        }

        return $status;
    }

    /**
     * Encode session data using php serialized 
     *
     * @access public
     */
    function encode() {
        reset($this->vars);
        $data = "";
        $i = 0;
        while(list($key, $val) = each($this->vars)) {
			if (is_object($this->vars[$key])) {
				$s = $this->serializeObject($val, $this->ob_delimiter);
			} else {
				$s = serialize($val);
			}

            $data .= sprintf("%s%s%s", $key, $this->delimiter_value, $s);
            if ($i < count($this->vars) - 1) $data .= $this->delimiter;
            $i++;
        }
        
		echo $data;
        return($data);
    }

    /**
     * Decode session data from string
     *
     * @param string $data
     * @access public
     */
    function decode($data) {
        $vars = explode($this->delimiter, trim($data));
        $data = array();
        while(list($key, $val) = each($vars)) {
            list($name, $value) = explode($this->delimiter_value, $val);

			if (substr($value, 0, 1) == 'O') {
				$data[$name] = $this->unserializeObject($value, $this->ob_delimiter, $this->incmethod);
			} else {
				$data[$name] = unserialize($value);
			}
		}

        return($data);
    }

	/**
	 * Get class defined files of the object
	 * Searching all included files where the object class
	 * was defined
	 *
	 * @param object $ob
	 *
	 * @return string or FALSE on failed
	 * @access private
	 */
	function getClassFiles($ob) {
		if (!is_object($ob)) return false;

		$included = get_included_files();
		reset($included);
		while (list($i, $file) = each($included)) {
			if(($fp = @fopen($file, 'r')) === false) return false;

			while (!feof($fp)) {
				$line = fgets($fp);
				$regex = '/(classs+' . get_class($ob) . ')(s+extendss+[w]*s*{|s*{)/i';
				if(preg_match($regex, $line, $matches)) {
					fclose($fp);
					return $file;
				}
			}

			fclose($fp);
		}
	}

	/**
	 * Custom serialize function for the object
	 * The string output is serialized object concatenated
	 * with files where the class of object defined
	 *
	 * @param object $ob
	 * @param string $delimiter
	 *
	 * @return string or FALSE on failed
	 * @access private
	 */
	function serializeObject($ob, $delimiter) {
		if (!is_object($ob)) return false;

		if (($src = $this->getClassFiles($ob)) === false) return false;

		$s  = serialize($ob);
		$s .= $delimiter . $src;

		return($s);
	}

	/**
	 * Unserialize custom serialized object
	 * This function will automatic include a file
	 * that concatenated in string after delimiter
	 *
	 * @param string $s         custom serialized object
	 * @param string $delimiter
	 * @param string $incmethod    include method, if "require"
	 *                          file will include using require_once()
	 *
	 * @return object or FALSE on failed
	 * @access private
	 * @see serializeObject()
	 */
	function unserializeObject($s, $delimiter, $incmethod = 'include') {
		if (substr($s, 0, 1) != 'O' || substr($s, -1, 1) == '}') return false;

		$buffer = strrev($s);
		$pos = strlen($s) - strpos($buffer, $delimiter);
		$src = substr($s, $pos);
		$ob  = substr($s, 0, $pos - strlen($delimiter));

		if ($src != __FILE__) {
			if ($incmethod == 'require') {
				require_once($src);
			} else {
				include_once($src);
			}
		}

		return(unserialize($ob));
	}

    /**
     * Put all register variable into GLOBALS variables
     *
     * @access private
     */
    function put2globals() {
        while(list($name, $value) = each($this->vars)) {
            $GLOBALS[$name] = $value;
        }
    }

    /**
     * Send the HTTP header
     *
     * @access private
     */
    function sendHeader() {
        $now = gmdate('D, d M Y H:i:s') . ' GMT';
        $lastmod = gmdate("D, d M Y H:i:s", getlastmod()) . " GMT";
        header('Expires: ' . $now);
        header('Last-Modified: ' . $lastmod);

        switch ($this->cache_limiter) {
            case 'private':
                header('Cache-Control: private');
                header('Cache-Control: max-age='   . $this->cache_expire * 60);
                header('Cache-Control: pre-check=' . $this->cache_expire * 60);
            break;
            case 'public':
                header("Cache-Control: public");
                header("Cache-Control: max-age="   . $this->cache_expire * 60);
            break;
            default:
                header("Cache-Control: no-cache, no-store");
                header("Cache-Control: must-revalidate, post-check=0, pre-check=0, max-age=0");
                header("Pragma: no-cache");
            break;
        }
    }

    /**
     * Save session data for future use
     *
     * @access public
     */
    function save() {
        $this->put2globals();
        $sess_data = $this->encode();

        include_once 'Crypt/HCEMD5.php';
        $hcemd5 = new Crypt_HCEMD5($this->key4id());
        $sess_data = $hcemd5->encodeMimeSelfRand($sess_data);

        $this->write($sess_data);
    }

    /**
     * Load session data for use
     *
     * @access public
     */
    function load() {
        $sess_data = $this->read();
        
        include_once 'Crypt/HCEMD5.php';
        $hcemd5 = new Crypt_HCEMD5($this->key4id());
        $sess_data = $hcemd5->DecodeMimeSelfRand($sess_data);

        $this->vars = $this->decode($sess_data);

        $this->put2globals();
    }

    /**
     * Detroy all session data
     *
     * @access public
     */
    function destroy() {
        if (!mysql_query("DELETE FROM " . $this->mysql_tbname . " WHERE session_id='" . $this-> id . "'", $this->mysql_link)) {
            $this->halt(E_USER_ERROR, mysql_errno($this->mysql_link), mysql_error($this->mysql_link));
        }
    }

    /**
     * Garbage collection, destroy all session older than gc_maxlifetime
     *
     * @access private
     */
    function gc() {
        $timeago = $this->timestamp2mysql(time() - ($this->gc_maxlifetime * 60));
        if (($result = @mysql_query("DELETE FROM " . $this->mysql_tbname . " WHERE session_time <= " . $timeago, $this->mysql_link)) === false) {
            $this->halt(E_USER_ERROR, mysql_errno($this->mysql_link), mysql_error($this->mysql_link));
        }
    }

    /**
     * Start the session
     *
     * @access public
     */
    function start() {
        ob_start();

        $this->open();

        if (!$this->putID()) {
            if ($this->fallback_on_failed) {
                $this->method = $this->fallback_method;
                $this->putID();
            } else {
                die;
            }
        } else {
            $this->sendHeader();
            $this->gc();
        }
        
        ob_end_flush();
    }

    /**
     * Print an error and exit
     *
     * @param integer $errno
     * @param string  $errmsg
     *
     * @access private
     */
    function halt($errtype = E_USER_NOTICE, $errno = -1, $errmsg = 'Unknown error') {
        $formatted = sprintf("[%d]: %s", $errno, $errmsg);
        switch ($errtype) {
            case E_USER_ERROR:
                die('Fatal Error ' . $formatted);
            break;
            case E_USER_WARNING:
                print('Warning ' . $formatted);
            break;
            case E_USER_NOTICE:
                print('Notice ' . $formatted);
            break;
        }
    }
}
?>