PHP Session

Session(會話)是一種在伺服器端儲存使用者資料的機制。與 Cookie 不同,Session 資料存放在伺服器上,只有一個唯一的 Session ID 會傳送給使用者(通常透過 Cookie)。這讓 Session 更適合儲存敏感資料,例如登入狀態、購物車內容、使用者權限等。

開始 Session

使用 session_start() 開始或恢復一個 Session。這個函數必須在任何 HTML 輸出之前呼叫,它會讀取使用者的 Session ID(如果有的話)並載入對應的 Session 資料。

<?php
session_start();  // 必須在任何輸出之前

// 設定 Session 變數
$_SESSION['username'] = 'Alice';
$_SESSION['user_id'] = 123;

// 讀取 Session 變數
echo $_SESSION['username'];  // Alice

// 檢查是否存在
if (isset($_SESSION['username'])) {
    echo "已登入";
}
?>

登入範例

<?php
session_start();

// 登入
function login(int $userId, string $username): void {
    $_SESSION['user_id'] = $userId;
    $_SESSION['username'] = $username;
    $_SESSION['logged_in'] = true;
    $_SESSION['login_time'] = time();
    
    // 重新產生 Session ID 防止 Session Fixation
    session_regenerate_id(true);
}

// 檢查是否已登入
function isLoggedIn(): bool {
    return isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === true;
}

// 取得使用者資訊
function getCurrentUser(): ?array {
    if (!isLoggedIn()) {
        return null;
    }
    
    return [
        'id' => $_SESSION['user_id'],
        'username' => $_SESSION['username']
    ];
}

// 登出
function logout(): void {
    $_SESSION = [];
    
    if (ini_get("session.use_cookies")) {
        $params = session_get_cookie_params();
        setcookie(session_name(), '', time() - 42000,
            $params["path"], $params["domain"],
            $params["secure"], $params["httponly"]
        );
    }
    
    session_destroy();
}
?>

刪除 Session

當使用者登出或需要清除 Session 時,應該完整地清除 Session 資料、移除 Session Cookie,並銷毀 Session 本身:

<?php
session_start();

// 刪除單一變數
unset($_SESSION['username']);

// 清空所有 Session 變數
$_SESSION = [];

// 銷毀 Session
session_destroy();
?>

Session 設定

可以在 session_start() 之前調整 Session 的行為,例如設定 Cookie 的安全選項、過期時間等:

<?php
// 在 session_start() 之前設定
ini_set('session.cookie_lifetime', 0);      // 關閉瀏覽器後過期
ini_set('session.cookie_httponly', 1);      // HttpOnly
ini_set('session.cookie_secure', 1);        // 只在 HTTPS
ini_set('session.cookie_samesite', 'Lax');  // SameSite

// 或使用 session_set_cookie_params
session_set_cookie_params([
    'lifetime' => 0,
    'path' => '/',
    'domain' => 'example.com',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Lax'
]);

session_start();
?>

安全最佳實踐

Session 安全是 Web 應用程式安全的重要環節。以下實踐可以防止 Session 劫持(Session Hijacking)和 Session 固定攻擊(Session Fixation):

<?php
// 1. 重新產生 Session ID
session_start();
if (!isset($_SESSION['initiated'])) {
    session_regenerate_id(true);
    $_SESSION['initiated'] = true;
}

// 2. 驗證使用者代理
if (isset($_SESSION['user_agent'])) {
    if ($_SESSION['user_agent'] !== $_SERVER['HTTP_USER_AGENT']) {
        session_destroy();
        die('Session hijacking detected');
    }
} else {
    $_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
}

// 3. 設定 Session 過期時間
$timeout = 1800;  // 30 分鐘
if (isset($_SESSION['last_activity'])) {
    if (time() - $_SESSION['last_activity'] > $timeout) {
        session_destroy();
        header('Location: login.php');
        exit;
    }
}
$_SESSION['last_activity'] = time();
?>

Flash 訊息

Flash 訊息是一種只顯示一次的 Session 資料,常用於在重新導向後顯示操作結果(如「儲存成功」或「刪除失敗」)。訊息在讀取後會自動移除:

<?php
function setFlash(string $type, string $message): void {
    $_SESSION['flash'][$type] = $message;
}

function getFlash(string $type): ?string {
    $message = $_SESSION['flash'][$type] ?? null;
    unset($_SESSION['flash'][$type]);
    return $message;
}

// 使用
setFlash('success', '資料已儲存!');

// 顯示
if ($message = getFlash('success')) {
    echo "<div class='alert alert-success'>$message</div>";
}
?>
特性SessionCookie
儲存位置伺服器瀏覽器
安全性較高較低
大小限制無限制約 4KB
生命週期預設至瀏覽器關閉可設定很長
適用場合敏感資料、登入狀態偏好設定、追蹤