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

PHP 基於 Session 實現數據庫存儲的完整類庫

     編輯:PHP 綜合知識

為什麼要將 Session 存入數據庫?

默認 PHP Session 以文件形式存儲於服務器磁盤,集群環境下需共享存儲(NFS/Redis/DB)。數據庫方案優勢:無額外組件依賴、支持事務、便於統計在線用戶、可攜帶自定義字段(User-Agent、IP)增強安全性。

類設計亮點

  • 靜態單例模式:所有方法為 static,無需實例化;
  • 安全校驗:讀取時比對 User-Agent MD5 及客戶端 IP,防止 Session 劫持;
  • 垃圾回收:按概率(默認 20/100)隨機觸發 gc() 清理過期數據;
  • 自定義 Cookie 參數:路徑、域、Secure、HttpOnly 可配置。

核心代碼(精簡版)

fetchRow(
            "SELECT session_id, value, agent, ip FROM " . self::$table .
            " WHERE session_id = ? AND expiry > ?",
            [$sid, $expire]
        );
        if (!$rs || $rs['agent'] !== $agent || $rs['ip'] !== $ip) return false;

        self::$session_id = $rs['session_id'];
        return unserialize($rs['value']);
    }

    // 寫入/更新 Session
    private static function write(array $data) {
        $sid = self::$session_id ?: self::get_session_id();
        $expire = TIME + self::$gc_max_time;
        $agent = isset($_SERVER['HTTP_USER_AGENT']) ? md5($_SERVER['HTTP_USER_AGENT']) : '';
        $ip = Fun::getIp();
        $val = serialize($data);

        if ($sid && $sid === self::$session_id) {
            self::$dbo->query(
                "UPDATE " . self::$table . " SET value=?, expiry=?, agent=?, ip=? WHERE session_id=?",
                [$val, $expire, $agent, $ip, $sid]
            );
        } else {
            $sid = self::create_session_id();
            self::$dbo->query(
                "INSERT INTO " . self::$table . " (session_id, value, expiry, agent, ip) VALUES (?,?,?,?,?)",
                [$sid, $val, $expire, $agent, $ip]
            );
            self::$session_id = $sid;
        }
        return true;
    }

    // 生成 Session ID 並寫入 Cookie
    private static function create_session_id() {
        $sid = self::get_session_id();
        if (!$sid) {
            $sid = md5(self::$pre_key . Fun::getIp() . TIME . microtime(true) . mt_rand());
            $sid = substr($sid, 0, 32);
            setcookie('WBSID', $sid, TIME + self::$gc_max_time, self::$path, self::$domain, self::$secure, self::$httponly);
        }
        return $sid;
    }

    // 公開 API
    public static function set($key, $val = null) { /* ... */ }
    public static function get($key = null) { /* ... */ }
    public static function del($key) { /* ... */ }
    public static function destroy() { /* ... */ }
    // 垃圾回收、關閉等內部方法省略...
}

數據表結構建議

CREATE TABLE `sessions` (
  `session_id` VARCHAR(32) NOT NULL PRIMARY KEY,
  `value` TEXT NOT NULL,
  `expiry` INT(11) UNSIGNED NOT NULL,
  `agent` VARCHAR(32) NOT NULL DEFAULT '',
  `ip` VARCHAR(45) NOT NULL DEFAULT '',
  INDEX `idx_expiry` (`expiry`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

使用示例

require 'Session.php';

// 寫入
Session::set('user_id', 12345);
Session::set(['nickname' => '張三', 'role' => 'admin']);

// 讀取
$userId = Session::get('user_id');
$all = Session::get(); // 返回全部數組

// 刪除單鍵
Session::del('user_id');

// 銷毀整個 Session
Session::destroy();

生產環境優化建議

  1. 預處理語句:代碼中已使用佔位符防止 SQL 注入;
  2. 連接池:高併發下建議使用持久連接或連接池;
  3. 分表/分區:大流量站點可按 session_id 哈希分表;
  4. 異步 GC:改用定時任務(Cron)清理過期數據,避免請求阻塞;
  5. Redis 替代:極高併發場景建議直接使用 Redis 存儲 Session。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved