优化使用mysql存储session的php代码


Posted in PHP onJanuary 10, 2008

之前写过两篇文章《自定义SESSION(二)——数据库保存》和《我为什么不使用session》
  但后来发现都有问题。前者处理在实际中几乎没什么用处,而且session回收还得自己另外处理。后者频繁的操作数据库,打来了很大的性能问题。

  这两天仔细考虑下,大致给出一个方案,但还没有具体详细的测试。
  1、session处理和统计结合起来。同时游客也都有记录。
  2、完全使用数据库和cookie来模拟session的功能。
  3、用户的对session的操作都尽量保证在一条sql语句完成。不用到session的时候,绝对不多一条查询。
  4、为了效率起见,session的回收没有集成进来,但提供了接口,可以调用实现。

暂时给出代码,不具体解释。
sql

CREATE TABLE `*****_session` (
 `sid` char(32) NOT NULL,
 `uid` int(10) NOT NULL,
 `username` char(32) NOT NULL,
 `usertype` tinyint(1) NOT NULL,
 `activetime` int(10) NOT NULL,
 `expiry` int(10) NOT NULL,
 `ip` char(15) NOT NULL,
 `url` char(80) NOT NULL,
 `value` char(255) NOT NULL,
 PRIMARY KEY  (`sid`)
) ENGINE=MEMORY DEFAULT CHARSET=utf8;

php代码

<? 
class session{ 

    private $_sessionPrex= '';//session的前缀 

    private $_time = '';//当前时间 

    private $_model = null;//数据库操作模型 

    private $_expiry = 1200;//session有效时间 

    private $_domain = '';//session的作用域 

    protected $isNew = 0;//判定操作动作 0 更新 1 增加 

    protected $session = array();//对应的一条session记录 

    public function __construct($options){ 
        $this->_setOptions($options); 
        if(empty($this->_time))$this->_time = time(); 
        $this->session['activetime'] = $this->_time; 
    } 

    public function start(){ 
        $this->_getSid(); 
    } 

    public function set($key,$value){ 
        if(in_array($key,array('uid','username','usertype','url','expiry'))){ 
            if($key == 'expiry'){ 
                $this->_setCookie($this->_sessionPrex.'_sid',$this->session['sid'],$value); 
                $this->_setCookie($this->_sessionPrex.'_uid',$this->session['uid'],$value); 
            } 
            $this->session[$key] = $value; 
        }else{ 
            $other = $this->session['value']; 
            $other[$key] = $value; 
            $this->session['value'] = $other; 
        } 
    } 

    public function get($key){ 
        if(in_array($key,array('uid','username','usertype','url','expiry'))){ 
            return $this->session[$key]; 
        }else{ 
            if(isset($this->session['value'][$key])){ 
                return $this->session['value'][$key]; 
            } 
            return null; 
        } 
    } 

    public function gc($file,$time = 1200){ 
        $lasttime = file_get_contents($file); 
        if($lasttime + $time<$this->_time){ 
            file_put_contents($file,$this->_time); 
            return $this->_model->delete('activetime+expiry<'.$this->_time); 
        } 
    } 

    public function destroy(){ 
        $this->session['uid'] = 0; 
        $this->session['username'] = ''; 
        $this->session['usertype'] = -1; 
        $this->session['expiry'] = $this->_expiry; 
        $this->session['value'] = array(); 
        $this->_setCookie($this->_sessionPrex.'_sid',$this->session['sid'],$this->_expiry); 
        $this->_setCookie($this->_sessionPrex.'_uid',$this->session['uid'],$this->_expiry); 
    } 

    public function __destruct(){ 
        $this->_save(); 
    } 

    private function _save(){ 
        $dbSession = $this->session; 
        $dbSession['value'] = serialize($dbSession['value']); 
        if(strlen($dbSession['value'])>255)$this->_error('session->value is too long!'); 
        if($this->isNew == 1){ 
            //增加 
            $this->_model->insert($dbSession); 
        }else{ 
            //更新 
            $sid = $dbSession['sid']; 
            $this->_model->update(array_slice($dbSession,1),'sid=\''.$sid.'\''); 
        } 
    } 

    private function _getSession($sid){ 
        $dbSession = $this->_model->detail('sid = \''.$sid.'\''); 
        if(!$dbSession)return false; 
        $dbSession['value'] = unserialize($dbSession['value']); 
        $this->session = array_merge($dbSession,$this->session);         
        return true; 
    } 

    private function _getSid(){ 
        $sid = strip_tags($_COOKIE[$this->_sessionPrex.'_sid']); 
        if(strlen($sid)==32){ 
            if($this->_getSession($sid)){ 
                return true; 
            } 
        }else{ 
            $sid = md5(time().mt_rand(1000,10000)); 
            $this->_setCookie($this->_sessionPrex.'_sid',$sid); 
        } 
        $this->_setCookie($this->_sessionPrex.'_uid',0); 
        $this->session = array( 
                'uid' => 0, 
                'username' => '', 
                'usertype' => -1, 
                'activetime' => $this->_time, 
                'ip' => $this->_getip(), 
                'url' => strip_tags($_SERVER['REQUEST_URI']), 
                'expiry' =>$this->_expiry, 
                'value' => array() 
        ); 
        $this->isNew = 1; 
        $this->session['sid'] = $sid; 
    } 

    private function _setCookie($name,$value,$expiry=0){ 
        if(empty($expiry))$expiry = $this->_expiry; 
        if(empty($this->_domain)){ 
            setcookie($name,$value,$this->_time + $expiry,'/'); 
        }else{ 
            setcookie($name,$value,$this->_time + $expiry,'/',$this->_domain); 
        } 
    } 

    private function _getip(){ 
        return getip(); 
    } 

    private function _setOptions($options){ 
        foreach ($options as $key=>$value){ 
            if(in_array($key,array('sessionPrex','time','model','expiry','domain'))){ 
                $key = '_'.$key; 
                $this->$key = $value; 
            } 
        } 
    } 

    private function _error($msg){ 
        throw new Phpbean_Exception($msg); 
    } 

?> 

(注意,该代码不能直接使用,本文主要是提供一种思路) 

PHP 相关文章推荐
PHP4 与 MySQL 数据库操作函数详解
Oct 09 PHP
Memcache 在PHP中的使用技巧
Feb 08 PHP
114啦源码(114la)不能生成地方房产和地方报刊问题4级页面0字节的解决方法
Jan 12 PHP
单一index.php实现PHP任意层级文件夹遍历(Zjmainstay原创)
Jul 31 PHP
PHP数字和字符串ID互转函数(类似优酷ID)
Jun 30 PHP
destoon文章模块调用企业会员资料的方法
Aug 22 PHP
百万级别知乎用户数据抓取与分析之PHP开发
Sep 28 PHP
php的socket编程详解
Nov 20 PHP
thinkphp5 URL和路由的功能详解与实例
Dec 26 PHP
laravel框架模型、视图与控制器简单操作示例
Oct 10 PHP
php获取微信openid方法总结
Oct 10 PHP
Yii 框架控制器创建使用及控制器响应操作示例
Oct 14 PHP
Http 1.1 Etag 与 Last-Modified提高php效率
Jan 10 #PHP
PHP读取目录下所有文件的代码
Jan 07 #PHP
台湾中原大学php教程孙仲岳主讲
Jan 07 #PHP
修改php.ini实现Mysql导入数据库文件最大限制的修改方法
Dec 11 #PHP
php下过滤HTML代码的函数
Dec 10 #PHP
php字符串截取中文截取2,单字节截取模式
Dec 10 #PHP
php获得当前的脚本网址
Dec 10 #PHP
You might like
雄兵连:第三季确定会出,不过时间未定,鹤熙是第三季的主角!
2020/03/13 国漫
php实现的Captcha验证码类实例
2014/09/22 PHP
详解PHP中foreach的用法和实例
2016/10/25 PHP
Thinkphp框架 表单自动验证登录注册 ajax自动验证登录注册
2016/12/27 PHP
Prototype源码浅析 String部分(一)之有关indexOf优化
2012/01/15 Javascript
用jquery仿做发微博功能示例
2014/04/18 Javascript
JavaScript实现数字数组正序排列的方法
2015/04/06 Javascript
JavaScript登录验证码的实现
2016/10/27 Javascript
ES6中Iterator与for..of..遍历用法分析
2017/03/31 Javascript
JS返回顶部实例代码
2020/08/09 Javascript
nodejs之koa2请求示例(GET,POST)
2018/08/07 NodeJs
React中如何引入Angular组件详解
2018/08/09 Javascript
浅谈webpack4.x 入门(一篇足矣)
2018/09/05 Javascript
Vue触发式全局组件构建的方法
2018/11/28 Javascript
JavaScript 实现继承的几种方式
2021/02/19 Javascript
python的urllib模块显示下载进度示例
2014/01/17 Python
在Linux系统上部署Apache+Python+Django+MySQL环境
2015/12/24 Python
Ubuntu下创建虚拟独立的Python环境全过程
2017/02/10 Python
python 自定义对象的打印方法
2019/01/12 Python
浅谈pytorch grad_fn以及权重梯度不更新的问题
2019/08/20 Python
python同义词替换的实现(jieba分词)
2020/01/21 Python
Python使用pyyaml模块处理yaml数据
2020/04/14 Python
Jmeter调用Python脚本实现参数互相传递的实现
2021/01/22 Python
纯css3制作网站后台管理面板
2014/12/30 HTML / CSS
加拿大最大的相机店:Henry’s
2017/05/17 全球购物
英国家喻户晓的家居商店:The Range
2019/03/25 全球购物
DTD的含义以及作用
2014/01/26 面试题
车间组长岗位职责
2013/12/20 职场文书
《草原》教学反思
2014/02/15 职场文书
任命书范本大全
2014/06/06 职场文书
奥巴马经典演讲稿
2014/09/13 职场文书
银行反四风对照检查材料
2014/09/29 职场文书
镇党政领导班子民主生活会思想汇报
2014/10/11 职场文书
2015出纳试用期工作总结
2014/12/12 职场文书
2015年销售助理工作总结
2015/05/11 职场文书
企业文化学习心得体会
2016/01/21 职场文书