本文提供一個生產級 UserLogin 靜態類,結合 Session(伺服器端)與 Cookie(客戶端)實現「記住我」自動登入、跨請求狀態保持、登出清理等完整流程,並附帶登入控制器調用範例與 Session/Cookie 差異深度解析。
UserLoginfinal class UserLogin {
public static function getUserInfo() {
if (isset($_COOKIE['user_id']) && $_COOKIE['user_id'] && trim($_COOKIE['user_id']) !== '') {
if (isset($_SESSION['USER_INFO'])) return $_SESSION['USER_INFO'];
$dao = new UserDao();
$user = $dao->find($_COOKIE['user_id']);
if ($user) {
$_SESSION['USER_INFO'] = $user;
self::refreshCookies($user);
return $user;
}
}
self::clearCookie();
return null;
}
public static function setUserInfo($userInfo) {
$_SESSION['USER_INFO'] = $userInfo;
setcookie('docloud_sid', session_id(), time() + 36000);
setcookie('user_id', $userInfo->getId(), time() + 36000);
}
public static function isLogin() { return self::getUserInfo() !== null; }
public static function delUserInfo() {
self::clearCookie();
session_destroy();
}
private static function refreshCookies($user) {
setcookie('docloud_sid', session_id(), time() + 36000);
setcookie('user_id', $user->getId(), time() + 36000);
// 同步延長業務相關 Cookie
foreach (['selected_prj_id','selected_class_id','selected_image_id','test_image_ids','upload_image_ids'] as $key) {
if (array_key_exists($key, $_COOKIE))
setcookie($key, $_COOKIE[$key], time() + 36000);
}
}
private static function clearCookie() {
foreach (['docloud_sid','user_id','selected_prj_id','selected_class_id','selected_image_id','test_image_ids','upload_image_ids'] as $key)
setcookie($key, '', time() - 36000);
}
}
require_once 'Init.php';
if (UserLogin::isLogin() && $_COOKIE['user_id'] == 1) UserLogin::delUserInfo();
elseif (UserLogin::isLogin()) Utils::redirect('welcome');
$msg = '';
if (isset($_POST['username'], $_POST['password'])) {
$username = addslashes(trim(stripslashes($_POST['username'])));
$password = addslashes(trim(stripslashes($_POST['password'])));
$errors = LoginValidator::validate($username, $password);
if (empty($errors)) {
$dao = new UserDao();
$user = $dao->findByName($username);
$user->setLastLoginIp(Utils::getIpAddress());
$user->setLastLoginTime(new DateTime());
$dao->save($user);
UserLogin::setUserInfo($user);
Flash::addFlash('登入成功!');
Utils::redirect('welcome');
}
foreach ($errors as $e) $msg .= $e->getMessage().'<br>';
}
| 維度 | Cookie | Session |
|---|---|---|
| 儲存位置 | 客戶端瀏覽器/硬碟 | 伺服器端記憶體/檔案/資料庫 |
| 安全性 | 可被竄改、偽造、攔截 | 資料不外露,僅傳遞 Session ID |
| 生命週期 | 可設定持久化(跨瀏覽器關閉) | 通常隨瀏覽器關閉失效,伺服器可配置 |
| 容量限制 | 單個 ~3KB,域名下共 ~20 個 | 受限於伺服器記憶體/儲存配置 |
| 適用場景 | 非敏感偏好、追蹤、記住我 Token | 用戶身份、權限、購物車等敏感狀態 |
最佳實踐:登入憑證、權限等核心資訊放 Session;「記住我」長效 Token、UI 偏好放 Cookie;並對 Cookie 內容簽名/加密防竄改。