首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP Session 寫入資料庫完整實作:自定義 Session Handler 類別

     編輯:PHP 綜合知識

核心原理

使用 session_set_save_handler() 註冊自定義儲存處理器,將 Session 資料存入 MySQL 而非預設檔案系統,支援分散式部署、叢集環境共享 Session。

Session Handler 類別完整實作

class SessionHandler {
    protected $maxlifetime = null;
    protected $link = null;
    public $config = null;

    public static function init($args) { return new self($args); }

    public function __construct($args) {
        $this->config = $args;
        $this->maxlifetime = get_cfg_var("session.gc_maxlifetime");
        session_set_save_handler(
            [$this, "open"],
            [$this, "close"],
            [$this, "read"],
            [$this, "write"],
            [$this, "destroy"],
            [$this, "gc"]
        );
    }

    // 開啟連線、建立資料表
    public function open() {
        $this->link = mysqli_connect(
            $this->config['host'],
            $this->config['user'],
            $this->config['password'],
            $this->config['database']
        );
        mysqli_set_charset($this->link, "utf8");
        $sql = 'CREATE TABLE IF NOT EXISTS `%s` (
            `session_id` varchar(255) NOT NULL,
            `session_data` text,
            `session_expires` char(10) NOT NULL,
            PRIMARY KEY (`session_id`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;';
        $sql = sprintf($sql, $this->config['table']);
        mysqli_query($this->link, $sql);
        return true;
    }

    public function close() { return true; }

    // 讀取 Session
    public function read($session_id) {
        if (empty($session_id)) return null;
        $sql = 'SELECT `session_data` AS `data` FROM `%s` 
                WHERE `session_id` = "%s" AND `session_expires` > "%u"';
        $sql = sprintf($sql,
            mysqli_real_escape_string($this->link, $this->config['table']),
            mysqli_real_escape_string($this->link, $session_id),
            time()
        );
        $result = mysqli_query($this->link, $sql);
        $row = mysqli_fetch_assoc($result);
        return $row['data'] ?? '';
    }

    // 寫入 Session (REPLACE INTO 實現 upsert)
    public function write($session_id, $session_data) {
        if (empty($session_id)) return null;
        $newExpires = time() + $this->maxlifetime;
        $sql = 'REPLACE INTO `%s` SET 
                `session_id` = "%s", 
                `session_data` = "%s", 
                `session_expires` = "%u"';
        $sql = sprintf($sql,
            mysqli_real_escape_string($this->link, $this->config['table']),
            mysqli_real_escape_string($this->link, $session_id),
            mysqli_real_escape_string($this->link, $session_data),
            $newExpires
        );
        $result = mysqli_query($this->link, $sql);
        return mysqli_affected_rows($this->link);
    }

    // 銷毀 Session
    public function destroy($session_id) {
        $sql = 'DELETE FROM `%s` WHERE `session_id` = "%s"';
        $sql = sprintf($sql,
            mysqli_real_escape_string($this->link, $this->config['table']),
            mysqli_real_escape_string($this->link, $session_id)
        );
        $result = mysqli_query($this->link, $sql);
        return mysqli_affected_rows($this->link);
    }

    // 垃圾回收:清理過期 Session
    public function gc() {
        $sql = 'DELETE FROM `%s` WHERE `session_expires` < "%u"';
        $sql = sprintf($sql,
            mysqli_real_escape_string($this->link, $this->config['table']),
            time()
        );
        $result = mysqli_query($this->link, $sql);
        return mysqli_affected_rows($this->link);
    }
}

Session 管理封裝類別

class Session {
    public static $collection = null;

    public static function open($clean = false, $token = false) {
        if ($clean) ob_end_clean();
        if ($token) session_id($token);
        session_start();
        self::$collection = $_SESSION;
    }

    public static function id() {
        $args = func_get_args();
        return $args ? session_id($args[0]) : session_id();
    }

    public static function get($name) {
        return isset($_SESSION[$name]) ? $_SESSION[$name] : null;
    }

    public static function set($name, $value) {
        $_SESSION[$name] = $value;
        return true;
    }

    public static function delete($name) {
        if (!isset($_SESSION[$name])) return null;
        unset($_SESSION[$name]);
        return true;
    }

    public static function destroy() { session_destroy(); }
}

使用範例

$config = [
    "host"     => "127.0.0.1",
    "user"     => "root",
    "password" => "123456",
    "database" => "test",
    "charset"  => "utf8",
    "table"    => "user_session"
];

SessionHandler::init($config);
Session::open();
Session::set("profile", ["id" => 1, "user" => "haowei", "vip-level" => 6]);

資料表結構說明

欄位型別說明
session_idVARCHAR(255)主鍵,PHP Session ID
session_dataTEXT序列化後的 Session 資料
session_expiresCHAR(10)Unix 時間戳,過期時間

優化建議

  1. 索引優化:session_expires 加入索引加速 GC 查詢
  2. 資料壓縮:大 Session 可用 gzcompress() 壓縮存儲
  3. 主從分離:讀寫分離架構下,Session 讀寫建議走主庫
  4. Redis 替代:高併發場景建議改用 Redis 儲存 Session (效能更高、原生支援 TTL)
  5. 預處理語句:生產環境建議使用 prepare() 防注入

適用場景

  • 多伺服器負載均衡環境共享 Session
  • Session 持久化需求 (重啟不丟失)
  • 需查詢/分析 Session 資料 (線上用戶統計等)
  • 安全合規要求 Session 存入資料庫審計
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved