zoukankan      html  css  js  c++  java
  • session 存入数据库 php

    •  session 机制

    1、php中session的生成机制

    session是保存在服务器的,当我们在代码中调用session_start();时,PHP会同时往SESSION的存放目录(默认为/tmp/)和客户端的 cookie目录各生成一个文件。session文件名称像这样:

    格式为sess_{SESSIONID} ,这时session文件中没有任何内容,当我们在session_start();并添加了这两行代码:

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

    $_SESSION['blog'] = 'coderbolg.net';

    session文件会生成如下代码保存在session文件中
    name|s:11:"wanchun0222";blog|s:13:"coderbolg.net";

    这时再看看cookie:

    可以看到服务器为我们自动生成了一个cookie,cookie名称为"PHPSESSID",cookie内容是一串字符,其实这串字符就是 {SESSIONID}。当我们使用session时,PHP就先生成一个唯一的SESSIONID号(如 2bd170b3f86523f1b1b60b55ffde0f66),再在我们服务器的默认目录下生成一个文件,文件名为 sess_{SESSIONID},同时在当前用户的客户端生成一个cookie,内容已经说过了。这样PHP会为每一个用户生成一个 SESSIONID,也就是说一个用户一个session文件。PHP第一次为某个用户使用session时就向客户端写入了cookie,当这个用户以 后访问时,浏览器会带上这个cookie,PHP在拿到cookie后就读出里面的SESSIONID,拿着这个SESSIONID去session目录 下找session文件。找到后在调用$_SESSION['blog']的时候显示出来。

    2、php中session的过期回收机制

    我们明白了session的生成及工作原理,发现在session目录下会有许多session文件。当然这些文件一定不是永远存在的,PHP一定 提供了一种过期回收机制。在php.ini中session.gc_maxlifetime为session设置了生存时间(默认为1440s)。如果 session文件的最后更新时间到现在超过了生存时间,这个session文件就被认为是过期的了。在下一次session回收的时候就会被删除。那下 一次session回收是在什么时候呢?这和php请求次数有关的。在PHP内部机制中,当php被请求了N次后就会有一次触发回收机制。到底是请求多少 次触发一次是通过以下两个参数控制的:

    session.gc_probability = 1

    session.gc_divisor = 100


    这是php.ini的默认设置,意思是每100次PHP请求就有一次回收发生。概率是 gc_probability/gc_divisor 。我们了解了服务器端的session过期机制,再来看看客户端的cookie的过期机制。

    如果cookie失效了浏览器自然发送不了cookie到服务器,这时即使服务器的session文件存在也没用,因为PHP不知道要读取哪个 session文件。我们知道PHP的cookie过期时间是在创建时设置的,那么PHP在创建session的同时为客户端创建的cookie的生命周 期是多久呢?这个在php.ini中有设置:session.cookie_lifetime 。这个值默认是0,代表浏览器一关闭SESSIONID就失效。那就是说我们把session.gc_maxlifetime和 session.cookie_lifetime设置成同一个值就可以控制session的失效时间了。

    3、php中session的客户端存储机制

    由上面的介绍我们可以知道,如果用户关闭了cookie,那我们的session就完全没法工作了。是的,确实是这样。php中session的客 户端存储机制只有cookie吗?不是的。既然我们的SESSIONID 不能通过cookie传递到各个页面,那我们还有另一个法宝,就是通过页面GET传值的方式。

    PHP可以在cookie被禁用时自动通过GET方式跨页传递SESSIONID,前提是设置php.ini的 session.use_trans_sid为1。这时当我们在客户端禁用了cookie时使用了session,并在当前页面通过点击链接到另一页面 时,PHP会自动在链接上添加SESSIONID参数,像这 样:nextpage.php?SESSIONID=2bd170b3f86523f1b1b60b55ffde0f66。

    • session存入MySQL 数据库
    <?php 
    /*============================文件说明======================================== 
    @filename:     session.class.php 
    @description:  数据库保存在线用户session,实现在线用户功能! 
    @notice:       session过期时间一个小时,因为我们的站点是使用cookie(有效时间是1小时)登录。                 
              因此我们只记录用户登录的时间,而不是刷新一次更新一次                 
              删除数据库中session记录的动作发生在用户超时后执行这个文件或正常退出(session_destory)  
    @database:     database:sessions  field:sessionid(char32),uid(int10),last_visit(int10) 
    @author:       duanjianbo          
    @adddate       2008-8-29 
    =============================================================================
    */
     class session { 
         private $db; 
         private $lasttime=3600;//超时时间:一个小时
          function session(&$db) { 
             $this->db = &$db;
             session_module_name('user'); //session文件保存方式,这个是必须的!除非在Php.ini文件中设置了
             session_set_save_handler( 
                 array(&$this, 'open'), //在运行session_start()时执行
                  array(&$this, 'close'), //在脚本执行完成或调用session_write_close() 或 session_destroy()时被执行,即在所有session操作完后被执行 
                 array(&$this, 'read'), //在运行session_start()时执行,因为在session_start时,会去read当前session数据
                 array(&$this, 'write'), //此方法在脚本结束和使用session_write_close()强制提交SESSION数据时执行
                  array(&$this, 'destroy'), //在运行session_destroy()时执行
                  array(&$this, 'gc') //执行概率由session.gc_probability 和 session.gc_divisor的值决定,时机是在open,read之后,session_start会相继执行open,read和gc
             ); 
             session_start(); //这也是必须的,打开session,必须在session_set_save_handler后面执行
         } 
            function unserializes($data_value) { 
             $vars = preg_split( 
                 '/([a-zA-Z_x7f-xff][a-zA-Z0-9_x7f-xff]*)|/', 
                 $data_value, -1, PREG_SPLIT_NO_EMPTY | 
                 PREG_SPLIT_DELIM_CAPTURE 
             ); 
             for ($i = 0; isset($vars[$i]); $i++) { 
                 $result[$vars[$i++]] = unserialize($vars[$i]); 
             } 
             return $result; 
         }  
         function open($path, $name) { 
             return true; 
         } 
         function close() { 
             $this->gc($this->lasttime);
             return true; 
         } 
        function read($SessionKey){
             $sql = "SELECT uid FROM sessions WHERE session_id = '".$SessionKey."' limit 1"; 
             $query =$this->db->query($sql);
             if($row=$this->db->fetch_array($query)){
               return $row['uid'];
             }else{
                 return ""; 
             }
                  } 
         function write($SessionKey,$VArray) { 
             require_once(MRoot.DIR_WS_CLASSES .'db_mysql_class.php');
            $db1=new DbCom();
           // make a connection to the database... now
            $db1->connect(DB_SERVER, DB_SERVER_USERNAME, DB_SERVER_PASSWORD, DB_DATABASE);
            $db1->query("set names utf8");
            $this->db=$db1;
            $SessionArray = addslashes($VArray);
             $data=$this->unserializes($VArray);   
                              $sql0 = "SELECT uid FROM sessions WHERE session_id = '".$SessionKey."' limit 1"; 
             $query0 =$this->db->query($sql0);
             if($this->db->num_rows($query0)<=0){
                 if (isset($data['webid']) && !empty($data['webid'])) { 
                    $this->db->query("insert into `sessions` set `session_id` = '$SessionKey',uid='".$data['webid']."',last_visit='".time()."'");
                 }    
                        return true;
             }else{
                 /*$sql = "update `sessions` set "; 
                 if(isset($data['webid'])){
                 $sql .= "uid = '".$data['webid']."', " ;
                 }
                 $sql.="`last_visit` = null " 
                       . "where `session_id` = '$SessionKey'"; 
                                   $this->db->query($sql); */
                 return true; 
             }    
         } 
       function destroy($SessionKey) { 
          $this->db->query("delete from `sessions` where `session_id` = '$SessionKey'"); 
          return true; 
        } 
        function gc($lifetime) {
            $this->db->query("delete from `sessions` where unix_timestamp(now()) -`last_visit` > '".$this->lasttime."'");
            return true;
        } 
         } 
     ?> 
    

    以上代码放入到文件session_db.php中,

    然后每一个文件头最上方引用一下include_once('session_db.php')即可。

    另外,在php.ini中要将session.save_handler设置为"user"即可。

    这样就可以将数据库保存到mysql的tb_session表中,可以有很多人访问,再也不用担心访问的人过多导致session_temp文件目录中的碎文件过多读取效率低下的问题了。

    随辅:tb_session的数据库脚本:

    CREATE TABLE `tb_session` (

      `session_key` varchar(30) NOT NULL,

      `session_data` varchar(60) DEFAULT NULL,

      `session_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

      PRIMARY KEY (`session_key`)

    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    以下同上代码作用一致,代码稍作调整

    <?php
      /*
      *@author  Fahy
      *数据库为mysql,
      *数据库名为session,表名为session,
      *表中字段包括PHPSESSID,update_time,client_ip,data
      */
      class Session{
        private static $handler = null;
        private static $ip = null;
        private static $lifetime = null;
        private static $time = null;
         
        //配置静态变量
        private static function init($handler){
          self::$handler = $handler;    //获取数据库资源
          self::$ip = !empty($_SERVER["REMOTE_ADDR"])? $_SERVER["REMOTE_ADDR"]:'unkonw';    //获取客户端ip
          self::$lifetime = ini_get('session.gc_maxlifetime');    //获取session生命周期
          self::$time = time();    //获取当前时间
        }
        //调用session_set_save_handler()函数并开启session
        static function start($pdo){
          self::init($pdo);
          session_set_save_handler(
            array(__CLASS__,'open'),
            array(__CLASS__,'close'),
            array(__CLASS__,'read'),
            array(__CLASS__,'write'),
            array(__CLASS__,'destroy'),
            array(__CLASS__,'gc')
          );
          session_start();
        }
         
        public static function open($path,$name){
          return true;
        }
        public static function close(){
          return true;
        }
         
        //查询数据库中的数据
        public static function read($PHPSESSID){
          $sql = "select PHPSESSID,update_time,client_ip,data from session where PHPSESSID=?";
          $stmt = self::$handler->prepare($sql);
          $stmt->execute(array($PHPSESSID));
          if(!$result = $stmt->fetch(PDO::FETCH_ASSOC)){
            return '';
          }
          if(self::$ip == $result['client_ip']){
            self::destroy($PHPSESSID);
            return '';
          }
          if(($result['update_time']+self::$lifetime)<self::$time){
            self::destroy($PHPSESSID);
            return '';
          }
          return $result['data'];
        }
        /*
        *首先查询该session是否存在数据,如果存在,则更新数据,如果不存在,则插入数据
        */
        //将session写入数据库中,$data传入session中的keys和values数组
        public static function write($PHPSESSID,$data){
          $sql = "select PHPSESSID,update_time,client_ip,data from session where PHPSESSID=?";
          $stmt = self::$handler->prepare($sql);
          $stmt->execute(array($PHPSESSID));
           
          if($result=$stmt->fetch(PDO::FETCH_ASSOC)){        
            if($result['data'] != $data || self::$time > ($result['update_time']+30)){
              $sql = "update session set update_time=?,data=? where PHPSESSID = ?";
              $stmt = self::$handler->prepare($sql);
              $stmt->execute(array($self::$time,$data,$PHPSESSID));
            }
          }else{
            if(!empty($data)){
              try{
                $sql = "insert into session(PHPSESSID,update_time,client_ip,data) values(?,?,?,?)";
              }catch(PDOException $e){
                echo $e->getMessage();
              }
              $sth = self::$handler->prepare($sql);
              $sth->execute(array($PHPSESSID,self::$time,self::$ip,$data));
            }
          }
          return true;
        }
         
        public static function destroy($PHPSESSID){
          $sql = "delete from session where PHPSESSID = ?";
          $stmt = self::$handler->prepare($sql);
          $stmt->execute(array($PHPSESSID));
          return true;
        }
        public static function gc($lifetime){
          $sql = "delete from session where update_time<?";
          $stmt = self::$handler->prepare($sql);
          $stmt->execute(array(self::$time-$lifetime));
          return true;
        }
      }
      //使用PDO连接数据库
      try{
        $pdo = new PDO("mysql:host=localhost;dbname=session","root","hwj193");
      }catch(PDOException $e){
        echo $e->getMessage();
      }
      //传递数据库资源
      Session::start($pdo);
    • session存入数据库(在thinkphp中)
    <?php
    try{
    $pdo = new PDO('mysql:host=localhost;dbname=rphp4zf', 'root','');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    new SessionToDB($pdo);
    } catch(PDOException $e) {
    echo 'Error: '.$e->getMessage();
    }

    class SessionToDB
    {
    private $_path = null;
    private $_name = null;
    private $_pdo = null;
    private $_ip = null;
    private $_maxLifeTime = 0;

    public function __construct(PDO $pdo)
    {
    session_set_save_handler(
    array(&$this, 'open'),
    array(&$this, 'close'),
    array(&$this, 'read'),
    array(&$this, 'write'),
    array(&$this, 'destroy'),
    array(&$this, 'gc')
    );

    $this->_pdo = $pdo;
    $this->_ip = !empty($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null;
    $this->_maxLifeTime = ini_get('session.gc_maxlifetime');
    }

    public function open($path,$name)
    {
    return true;
    }

    public function close()
    {
    return true;
    }

    public function read($id)
    {
    $sql = 'SELECT * FROM session where PHPSESSID = ?';
    $stmt = $this->_pdo->prepare($sql);
    $stmt->execute(array($id));

    if (!$result = $stmt->fetch(PDO::FETCH_ASSOC)) {
    return null;
    } elseif ($this->_ip != $result['client_ip']) {
    return null;
    } elseif ($result['update_time']+$this->_maxLifeTime < time()){
    $this->destroy($id);
    return null;
    } else {
    return $result['data'];
    }
    }

    public function write($id,$data)
    {
    $sql = 'SELECT * FROM session where PHPSESSID = ?';
    $stmt = $this->_pdo->prepare($sql);
    $stmt->execute(array($id));

    if ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
    if ($result['data'] != $data) {
    $sql = 'UPDATE session SET update_time =? , date = ? WHERE PHPSESSID = ?';

    $stmt = $this->_pdo->prepare($sql);
    $stmt->execute(array(time(), $data, $id));
    }
    } else {
    if (!empty($data)) {
    $sql = 'INSERT INTO session (PHPSESSID, update_time, client_ip, data) VALUES (?,?,?,?)';
    $stmt = $this->_pdo->prepare($sql);
    $stmt->execute(array($id, time(), $this->_ip, $data));
    }
    }

    return true;
    }

    public function destroy($id)
    {
    $sql = 'DELETE FROM session WHERE PHPSESSID = ?';
    $stmt = $this->_pdo->prepare($sql);
    $stmt->execute(array($id));

    return true;
    }

    public function gc($maxLifeTime)
    {
    $sql = 'DELETE FROM session WHERE update_time < ?';
    $stmt = $this->_pdo->prepare($sql);
    $stmt->execute(array(time() - $maxLifeTime));

    return true;
    }
    }

  • 相关阅读:
    Informatica 常用组件Lookup缓存之五 使用动态查找高速缓存
    Informatica 常用组件Lookup缓存之四 使用不高速缓存的查找或静态高速缓存
    Informatica 常用组件Lookup缓存之三 重建查找高速缓存
    Golang入门教程(十一)beego 框架之RESTful Controller 路由
    PHP7 学习笔记(十二)PHPExcel vs PhpSpreadsheet and PHP_XLSXWriter
    PHP7 学习笔记(十二)gRPC
    PHP7 学习笔记(十一)使用phpstudy快速配置一个虚拟主机
    Golang入门教程(十)内建函数
    Golang入门教程(九)复合数据类型使用案例二
    Golang入门教程(八)复合数据类型使用案例一
  • 原文地址:https://www.cnblogs.com/jingzi111/p/5900709.html
Copyright © 2011-2022 走看看