zoukankan      html  css  js  c++  java
  • ECshop中的session机制理解

    ECshop中的session机制理解

       
    在网上找了发现都是来之一人之手,也没有用自己的话去解释,这里我就抛砖引玉,发表一下自己的意见,还希望能得到各界人士的指导批评!
        此session机制不需要session_start初始化,这个我一直不太清楚还得专家详解。自认为此种机制是建立在COOKIE基础上的模拟session,先用$GLOBALS['_SESSION'] = array();初始化session,然后在cookie中引入session,如$this->session_id = $_COOKIE[$this->session_name]。



    最近在做ECSHOP和UCENTERHOME的二次开发,有幸接触到了ECSHOP的SESSION机制,个人认为这种机制相比PHP自带的 SESSION机制拥有更高的安全性和可移植性,尤其是在做多系统共享SESSION时优势更为明显,因此简单的做了一下的代码分析,如有错误,请留言指 点.
    <?php



    class cls_session
    {
    var $db             = NULL;
    var $session_table  = '';

    var $max_life_time  = 1800; // SESSION 过期时间

    var $session_name   = '';
    var $session_id     = '';

    var $session_expiry = '';
    var $session_md5    = '';

    var $session_cookie_path   = '/';
    var $session_cookie_domain = '';
    var $session_cookie_secure = false;

    var $_ip   = '';
    var $_time = 0;

    //PHP5的构造函数,用于创建一个SESSION对象,为了保证对PHP4的兼容,其实是在该函数内部调用了和类同名的函数
    function __construct(&$db, $session_table, $session_data_table, $session_name = 'ECS_ID', $session_id = '')
    {
    $this->cls_session($db, $session_table, $session_data_table, $session_name, $session_id);
    }


    function cls_session(&$db, $session_table, $session_data_table, $session_name = 'ECS_ID', $session_id = '')
    {
    //将系统自带的$_SESSION初始化为一个空数组并放进全局函数里
    $GLOBALS['_SESSION'] = array();

    //根据配置文件设置相关的类属性
    if (!empty($GLOBALS['cookie_path']))
    {
    $this->session_cookie_path = $GLOBALS['cookie_path'];
    }
    else
    {
    $this->session_cookie_path = '/';
    }

    if (!empty($GLOBALS['cookie_domain']))
    {
    $this->session_cookie_domain = $GLOBALS['cookie_domain'];
    }
    else
    {
    $this->session_cookie_domain = '';
    }

    //这里稍微提一下,如果你使用的是HTTPS连接,那么这里需要设置为true
    if (!empty($GLOBALS['cookie_secure']))
    {
    $this->session_cookie_secure = $GLOBALS['cookie_secure'];
    }
    else
    {
    $this->session_cookie_secure = false;
    }

    $this->session_name       = $session_name;
    $this->session_table      = $session_table;
    $this->session_data_table = $session_data_table;

    $this->db  = &$db;
    $this->_ip = real_ip();

    //如果先前COOKIE中已经保存了sessionid则将他的值赋给session_id属性
    if ($session_id == '' && !empty($_COOKIE[$this->session_name]))
    {
    $this->session_id = $_COOKIE[$this->session_name];
    }
    else
    {
    $this->session_id = $session_id;
    }

    if ($this->session_id)
    {
    //如果COOKIE中已经存在session_id,取他的前32位做CRC32位校检保证值的正确性
    $tmp_session_id = substr($this->session_id, 0, 32);
    if ($this->gen_session_key($tmp_session_id) == substr($this->session_id, 32))
    {
    $this->session_id = $tmp_session_id;
    }
    else
    {
    $this->session_id = '';
    }
    }

    $this->_time = time();

    if ($this->session_id)
    {
    //从数据库中取对应session_id的记录保存到$_SESSION中
    $this->load_session();
    }
    else
    {
    //如果COOKIE中无值或者没能通过校检则创建一个全新且唯一的session_id
    $this->gen_session_id();

    //写COOKIE
    setcookie($this->session_name, $this->session_id . $this->gen_session_key($this->session_id), 0, $this->session_cookie_path, $this->session_cookie_domain, $this->session_cookie_secure);
    }


    register_shutdown_function(array(&$this, 'close_session'));
    }

    //生成一个唯一的session_id
    function gen_session_id()
    {
    $this->session_id = md5(uniqid(mt_rand(), true));

    return $this->insert_session();
    }

    //对COOKIE中的session_id做CRC32校检
    function gen_session_key($session_id)
    {
    static $ip = '';

    if ($ip == '')
    {
    $ip = substr($this->_ip, 0, strrpos($this->_ip, '.'));
    }

    return sprintf('x', crc32(!empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] . ROOT_PATH . $ip . $session_id : ROOT_PATH . $ip . $session_id));
    }

    //如果数据库中对应COOKIE内session_id的记录已经不存在,则创建一条对应的空记录
    function insert_session()
    {
    return $this->db->query('INSERT INTO ' . $this->session_table . " (sesskey, expiry, ip, data) VALUES ('" . $this->session_id . "', '". $this->_time ."', '". $this->_ip ."', 'a:0:{}')");
    }

    function load_session()
    {
    //检索对应session_id的记录,如果不存在则创建一条空记录
    $session = $this->db->getRow('SELECT userid, adminid, user_name, user_rank, discount, email, data, expiry FROM ' . $this->session_table . " WHERE sesskey = '" . $this->session_id . "'");
    if (empty($session))
    {
    $this->insert_session();

    $this->session_expiry = 0;
    $this->session_md5    = '40cd750bba9870f18aada2478b24840a';
    $GLOBALS['_SESSION']  = array();
    }
    else
    {
    //如果在SESSION表中检索到对应数据,且SESSION还没有过期则进行相关赋值操作
    if (!empty($session['data']) && $this->_time - $session['expiry'] <= $this->max_life_time)
    {
    $this->session_expiry = $session['expiry'];
    //对记录的值做一个MD5校检,以检测后边SESSION值是否发生变化
    $this->session_md5    = md5($session['data']);
    //反序列化$session['data']将值存到$_SESSION中
    $GLOBALS['_SESSION']  = unserialize($session['data']);
    $GLOBALS['_SESSION']['user_id'] = $session['userid'];
    $GLOBALS['_SESSION']['admin_id'] = $session['adminid'];
    $GLOBALS['_SESSION']['user_name'] = $session['user_name'];
    $GLOBALS['_SESSION']['user_rank'] = $session['user_rank'];
    $GLOBALS['_SESSION']['discount'] = $session['discount'];
    $GLOBALS['_SESSION']['email'] = $session['email'];
    }
    else
    {
    //否则说明SESSION值超过255字节,则到SESSION_DATA_TABLE表里边查询值
    $session_data = $this->db->getRow('SELECT data, expiry FROM ' . $this->session_data_table . " WHERE sesskey = '" . $this->session_id . "'");
    //如果在SESSION_DATA_TABLE表中检索到对应数据,且SESSION还没有过期则进行相关赋值操作
    if (!empty($session_data['data']) && $this->_time - $session_data['expiry'] <= $this->max_life_time)
    {
    $this->session_expiry = $session_data['expiry'];
    $this->session_md5    = md5($session_data['data']);
    $GLOBALS['_SESSION']  = unserialize($session_data['data']);
    $GLOBALS['_SESSION']['user_id'] = $session['userid'];
    $GLOBALS['_SESSION']['admin_id'] = $session['adminid'];
    $GLOBALS['_SESSION']['user_name'] = $session['user_name'];
    $GLOBALS['_SESSION']['user_rank'] = $session['user_rank'];
    $GLOBALS['_SESSION']['discount'] = $session['discount'];
    $GLOBALS['_SESSION']['email'] = $session['email'];
    }
    else
    {
    $this->session_expiry = 0;
    $this->session_md5    = '40cd750bba9870f18aada2478b24840a';
    $GLOBALS['_SESSION']  = array();
    }
    }
    }
    }

    function update_session()
    {
    //取得页面中$_SESSION变量内的值
    $adminid = !empty($GLOBALS['_SESSION']['admin_id']) ? intval($GLOBALS['_SESSION']['admin_id']) : 0;
    $userid  = !empty($GLOBALS['_SESSION']['user_id'])  ? intval($GLOBALS['_SESSION']['user_id'])  : 0;
    $user_name  = !empty($GLOBALS['_SESSION']['user_name'])  ? trim($GLOBALS['_SESSION']['user_name'])  : 0;
    $user_rank  = !empty($GLOBALS['_SESSION']['user_rank'])  ? intval($GLOBALS['_SESSION']['user_rank'])  : 0;
    $discount  = !empty($GLOBALS['_SESSION']['discount'])  ? round($GLOBALS['_SESSION']['discount'], 2)  : 0;
    $email  = !empty($GLOBALS['_SESSION']['email'])  ? trim($GLOBALS['_SESSION']['email'])  : 0;
    unset($GLOBALS['_SESSION']['admin_id']);
    unset($GLOBALS['_SESSION']['user_id']);
    unset($GLOBALS['_SESSION']['user_name']);
    unset($GLOBALS['_SESSION']['user_rank']);
    unset($GLOBALS['_SESSION']['discount']);
    unset($GLOBALS['_SESSION']['email']);

    $data        = serialize($GLOBALS['_SESSION']);
    $this->_time = time();

    //如果页面上SESSION的值没有发生变化并且最后一次SESSION更新时间距离当前时间小于10秒则跳出函数
    if ($this->session_md5 == md5($data) && $this->_time < $this->session_expiry + 10)
    {
    return true;
    }

    //转义SESSION的值用于安全入库
    $data = addslashes($data);


    if (isset($data{255}))
    {
    $this->db->autoReplace($this->session_data_table, array('sesskey' => $this->session_id, 'expiry' => $this->_time, 'data' => $data), array('data' => $data));

    $data = '';
    }

    //更新SESSION个字段的值,主要作用是更新expiry这个字段,以此来判断用户是否处于活动状态
    return $this->db->query('UPDATE ' . $this->session_table . " SET expiry = '" . $this->_time . "', ip = '" . $this->_ip . "', userid = '" . $userid . "', adminid = '" . $adminid . "', user_name='" . $user_name . "', user_rank='" . $user_rank . "', discount='" . $discount . "', email='" . $email . "', data = '$data' WHERE sesskey = '" . $this->session_id . "' LIMIT 1");
    }

    //register_shutdown_function将调用这个函数进行SESSION的更新和删除过期数据的操作
    function close_session()
    {
    $this->update_session();


    if (mt_rand(0, 2) == 2)
    {
    $this->db->query('DELETE FROM ' . $this->session_data_table . ' WHERE expiry < ' . ($this->_time - $this->max_life_time));
    }

    if ((time() % 2) == 0)
    {
    return $this->db->query('DELETE FROM ' . $this->session_table . ' WHERE expiry < ' . ($this->_time - $this->max_life_time));
    }

    return true;
    }

    function delete_spec_admin_session($adminid)
    {
    if (!empty($GLOBALS['_SESSION']['admin_id']) && $adminid)
    {
    return $this->db->query('DELETE FROM ' . $this->session_table . " WHERE adminid = '$adminid'");
    }
    else
    {
    return false;
    }
    }

    //清空$_SESSION
    function destroy_session()
    {
    $GLOBALS['_SESSION'] = array();

    setcookie($this->session_name, $this->session_id, 1, $this->session_cookie_path, $this->session_cookie_domain, $this->session_cookie_secure);


    if (!empty($GLOBALS['ecs']))
    {
    $this->db->query('DELETE FROM ' . $GLOBALS['ecs']->table('cart') . " WHERE session_id = '$this->session_id'");
    }


    $this->db->query('DELETE FROM ' . $this->session_data_table . " WHERE sesskey = '" . $this->session_id . "' LIMIT 1");

    return $this->db->query('DELETE FROM ' . $this->session_table . " WHERE sesskey = '" . $this->session_id . "' LIMIT 1");
    }

    function get_session_id()
    {
    return $this->session_id;
    }

    //得以于这种优秀的机制,现在统计在线活动用户仅需要这么一个简单的查询
    function get_users_count()
    {
    return $this->db->getOne('SELECT count(*) FROM ' . $this->session_table);
    }
    }

    ?>
    不掉到水里,也永不知道自己有多大潜力!
  • 相关阅读:
    PHP基本的语法以及和Java的差别
    Linux 性能測试工具
    【Oracle 集群】Linux下Oracle RAC集群搭建之Oracle DataBase安装(八)
    【Oracle 集群】Oracle 11G RAC教程之集群安装(七)
    【Oracle 集群】11G RAC 知识图文详细教程之RAC在LINUX上使用NFS安装前准备(六)
    【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之RAC 特殊问题和实战经验(五)
    【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之缓存融合技术和主要后台进程(四)
    【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之RAC 工作原理和相关组件(三)
    Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之ORACLE集群概念和原理(二)
    【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之集群概念介绍(一)
  • 原文地址:https://www.cnblogs.com/guolanzhu/p/3476138.html
Copyright © 2011-2022 走看看