session 存入數據庫 php

  •  session 機制

一、php中session的生成機制php

session是保存在服務器的,當咱們在代碼中調用session_start();時,PHP會同時往SESSION的存放目錄(默認爲/tmp/)和客戶端的 cookie目錄各生成一個文件。session文件名稱像這樣:mysql

格式爲sess_{SESSIONID} ,這時session文件中沒有任何內容,當咱們在session_start();並添加了這兩行代碼:
web

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

 

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

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']的時候顯示出來。thinkphp

二、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的失效時間了。服務器

三、php中session的客戶端存儲機制cookie

由上面的介紹咱們能夠知道,若是用戶關閉了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;
}
}
相關文章
相關標籤/搜索