<?PHP

#
#   Axis--Session.php
#   An Object for Maintaining the Values of Variables Across Pages
#
#   Copyright 1999-2003 Axis Data
#   This code is free software that can be used or redistributed under the
#   terms of Version 2 of the GNU General Public License, as published by the
#   Free Software Foundation (http://www.fsf.org).
#
#   Author:  Edward Almasy (almasy@axisdata.com)
#
#   Part of the AxisPHP library v1.2.5
#   For more information see http://www.axisdata.com/AxisPHP/
#


class Session {

    # ---- PUBLIC INTERFACE --------------------------------------------------

    function __construct(&$DB = NULL)
    {
        global $APSession_Shutdown_Sessions;

        # create database object if none supplied
        if ($DB === NULL)
        {
            $DB = new Database();
        }

        # save database object (if supplied) or create new one
        $this->DB =& $DB;

        # construct session variable name
        $SessionVar = "APSessionId".md5($DB->DBHostName().$DB->DBName());

        # if session ID available
        if (isset($_SESSION[$SessionVar]))
        {
            # look for session ID in database
            $this->SessionId = $_SESSION[$SessionVar];
            $DB->Query("SELECT * FROM APSessions WHERE SessionId = "
                    .intval($this->SessionId));

            # if matching session ID record not found in database
            if ($DB->NumRowsSelected() < 1)
            {
                # clear session ID
                unset($this->SessionId);
            }
        }

        # if session ID found
        if (isset($this->SessionId))
        {
            # load session variables from database
            $DB->Query("SELECT * FROM APSessionData WHERE SessionId = "
                    .intval($this->SessionId));
            while ($Record = $DB->FetchRow())
            {
                $VarName = $Record["DataName"];
                $VarValue = unserialize($Record["DataValue"]);
                if (substr($VarName, -2) == "-T")
                {
                    $VarName = substr($VarName, 0, -2);
                    $this->SaveVarFlags[$VarName] = FALSE;
                }
                else
                {
                    $this->SaveVarFlags[$VarName] = TRUE;
                    $this->TempVarFlags[$VarName] = FALSE;
                }
                $this->SessionVariables[$VarName] = $VarValue;
                $GLOBALS[$VarName] = $VarValue;
            }
        }
        else
        {
            # generate unique session ID
            do
            {
                $this->SessionId = mt_rand();
            } while ($DB->Query("SELECT COUNT(*) AS FoundCount FROM APSessionData"
                    ." WHERE SessionId = ".$this->SessionId, "FoundCount"));

            # save session ID
            $_SESSION[$SessionVar] = $this->SessionId;
        }

        # make sure session state will be saved when page ends
        $APSession_Shutdown_Sessions[] =& $this;
    }

    function RegisterVariable($VariableName, $Value = NULL)
    {
        # add variable to list of variables to be saved
        if ($Value !== NULL)
        {
            $this->SessionVariables[$VariableName] = $Value;
        }
        else
        {
            $this->SessionVariables[$VariableName] = $GLOBALS[$VariableName];
        }
        $this->SaveVarFlags[$VariableName] = TRUE;
        $this->TempVarFlags[$VariableName] = FALSE;
    }

    function PassVariable($VariableName, $Value = NULL)
    {
        # add variable to list of variables to be saved
        if ($Value !== NULL)
        {
            $this->SessionVariables[$VariableName] = $Value;
        }
        else
        {
            if (isset($GLOBALS[$VariableName]))
            {
                $this->SessionVariables[$VariableName] = $GLOBALS[$VariableName];
            }
            else
            {
                $this->SessionVariables[$VariableName] = NULL;
            }
        }
        $this->SaveVarFlags[$VariableName] = TRUE;
        $this->TempVarFlags[$VariableName] = TRUE;
    }

    function UnregisterVariable($VariableName)
    {
        # remove variable from list of variables to be saved (if present)
        if (isset($this->SessionVariables[$VariableName]))
        {
            unset($this->SessionVariables[$VariableName]);
            unset($this->TempVarFlags[$VariableName]);
        }
    }

    function IsRegistered($VariableName)
    {
        return (isset($this->SessionVariables[$VariableName]) ? TRUE : FALSE);
    }

    function IsPassed($VariableName)
    {
        return ((isset($this->SessionVariables[$VariableName]) && $this->TempVarFlags[$VariableName])
                ? TRUE : FALSE);
    }

    # retrieve variable with specified name
    function Get($VariableName)
    {
        if (isset($this->SessionVariables[$VariableName]))
        {
            return $this->SessionVariables[$VariableName];
        }
        else
        {
            return NULL;
        }
    }

    # retrieve variable with specified name from all active sessions
    function GetFromAllSessions($VariableName)
    {
        # clear out any expired sessions
        $this->DeleteExpiredSessions();

        # start with empty array
        $ReturnValue = array();

        # for each instance of variable in session database
        $DB =& $this->DB;
        $DB->Query("SELECT SessionId,DataValue FROM APSessionData WHERE DataName = '".$VariableName."'");
        while ($Record = $DB->FetchRow())
        {
            # unpack variable value and add to array to be returned
            $ReturnValue[$Record["SessionId"]] = unserialize($Record["DataValue"]);
        }

        # return array of variable values to caller
        return $ReturnValue;
    }


    # ---- PRIVATE INTERFACE -------------------------------------------------

    # handle to SQL database we use to store session information
    var $DB;

    # session ID
    var $SessionId;

    # array containing variables to be maintained between pages
    var $SessionVariables;

    # flags indicating whether to save variable for next session
    var $SaveVarFlags;

    # flags indicating whether to mark variable as temporary for next session
    var $TempVarFlags;

    # how long before sessions will expire (in minutes)
    var $SessionExpirationTime = 180;

    function SaveState()
    {
        # if session record not found in database
        $this->DB->Query("SELECT * FROM APSessions WHERE SessionId = "
                .intval($this->SessionId));
        if ($this->DB->NumRowsSelected() < 1)
        {
            # create new session record
            $this->DB->Query(sprintf("INSERT INTO APSessions "
                            ."(SessionId, LastActiveDate) VALUES "
                            ."(%d, NOW())",
                    $this->SessionId));
        }
        else
        {
            # update last active timestamp for session
            $this->DB->query("UPDATE APSessions "
                    ."SET LastActiveDate=NOW() "
                    ."WHERE SessionId = ".intval($this->SessionId));
        }

        # clear all old stored session variables from database
        $this->DB->Query(sprintf("DELETE FROM APSessionData WHERE SessionId = '%d'",
                $this->SessionId));

        # save session variables to database (if any)
        if (isset($this->SessionVariables))
        {
            foreach ($this->SessionVariables as $VariableName => $VariableValue)
            {
                if ($this->SaveVarFlags[$VariableName])
                {
                    if ($this->TempVarFlags[$VariableName]) {  $VariableName .= "-T";  }
                    $this->DB->Query(sprintf("INSERT INTO APSessionData "
                                    ."(SessionId, DataName, DataValue) VALUES "
                                    ."(%d, '%s', '%s')",
                            $this->SessionId,
                            $VariableName,
                            addslashes(serialize($VariableValue))));
                }
            }
        }

        # clear any expired sessions from database
        $this->DeleteExpiredSessions();
    }

    function DeleteExpiredSessions()
    {
        # retrieve expired session records
        $DB =& $this->DB;
        $DB->Query(sprintf("SELECT * FROM APSessions WHERE DATE_SUB(NOW(), INTERVAL %d MINUTE) > LastActiveDate",
                $this->SessionExpirationTime));

        # if expired sessions were found
        if ($DB->NumRowsSelected() > 0)
        {
            # for each record
            while ($Record = $DB->FetchRow())
            {
                # save record ID
                $Id[$Record["SessionId"]] = 1;
            }

            # for each saved session record ID
            while (list($SessionId) = each($Id))
            {
                # delete any stored session data
                $DB->Query(sprintf("DELETE FROM APSessionData WHERE SessionId=%d",
                        $SessionId));
            }

            # delete expired session records
            $DB->Query(sprintf("DELETE FROM APSessions WHERE DATE_SUB(NOW(), INTERVAL %d MINUTE) > LastActiveDate",
                    $this->SessionExpirationTime));
        }
    }
};

function APSession_Shutdown()
{
    global $APSession_Shutdown_Sessions;

    # if we have Sessions to shut down
    if (isset($APSession_Shutdown_Sessions))
    {
        # call shutdown functions
        while (list($Key) = each($APSession_Shutdown_Sessions))
        {
            $SessionObject =& $APSession_Shutdown_Sessions[$Key];
            $SessionObject->SaveState();
        }
    }
}

register_shutdown_function("APSession_Shutdown");


?>
