安全提示:sessions/ 目录不得通过 Web 访问。请在 sessions/.htaccess 中添加 deny from all 规则,或将文件夹放置在 public_html 之外。
# 创建 sessions/.htaccess 以阻止 Web 访问
Deny from all
方案三 — 将 Session 存储在数据库中(推荐用于生产环境)
最稳健的解决方案——通过将 session 存储在 MySQL 中,完全消除 GC 干扰:
-- 在 MySQL 中创建 sessions 表
CREATE TABLE php_sessions (
id VARCHAR(128) NOT NULL PRIMARY KEY,
data TEXT NOT NULL,
expires INT NOT NULL,
INDEX idx_expires (expires)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
<?php
// 数据库 Session 处理器
class DBSessionHandler implements SessionHandlerInterface {
private PDO $db;
private int $lifetime;
public function __construct(PDO $db, int $lifetime = 86400) {
$this->db = $db;
$this->lifetime = $lifetime;
}
public function open($path, $name): bool { return true; }
public function close(): bool { return true; }
public function read($id): string {
$stmt = $this->db->prepare(
'SELECT data FROM php_sessions WHERE id=? AND expires>?'
);
$stmt->execute([$id, time()]);
return $stmt->fetchColumn() ?: '';
}
public function write($id, $data): bool {
$expires = time() + $this->lifetime;
$stmt = $this->db->prepare(
'REPLACE INTO php_sessions (id, data, expires) VALUES (?, ?, ?)'
);
return $stmt->execute([$id, $data, $expires]);
}
public function destroy($id): bool {
$stmt = $this->db->prepare('DELETE FROM php_sessions WHERE id=?');
return $stmt->execute([$id]);
}
public function gc($max_lifetime): int|false {
$stmt = $this->db->prepare('DELETE FROM php_sessions WHERE expires<?');
$stmt->execute([time()]);
return $stmt->rowCount();
}
}
// 初始化
$pdo = new PDO('mysql:host=localhost;dbname=mydb;charset=utf8mb4', 'user', 'pass');
$handler = new DBSessionHandler($pdo, 86400);
session_set_save_handler($handler, true);
ini_set('session.gc_probability', 0); // 禁用 PHP GC — 改用 expires 列控制
session_start();