PHP Standalone Session Database Storage Operations Class Sharing

  • 2021-06-29 10:33:25
  • OfStack

Code directly:


class DbSession
{
    const TYPE_INT = 1;
    const TYPE_STR = 2;
    /**
     * Database configration
     *
     * @var array
     */
    private $_config = array(
             ' host' => '127.0.0.1 ' ,
             ' port' => 3306,
             ' username' =>  ' root',
             ' password' =>  ' root',
             ' dbname' =>  ' db_mylab',
         ' tablename' =>  ' t_sessions',
         ' cookie_prefix' =>  ' mylab_',
         ' cookiepath' =>  ' /',
         ' cookiedomain' =>  " ,
         ' cookie_timeout' => 900
    );
    /**
     * Table fields type array
     *
     * @var array
     */
    private  $_db_fields = array(
         ' crc32sid'      => self::TYPE_INT,
                 ' sessionhash'   => self::TYPE_STR,
                 ' idhash'        => self::TYPE_STR,
                 ' userid'        => self::TYPE_INT,
                 ' ipaddress'     => self::TYPE_STR,
                 ' lastactivity'  => self::TYPE_STR,
                 ' location'      => self::TYPE_STR,
         ' loggedin'      => self::TYPE_INT,
         ' heartbeat'     => self::TYPE_STR
        );
        /**
         * db obj
         *
         * @var mysqli object
         */
    private $_mysqli = null;
    /**
     * Weather the session was created or existed previously
     *
     * @var bool
     */
    private $_created = false;
    /**
     * Array of changes.
     *
     * @var array
     */
    private $_changes = array();
    /**
     * @var bool
     */
    private $_db_inited = false;
    /**
     * session host
     *
     * @var string
     */
    private $_session_host =  " ;
    /**
     * session idhash
     *
     * @var string
     */
    private $_session_idhash =  " ;
    private $_dbsessionhash =  " ;
    private $_vars = array();
        public function __construct()
        {
                $this->_dbsessionhash = addslashes($this->get_cookie( ' sessionhash'));
            $this->_session_host = substr($_SERVER[ ' REMOTE_ADDR'], 0, 15);
            #This should *never* change during a session
            $this->_session_idhash = md5($_SERVER[ ' HTTP_USER_AGENT'] . self::fetch_substr_ip(self::fetch_alt_ip()) );
            $this->_init_config();
            $this->init_db();
            $gotsession = false;
            if ($this->_dbsessionhash)
            {
                $sql =  ' 
                        SELECT *
                        FROM  '  . $this->_config[ ' tablename'] .  ' 
                        WHERE   crc32sid =  '  . sprintf( ' %u', crc32($this->_dbsessionhash)) .  ' 
                            AND sessionhash = ' '  . $this->_dbsessionhash .  ' '
                                AND idhash = ' '  . $this->_session_idhash .  ' '
                        AND heartbeat > ' '  . date( ' Y-m-d H:i:s' ,TIMENOW  �  $this->_config[ ' cookie_timeout']) .  ' ' ' ;
                    //echo $sql;exit;
                $result = $this->_mysqli->query($sql);
                $session = $result->fetch_array(MYSQLI_ASSOC);
                if ($session AND ($this->fetch_substr_ip($session[ ' ipaddress']) == $this->fetch_substr_ip($this->_session_host)))
                {
                        $gotsession = true;
                        $this->_vars = $session;
                        $this->_created = false;
                }
            }
            if ($gotsession == false)
            {
                $this->_vars = $this->fetch_session();
                $this->_created = true;
                $gotsession = true;
            }
            if ($this->_created == false)
            {
            $this->set( ' lastactivity', date( ' Y-m-d H:i:s', TIMENOW));
            $this->set( ' location', $_SERVER[ ' REQUEST_URI']);
            }
        }
    /**
     * Builds an array that can be used to build a query to insert/update the session
     *
     * @return    array    Array of column name => prepared value
     */
    private function _build_query_array()
    {
        $return = array();
        foreach ($this->_db_fields AS $fieldname => $cleantype)
        {
            switch ($cleantype)
            {
                case self::TYPE_INT:
                    $cleaned = is_numeric($this->_vars["$fieldname"]) ? $this->_vars["$fieldname"] : intval($this->_vars["$fieldname"]);
                    break;
                case self::TYPE_STR:
                default:
                    $cleaned = "'" . addslashes($this->_vars["$fieldname"]) . "'";
            }
            $return["$fieldname"] = $cleaned;
        }
        return $return;
    }
    /**
     * Sets a session variable and updates the change list.
     *
     * @param    string    Name of session variable to update
     * @param    string    Value to update it with
     */
    public function set($key, $value)
    {
        if ($this->_vars["$key"] != $value)
        {
            $this->_vars["$key"] = $value;
            $this->_changes["$key"] = true;
        }
    }
    public function get($key)
    {
        return $this->_vars["$key"];
    }
        public function unsetchangedvar($var)
    {
        if (isset($this->_changes["$var"]))
        {
                unset($this->_changes["$var"]);
        }
    }
    /**
     * Fetches a valid sessionhash value, not necessarily the one tied to this session.
     *
     * @return    string    32-character sessionhash
     */
    static function fetch_sessionhash()
    {
        return hash( ' md5 '  , TIMENOW . rand(1, 100000) . uniqid() );
    }
        private function _init_config()
        {
                $registry = Zend_Registry::getInstance();
                $config = $registry->get( ' config');
                $this->_config[ ' host'] = $config->database->params->host;
        $this->_config[ ' port'] = $config->database->params->port;
        $this->_config[ ' username'] = $config->database->params->username;
        $this->_config[ ' password'] = $config->database->params->password;
        $this->_config[ ' dbname'] = $config->database->params->dbname;
        $this->_config[ ' tablename'] = $config->database->session->tablename;
        }
        /**
         * initialize database connection
         */
        public function init_db()
        {
            if ($this->_db_inited)
            {
                return true;
            }
            //mysqli_report(MYSQLI_REPORT_OFF);
            $this->_mysqli = new mysqli(
                $this->_config[ ' host'],
                $this->_config[ ' username'],
                $this->_config[ ' password'],
                $this->_config[ ' dbname'],
                $this->_config[ ' port']
            );
            /* check connection */
                if (mysqli_connect_errno())
                {
                    // printf("Connect failed: %sn", mysqli_connect_error());
                    // echo  ' in  ' , __FILE__,  '  on line  ' , __LINE__;
                    echo "{ success: false, errors: { reason:  '  Connect failed: " . addslashes( mysqli_connect_error() ) . "' }}";
                    exit();
                }
            $this->_mysqli->query( ' set names latin1 ' );
            $this->_db_inited = true;
            return true;
        }
    /**
         * Fetches an alternate IP address of the current visitor, attempting to detect proxies etc.
         *
         * @return      string
         */
        static function fetch_alt_ip()
        {
                $alt_ip = $_SERVER[ ' REMOTE_ADDR'];
                if (isset($_SERVER[ ' HTTP_CLIENT_IP']))
                {
                        $alt_ip = $_SERVER[ ' HTTP_CLIENT_IP'];
                }
                else if (isset($_SERVER[ ' HTTP_FROM']))
                {
                        $alt_ip = $_SERVER[ ' HTTP_FROM'];
                }
                return $alt_ip;
        }
    /**
     * Returns the IP address with the specified number of octets removed
     *
     * @param    string    IP address
     *
     * @return    string    truncated IP address
     */
    static function fetch_substr_ip($ip, $length = null)
    {
        return implode( ' .', array_slice(explode( ' .', $ip), 0, 4  �  $length));
    }
    /**
     * Fetches a default session. Used when creating a new session.
     *
     * @param    integer    User ID the session should be for
     *
     * @return    array    Array of session variables
     */
    public function fetch_session($userid = 0)
    {
        $sessionhash = self::fetch_sessionhash();
        $this->set_cookie( ' sessionhash', $sessionhash);
        return array(
             ' crc32sid'      => sprintf( ' %u', crc32($sessionhash)),
             ' sessionhash'   => $sessionhash,
             ' idhash'        => $this->_session_idhash,
             ' userid'        => $userid,
             ' ipaddress'     => $this->_session_host,
             ' lastactivity'  => date( ' Y-m-d H:i:s', TIMENOW),
             ' location'      => $_SERVER[ ' REQUEST_URI'],
             ' loggedin'      => $userid ? 1 : 0,
             ' heartbeat'     => date( ' Y-m-d H:i:s', TIMENOW)
        );
    }
    public function get_cookie($cookiename)
    {
        $full_cookiename = $this->_config[ ' cookie_prefix'] . $cookiename;
        if (isset($_COOKIE[$full_cookiename]))
        {
            return $_COOKIE[$full_cookiename];
        }
        else
        {
            return  false;
        }
    }
    public function set_cookie($name, $value =  " , $permanent = 1, $allowsecure = true)
    {
        if ($permanent)
        {
            $expire = TIMENOW + 60 * 60 * 24 * 365;
        }
        else
        {
            $expire = 0;
        }
        if ($_SERVER[ ' SERVER_PORT'] == '443 ' )
        {
            // we're using SSL
            $secure = 1;
        }
        else
        {
            $secure = 0;
        }
        // check for SSL
        $secure = ((REQ_PROTOCOL ===  ' https' AND $allowsecure) ? true : false);
        $name = $this->_config[ ' cookie_prefix'] . $name;
        $filename =  ' N/A';
        $linenum = 0;
        if (!headers_sent($filename, $linenum))
        { // consider showing an error message if there not sent using above variables?
            if ($value ==  "  AND strlen($this->_config[ ' cookiepath']) > 1 AND strpos($this->_config[ ' cookiepath'],  ' /') !== false)
            {
                // this will attempt to unset the cookie at each directory up the path.
                // ie, cookiepath = /test/abc/. These will be unset: /, /test, /test/, /test/abc, /test/abc/
                // This should hopefully prevent cookie conflicts when the cookie path is changed.
                $dirarray = explode( ' /', preg_replace( ' #/+$#',  " , $this->_config[ ' cookiepath']));
                $alldirs =  " ;
                foreach ($dirarray AS $thisdir)
                {
                    $alldirs .= "$thisdir";
                    if (!empty($thisdir))
                    { // try unsetting without the / at the end
                        setcookie($name, $value, $expire, $alldirs, $this->_config[ ' cookiedomain'], $secure);
                    }
                    $alldirs .= "/";
                    setcookie($name, $value, $expire, $alldirs, $this->_config[ ' cookiedomain'], $secure);
                }
            }
            else
            {
                setcookie($name, $value, $expire, $this->_config[ ' cookiepath'], $this->_config[ ' cookiedomain'], $secure);
            }
        }
        else if (!DEBUG)
        {
            echo "can't set cookies";
        }
    }
        private function _save()
        {
            $cleaned = $this->_build_query_array();
            if ($this->_created)
            {
                //var_dump($cleaned);
                # insert query
                $this->_mysqli->query( ' 
                        INSERT IGNORE INTO  '  . $this->_config[ ' tablename'] .  ' 
                        ( '  . implode( ' ,', array_keys($cleaned)) .  ' )
                    VALUES
                        ( '  . implode( ' ,', $cleaned).  ' )
                 ' );
            }
            else
            {
                # update query
                $update = array();
            foreach ($cleaned AS $key => $value)
            {
                if (!empty($this->_changes["$key"]))
                {
                    $update[] = "$key = $value";
                }
            }
            if (sizeof($update) > 0)
            {
                $sql =  ' UPDATE  '  . $this->_config[ ' tablename'] .  ' 
                        SET  '  . implode( ' ,  ' , $update) .  ' 
                        WHERE crc32sid =  '  . sprintf( ' %u', crc32($this->_dbsessionhash)) .  ' 
                            AND sessionhash = ' '  . $this->_dbsessionhash .  ' ' ' ;
                //echo $sql;
                $this->_mysqli->query($sql);
            }
            }
        }
        public function getOnlineUserNum()
        {
                $sql =  ' 
                        SELECT count(*) as cnt
                        FROM  '  . $this->_config[ ' tablename'] .  ' 
                        WHERE loggedin = 1
                          AND heartbeat > ' '  . date( ' Y-m-d H:i:s' ,TIMENOW  �  $this->_config[ ' cookie_timeout']) .  ' ' ' ;
            $result = $this->_mysqli->query($sql);
            $row = $result->fetch_array(MYSQLI_ASSOC);
                return $row[ ' cnt'];
        }
        private function _gc()
        {
                $rand_num = rand(); # randow integer between 0 and getrandmax()
                if ($rand_num < 100)
                {
                        $sql =  ' DELETE FROM  '  . $this->_config[ ' tablename'] .  ' 
                                WHERE heartbeat < ' '  . date( ' Y-m-d H:i:s' ,TIMENOW  �  $this->_config[ ' cookie_timeout']) .  ' ' ' ;
                        $this->_mysqli->query($sql);
                }
        }
        public function __destruct()
        {
            $this->_save();
            $this->_gc();
            $this->_mysqli->close();
        }
}


Related articles: