牛骨文教育服务平台(让学习变的简单)
博文笔记

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

创建时间:2016-04-28 投稿人: 浏览次数:2947

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
这里写图片描述

声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。