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

PHP Session 自定義儲存處理器:資料庫儲存實現分散式 Session 共享

     編輯:PHP 相關知識

為何需要自定義儲存?

  • 預設檔案儲存無法支援多伺服器負載平衡
  • Session 需在叢集間共享
  • 需自訂清理策略、加密儲存、審計追蹤

session_set_save_handler() 介面

bool session_set_save_handler(
    callable $open,
    callable $close,
    callable $read,
    callable $write,
    callable $destroy,
    callable $gc
)

資料表結構

CREATE TABLE `session` (
    `session_key` CHAR(32) NOT NULL PRIMARY KEY,
    `session_data` TEXT NOT NULL,
    `session_expiry` INT(11) UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

完整類別實作

<?php
class SessionHandler {
    private $expiry = 3600; // 1 小時
    private $pdo;

    public function __construct(PDO $pdo) {
        $this->pdo = $pdo;
        session_set_save_handler(
            [$this, 'open'],
            [$this, 'close'],
            [$this, 'read'],
            [$this, 'write'],
            [$this, 'destroy'],
            [$this, 'gc']
        );
        session_start();
    }

    public function open($savePath, $sessionName) {
        // PDO 已在建構式連線,這裡可做額外初始化
        return true;
    }

    public function close() {
        return true; // 持久連線不關閉
    }

    public function read($key) {
        $stmt = $this->pdo->prepare(
            "SELECT session_data FROM session WHERE session_key = ? AND session_expiry > ?"
        );
        $stmt->execute([$key, time()]);
        $row = $stmt->fetch(PDO::FETCH_COLUMN);
        return $row ?: '';
    }

    public function write($key, $data) {
        $expiry = time() + $this->expiry;
        $stmt = $this->pdo->prepare(
            "INSERT INTO session (session_key, session_data, session_expiry) VALUES (?, ?, ?)
             ON DUPLICATE KEY UPDATE session_data = VALUES(session_data), session_expiry = VALUES(session_expiry)"
        );
        return $stmt->execute([$key, $data, $expiry]);
    }

    public function destroy($key) {
        $stmt = $this->pdo->prepare("DELETE FROM session WHERE session_key = ?");
        return $stmt->execute([$key]);
    }

    public function gc($maxLifetime) {
        $stmt = $this->pdo->prepare("DELETE FROM session WHERE session_expiry < ?");
        return $stmt->execute([time()]);
    }
}

// 使用
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
new SessionHandler($pdo);

$_SESSION['time'] = time() + 1200;
echo time() . '<br>' . $_SESSION['time'];
?>

關鍵改進點 (vs 原始 mysql_* 版本)

項目原始版本現代版本
資料庫介面mysql_* (已移除)PDO (Prepared Statements)
SQL Injection直接拼接,高風險參數綁定,安全
字元集utf8utf8mb4 (支援 Emoji)
資料表引擎MyISAMInnoDB (交易、行鎖)
資料型別CHAR(255) 截斷風險TEXT 無長度限制
GC 效能全表掃描索引 session_expiry 加速

生產環境優化建議

  • Redis/Memcached:高效能記憶體儲存,原生支援 TTL 自動過期
  • 資料庫索引:CREATE INDEX idx_expiry ON session(session_expiry)
  • Session 鎖:預設檔案/資料庫儲存有阻塞問題,考慮 session_write_close() 早釋放鎖
  • 加密儲存:敏感資料 AES-256-GCM 加密後寫入
  • 分散式 Session:JWT 無狀態認證替代方案

第零空間版權所有

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved