刪除 Cookie 本質是設置一個已過期的 Cookie,瀏覽器收到後會刪除本地存儲。關鍵參數:
time() - 3600)<?php
// 刪除單個 Cookie
setcookie('username', '', time() - 3600, '/'); // 路徑必須匹配
// 刪除多個 Cookie(遍歷 $_COOKIE)
foreach ($_COOKIE as $name => $value) {
setcookie($name, '', time() - 3600, '/');
}
// 刪除指定前綴的 Cookie
$prefix = 'app_';
foreach ($_COOKIE as $name => $value) {
if (str_starts_with($name, $prefix)) {
setcookie($name, '', time() - 3600, '/');
}
}
?>
class CookieManager {
private string $defaultPath = '/';
private string $defaultDomain = '';
private bool $secure;
private bool $httponly = true;
private string $samesite = 'Lax';
public function __construct(array $options = []) {
$this->defaultPath = $options['path'] ?? '/';
$this->defaultDomain = $options['domain'] ?? '';
$this->secure = $options['secure'] ?? isset($_SERVER['HTTPS']);
}
/**
* 設置 Cookie
*/
public function set(string $name, string $value, int $expire = 0, array $options = []): bool {
$opts = array_merge([
'expires' => $expire ?: time() + 86400 * 30,
'path' => $this->defaultPath,
'domain' => $this->defaultDomain,
'secure' => $this->secure,
'httponly' => $this->httponly,
'samesite' => $this->samesite,
], $options);
return setcookie($name, $value, $opts);
}
/**
* 刪除單個 Cookie
*/
public function delete(string $name, array $options = []): bool {
$opts = array_merge([
'expires' => time() - 3600,
'path' => $this->defaultPath,
'domain' => $this->defaultDomain,
'secure' => $this->secure,
'httponly'=> $this->httponly,
'samesite'=> $this->samesite,
], $options);
return setcookie($name, '', $opts);
}
/**
* 批量刪除:支援精確名單、前綴、正則、回調函數
*/
public function deleteBatch(array|string|callable $matcher, array $options = []): int {
$deleted = 0;
foreach ($_COOKIE as $name => $value) {
$shouldDelete = match (true) {
is_array($matcher) => in_array($name, $matcher, true),
is_string($matcher) => $name === $matcher || str_starts_with($name, $matcher),
is_callable($matcher) => $matcher($name, $value),
default => false,
};
if ($shouldDelete) {
if ($this->delete($name, $options)) $deleted++;
}
}
return $deleted;
}
/**
* 清空當前域下所有 Cookie(謹慎使用)
*/
public function clearAll(array $options = []): int {
return $this->deleteBatch(fn($name) => true, $options);
}
/**
* 獲取 Cookie(帶默認值、類型轉換)
*/
public function get(string $name, $default = null, callable $caster = null) {
if (!isset($_COOKIE[$name])) return $default;
$value = $_COOKIE[$name];
return $caster ? $caster($value) : $value;
}
/**
* 檢查 Cookie 是否存在
*/
public function has(string $name): bool {
return isset($_COOKIE[$name]);
}
}
// 使用示例
$cookie = new CookieManager(['path' => '/', 'secure' => true]);
// 設置
$cookie->set('user_id', '12345', time() + 3600);
$cookie->set('theme', 'dark', time() + 86400 * 30);
$cookie->set('app_token', 'abc123', time() + 3600);
$cookie->set('app_refresh', 'xyz789', time() + 86400 * 7);
// 刪除單個
$cookie->delete('user_id');
// 刪除前綴匹配
$cookie->deleteBatch('app_'); // 刪除 app_token, app_refresh
// 刪除正則匹配(PHP 8+)
$cookie->deleteBatch(fn($name) => preg_match('/^temp_/', $name));
// 刪除精確名單
$cookie->deleteBatch(['theme', 'lang']);
// 清空所有
$cookie->clearAll();
// ❌ 錯誤:設置時 path=/admin,刪除時 path=/
setcookie('admin_pref', 'value', time()+3600, '/admin');
// 後續...
setcookie('admin_pref', '', time()-3600, '/'); // 無效!路徑不匹配
// ✅ 正確:刪除時使用相同路徑
setcookie('admin_pref', '', time()-3600, '/admin');
// ✅ 最佳實踐:封裝類統一管理路徑/域
$cookie = new CookieManager(['path' => '/admin']);
$cookie->set('pref', 'value');
$cookie->delete('pref'); // 內部自動使用正確路徑
| 場景 | 清理策略 | 代碼示例 |
|---|---|---|
| 用戶登出 | 刪除認證相關 Cookie,保留偏好設置 | $cookie->deleteBatch(['token', 'user_id', 'remember_me']); |
| 權限變更 | 刪除權限緩存 Cookie,強制重新獲取 | $cookie->deleteBatch(fn($n) => str_starts_with($n, 'perm_')); |
| 隱私合規(GDPR) | 用戶請求刪除所有追蹤 Cookie | $cookie->deleteBatch(fn($n) => !in_array($n, ['necessary_cookie'])); |
| 會話劫持應急 | 全站強制刷新所有用戶 Cookie | 修改 Cookie 名稱前綴或密鑰,舊 Cookie 自動失效 |
| 測試/調試 | 開發者工具一鍵清理 | 瀏覽器 DevTools → Application → Cookies → 右鍵清除 |
// 前端 JS 刪除 Cookie(需同域、同路徑)
function deleteCookie(name, path = '/', domain = '') {
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=${path}${domain ? '; domain=' + domain : ''}; SameSite=Lax`;
}
// 批量刪除
function deleteCookiesByPrefix(prefix) {
document.cookie.split(';').forEach(c => {
const name = c.split('=')[0].trim();
if (name.startsWith(prefix)) deleteCookie(name);
});
}
// 登出時調用
deleteCookie('token');
deleteCookie('user_id');
deleteCookiesByPrefix('app_');
// 查看即將發送的 Set-Cookie 頭(不實際發送)
function debugSetCookie(string $name, string $value, array $options = []) {
$opts = array_merge([
'expires' => time() + 3600,
'path' => '/',
'domain' => '',
'secure' => false,
'httponly' => true,
'samesite' => 'Lax',
], $options);
$parts = [$name . '=' . urlencode($value)];
$parts[] = 'Expires=' . gmdate('D, d-M-Y H:i:s T', $opts['expires']);
$parts[] = 'Path=' . $opts['path'];
if ($opts['domain']) $parts[] = 'Domain=' . $opts['domain'];
if ($opts['secure']) $parts[] = 'Secure';
if ($opts['httponly']) $parts[] = 'HttpOnly';
$parts[] = 'SameSite=' . $opts['samesite'];
return 'Set-Cookie: ' . implode('; ', $parts);
}
// 測試
echo debugSetCookie('test', 'value', ['path' => '/admin']);
// 輸出: Set-Cookie: test=value; Expires=...; Path=/admin; HttpOnly; SameSite=Lax
PHP 批量刪除 Cookie 核心在於精確匹配設置時的路徑、域、安全屬性。封裝 CookieManager 類統一管理配置,支援精確名單、前綴匹配、正則、回調函數多種批量模式,配合前端 JS 協同清理,可覆蓋登出、權限變更、隱私合規、應急響應等全場景。關鍵原則:設置與刪除參數完全一致、封裝統一管理、最小權限、安全屬性全開、操作可審計。