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

PHP setcookie 刪除 Cookie 深度解析:空值、NULL 與過期時間的底層邏輯

     編輯:PHP 相關知識

現象回顧

許多開發者發現:setcookie('name', '') 或 setcookie('name', null) 竟然能刪除 Cookie,而官方文檔建議設定過期時間為過去。這背後是什麼機制?

一、PHP 內核原始碼分析(PHP 8.2 參考)

關鍵檔案:ext/standard/head.c → php_setcookie()

// 簡化版核心邏輯
PHPAPI int php_setcookie(char *name, int name_len, char *value, int value_len, time_t expires, ...) {
    // ... 參數解析 ...
    
    if (value && value_len == 0) {           // ★ 關鍵判斷:值存在但長度為 0
        // 空字串情況:強制產生刪除 Cookie
        dt = php_format_date("D, d-M-Y H:i:s T", ..., 1, 0); // 時間戳 1 = 1970-01-01 00:00:01 GMT
        snprintf(cookie, len + 100, "Set-Cookie: %s=deleted; expires=%s", name, dt);
        efree(dt);
    } else {
        // 正常設定 Cookie
        snprintf(cookie, len + 100, "Set-Cookie: %s=%s", name, value ? encoded_value : "");
        if (expires > 0) {
            strlcat(cookie, "; expires=", len + 100);
            dt = php_format_date(..., expires, ...);
            strlcat(cookie, dt, len + 100);
        }
    }
    // ... 發送 header ...
}

二、三種刪除方式的等價性

呼叫方式內部處理生成 Header 範例備註
setcookie('name', '')value="", value_len=0Set-Cookie: name=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT最常用、語意清晰
setcookie('name', null)PHP 內部 zend_parse_parameters 將 null 轉為空字串同上等同空字串
setcookie('name', 'x', time()-3600)expires 為過去時間Set-Cookie: name=x; expires=Wed, 17-Jan-2024 10:00:00 GMT傳統寫法,需計算時間

三、為什麼設計成「空值即刪除」?

註解原文:MSIE doesn't delete a cookie when you set it to a null value so in order to force cookies to be deleted, even on MSIE, we pick an expiry date in the past

早期 IE 不支援 Set-Cookie: name=(無值)刪除,PHP 為了跨瀏覽器一致性,**主動攔截空值並注入過期時間**,確保行為統一。

四、實際測試驗證

<?php
// test_cookie.php
header('Content-Type: text/plain');

// 1. 設定 Cookie
setcookie('test_empty', '', time() + 3600); // 預期:設定一個空值 Cookie
setcookie('test_null', null, time() + 3600); // 預期:同空值
setcookie('test_normal', 'value', time() + 3600);

// 2. 觀察響應 Header(瀏覽器開發者工具 Network 標籤)
// 實際發送:
// Set-Cookie: test_empty=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0
// Set-Cookie: test_null=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0
// Set-Cookie: test_normal=value; expires=Fri, 18-Jan-2025 12:00:00 GMT

// 3. 驗證 $_COOKIE 下次請求
// test_empty、test_null 不會出現在 $_COOKIE 中(已被瀏覽器刪除)
// test_normal 會出現
?>

五、最佳實踐建議

1. 明確語意:使用專用函式

<?php
function deleteCookie(string $name, string $path = '/', string $domain = '', bool $secure = false, bool $httponly = true): void {
    setcookie($name, '', [
        'expires' => time() - 3600, // 明確過期
        'path' => $path,
        'domain' => $domain ?: '',
        'secure' => $secure,
        'httponly' => $httponly,
        'samesite' => 'Lax',
    ]);
}

// PHP 7.3+ 陣列語法
deleteCookie('session_id');
deleteCookie('remember_token', '/', '.example.com');

2. 避免隱性 Bug

  • 不要依賴「空值自動刪除」這個行為在文檔中明確承諾(雖然 20 年來未變)。
  • 路徑、域名、Secure、HttpOnly、SameSite **必須與設定時一致**,否則瀏覽器不會刪除對應 Cookie。

3. 批次清理(登出場景)

<?php
function clearAuthCookies(): void {
    $cookies = ['user_id', 'session_token', 'remember_me', 'csrf_token'];
    foreach ($cookies as $name) {
        deleteCookie($name);
    }
    // 如果用 session
    session_destroy();
}
?>

六、常見誤區

誤區真相
setcookie('name', false) 刪除false 轉字串為 "",同空值刪除
setcookie('name', 0) 刪除0 轉字串為 "0",**不會刪除**,會設定值為 "0"
只設定名稱 setcookie('name')報錯:缺少參數 2
刪除後立即 $_COOKIE['name'] 為空$_COOKIE 只反映**當前請求**的 Cookie,下一次請求才會消失

七、SameSite 與安全屬性補充

<?php
// 現代寫法(PHP 7.3+)
setcookie('auth', '', [
    'expires' => time() - 3600,
    'path' => '/',
    'domain' => '.example.com',
    'secure' => true,      // 僅 HTTPS
    'httponly' => true,    // 防 XSS
    'samesite' => 'Strict', // 防 CSRF
]);
?>

結語

setcookie($name, '') 能刪除 Cookie 是 PHP 內核為了相容舊版 IE 故意設計的「特性」,實際上注入了 expires=1970-01-01 與 value=deleted。雖然好用,但**生產代碼建議顯式設定過期時間與屬性**,確保語意明確、跨瀏覽器行為一致、安全屬性完整傳遞。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved