优化使用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 相关文章推荐
一些 PHP 管理系统程序中的后门
Aug 05 PHP
php中处理mysql_fetch_assoc返回来的数组 不用foreach----echo
May 04 PHP
php array_pop()数组函数将数组最后一个单元弹出(出栈)
Jul 12 PHP
php数组去重复数据示例
Feb 25 PHP
php获取域名的google收录示例
Mar 24 PHP
thinkphp获取栏目和文章当前位置的方法
Oct 29 PHP
Laravel 5 框架入门(三)
Apr 09 PHP
关于PHP文件的自动运行方法分析
May 13 PHP
老生常谈PHP位运算的用途
Mar 12 PHP
php类自动装载、链式操作、魔术方法实现代码
Jul 23 PHP
php简单读取.vcf格式文件的方法示例
Sep 02 PHP
PHP实现的无限分类类库定义与用法示例【基于thinkPHP】
Aug 06 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
php入门学习知识点四 PHP正则表达式基本应用
2011/07/14 PHP
PHP CodeBase:将时间显示为&quot;刚刚&quot;&quot;n分钟/小时前&quot;的方法详解
2013/06/06 PHP
destoon安装出现Internal Server Error的解决方法
2014/06/21 PHP
PHP时间类完整实例(非常实用)
2015/12/25 PHP
CI框架支持$_GET的两种实现方法
2016/05/18 PHP
学习thinkphp5.0验证类使用方法
2017/11/16 PHP
解决laravel资源加载路径设置的问题
2019/10/14 PHP
Js 弹出框口并返回值的两种常用方法
2010/12/30 Javascript
Javascript中的for in循环和hasOwnProperty结合使用
2013/06/05 Javascript
jquery ajax post提交数据乱码
2013/11/05 Javascript
javascript垃圾收集机制与内存泄漏详细解析
2013/11/11 Javascript
jQuery-ui引入后Vs2008的无智能提示问题解决方法
2014/02/10 Javascript
如何将php数组或者对象传递给javascript
2014/03/20 Javascript
jQuery实现产品对比功能附源码下载
2016/08/09 Javascript
Javascript 引擎工作机制详解
2016/11/30 Javascript
前端开发必知的15个jQuery小技巧
2017/01/22 Javascript
基于angular2 的 http服务封装的实例代码
2017/06/29 Javascript
jquery 给动态生成的标签绑定事件的几种方法总结
2018/02/24 jQuery
Vue 实现html中根据类型显示内容
2019/10/28 Javascript
[42:50]NB vs VP 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
python3.6+opencv3.4实现鼠标交互查看图片像素
2018/02/26 Python
python笔记_将循环内容在一行输出的方法
2019/08/08 Python
python自动保存百度盘资源到百度盘中的实例代码
2019/08/26 Python
pytorch实现从本地加载 .pth 格式模型
2020/02/14 Python
使用keras框架cnn+ctc_loss识别不定长字符图片操作
2020/06/29 Python
安装并免费使用Pycharm专业版(学生/教师)
2020/09/24 Python
利用Python实现学生信息管理系统的完整实例
2020/12/30 Python
Pytorch之扩充tensor的操作
2021/03/04 Python
html5的新玩法——语音搜索
2013/01/03 HTML / CSS
西班牙伏林航空公司:Vueling
2016/08/05 全球购物
国际书籍零售商:Wordery
2017/11/01 全球购物
荷兰的时尚市场:To Be Dressed
2019/05/06 全球购物
星空联盟C# .net笔试题
2014/12/05 面试题
2015年班组工作总结
2015/04/20 职场文书
Redis命令处理过程源码解析
2022/02/12 Redis
JS前端监控采集用户行为的N种姿势
2022/07/23 Javascript