php之自定义session存储机制【3】

session默认是以文件形式存储的,当网站的访问量很大的情况下,因为文件的IO性能问题,会让服务器的开销巨大,比较典型做法是把session存入数据库或内存,本文是以数据库为例。

主要有两个步骤:
1. 自定义实现session的操作方法,比如读、写、删除、垃圾回收…
2. 告诉系统的session机制调用自定义的方法去处理session.

数据库创建语句:

 CREATE TABLE `t_session` (
  `sess_id` varchar(50) NOT NULL COMMENT 'session id',
  `sess_content` text NOT NULL COMMENT 'session内容',
  `last_write` int(10) unsigned NOT NULL COMMENT '最后写入时间',
  PRIMARY KEY (`sess_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

代码如下:
这里写图片描述
session_db.php

<?php
require_once 'MyPdo.class.php';
require_once 'ModelFactory.class.php';
require_once 'SessionModel.class.php';

// function __autoload($class){
//     $filename = $class.".class.php";
//     if(file_exists($filename)){
//         require_once $filename;
//     }
// }


//让系统的session机制调用自定义的方法去处理session.
session_set_save_handler('sessionOpen', 'sessionClose', 'sessionRead', 'sessionWrite', 'sessionDestroy', 'sessionGc');

//打开session
function sessionOpen(){
    echo "<br>sessionOpen";
}


//关闭session
function sessionClose(){
    echo "<br>sessionClose";
    return true;
}

//session根据id读取数据
function sessionRead($sess_id){
    echo "<br>sessionRead";
    $model = ModelFactory::M("SessionModel");
    return $model->read($sess_id);
}

//session根据id写入数据
function sessionWrite($sess_id,$content){
    echo "<br>sessionWrite";
    $model = ModelFactory::M("SessionModel");
    $model->write($sess_id,$content);
}

/**
 * 销毁session,调用session_destroy()触发
 * @param string $sess_id
 */
function sessionDestroy($sess_id){
    echo "<br>sessionDestroy";
    $model = ModelFactory::M("SessionModel");
    $model->destroy($sess_id);
}

//垃圾session数据回收
function sessionGc($lifetime){
    echo "<br>sessionGc";
    $model = ModelFactory::M("SessionModel");
    $model->gc($lifetime);
}

?>

MyPdo.class.php

<?php

class MyPdo
{

    private static $_instance = null;

    private $dbh;

    private function __construct($config)
    {
        $dsn = "mysql:host={$config['host']}; port={$config['port']}; dbname={$config['dbname']}";
        $options = array(
            PDO::MYSQL_ATTR_INIT_COMMAND => "set names {$config['charset']}"
        );

        try {
            $this->dbh = new PDO($dsn, $config['username'], $config['passwd'], $options);
        } catch (PDOException $e) {
            echo 'Connection failed: ' . $e->getMessage();
        }
        $this->dbh -> setAttribute ( PDO :: ATTR_ERRMODE ,  PDO :: ERRMODE_EXCEPTION );
    }

    private function __clone()
    {}

    public static function getInstance($config = array('host'=>'localhost','port'=>'3306','dbname'=>'db7','charset'=>'utf8','username'=>'root',"passwd"=>'root'))
    {
        return isset(self::$_instance) ? self::$_instance : (self::$_instance = new self($config));
    }

    public function getPdo(){
        return $this->dbh;
    }

    public function close() {
       $this->dbh = null;
       self::$_instance = null;
    }

    public function query($sql) {
        try {
           $stmt =  $this->dbh->query($sql);
           return $stmt;
        } catch (PDOException $e) {
            echo "<p>sql语句执行失败,请参考如下信息:</p>";
            echo "<br>错误文件:" .$e->getFile();
            echo "<br>错误行号:" .$e->getLine();
            echo "<br>错误代号:" .$e->getCode(); 
            echo "<br>错误信息:" .$e->getMessage();
            echo "<br>错误语句:" .$sql;
        }
    }


    public function exec($sql) {
     try {
           $num =  $this->dbh->exec($sql);//失败返回false,成功返回受影响的行数,也可能是0
           if($num >= 0){
               return true;
           }
           return $num;
        } catch (PDOException $e) {
            echo "<p>sql语句执行失败,请参考如下信息:</p>";
            echo "<br>错误文件:" .$e->getFile();
            echo "<br>错误行号:" .$e->getLine();
            echo "<br>错误代号:" .$e->getCode(); 
            echo "<br>错误信息:" .$e->getMessage();
            echo "<br>错误语句:" .$sql;
        }
    }

    /**
     * 获取一行的结果
     * @param string $sql
     * @return array 数组
     */
    public function fetchRow($sql){
        $stmt = $this->query($sql);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    }

    /**
     * 获取多行结果
     * @param unknown $sql
     * @return array 二维数组
     */
    public function fetchAll($sql) {
        $stmt = $this->query($sql);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    /**
     * 获取一个数据
     * @param string $sql
     * @return string
     */
    public function fetchData($sql) {
        $stmt = $this->query($sql);
        $result =  $stmt->fetch(PDO::FETCH_NUM);
        if($result){
            return $result[0];
        }
        return '';
    }

}

?>

ModelFactory.class.php

<?php


class ModelFactory
{
    private static $arr = array();

    static function M($class) {
        if(!array_key_exists($class, static::$arr)){
            static::$arr[$class] = new $class();
        }
        return static::$arr[$class];

    }
}

?>

SessionModel.class.php

<?php
class SessionModel
{

  /**
   * 写入session_id的内容
   * @param string $sess_id
   * @param string $content
   */
  public function write($sess_id,$content) {
      $sql = "replace into t_session  (sess_id, sess_content, last_write) values ('$sess_id', '$content', UNIX_TIMESTAMP());";
      return MyPdo::getInstance()->exec($sql);
  }

  /**
   * 根据session_id读取内容
   * @param string $sess_id
   * @return string
   */
  public function read($sess_id) {
      $sql = "select sess_content from  t_session where sess_id = '$sess_id'";
      return MyPdo::getInstance()->fetchData($sql);

  }

  /**
   * 销毁session_id数据
   * @param string $sess_id
   */
  public function destroy($sess_id) {
      $sql = "delete from t_session where sess_id = '$sess_id'";
      return MyPdo::getInstance()->exec($sql);
  }

  /***
   * gc垃圾回收删除超过有效期的session数据
   * @param int $lifetime
   * @return Ambigous <boolean, int>
   */
  public function gc($lifetime){
      $sql = "delete from t_session where last_write < (UNIX_TIMESTAMP()- $lifetime)";
      return MyPdo::getInstance()->exec($sql);
  }


}


?>

use_session_db.php

<?php
require 'session_db.php';

//每2次访问服务器,可能进行1次垃圾扫描回收
ini_set('session.gc_probability', '1');
ini_set('session.gc_divisor', '2');
//设置session的有效期10秒
ini_set('session.gc_maxlifetime', '10');
@session_start();

echo '<br>current session id= '.session_id();

echo '<br>';
print_r($_SESSION);

$_SESSION['name'] = 'jack';

$_SESSION['age'] = 60;

$_SESSION['city'] = 'guangzhou';

$_SESSION['age'] = 88;

// session_destroy();

echo "<br>I am the last code!!";

这里写图片描述

session_destroy() 会触发sessionDestroy(),并且马上关闭session
这里写图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值