PHP独立Session数据库存储操作类分享
author:一佰互联 2019-04-29   click:187

直接上代码:
复制代码 代码如下:
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();
        }

}