在 IE6-IE9 中,使用 window.open() 或 target="_blank" 開啟新視窗時,PHP Session ID (PHPSESSID) 因儲存於「進程級」 Cookie(無 Expires,瀏覽器關閉即失效),導致新進程無法讀取舊進程的 Session,造成登入狀態遺失。本文詳細實測過程、根因分析與解決方案。
<?php
// index.php
setcookie('persist_cookie', 'value', time() + 3600); // 持久性 Cookie
session_start();
$_SESSION['test'] = 'session_value';
var_dump($_SESSION, $_COOKIE);
?>
<input type="button" value="window.open" onclick="window.open('b.php');">
<a href="b.php" target="_blank">target=_blank</a>
<?php
// b.php
session_start();
var_dump($_SESSION, $_COOKIE);
| 瀏覽器 | window.open | target="_blank" | 持久性 Cookie | Session Cookie |
|---|---|---|---|---|
| IE6/7/8/9 (IETester) | 遺失 | 遺失 | 保留 | 遺失 |
| IE10/11 (Win 內建) | 正常 | 正常 | 保留 | 保留 |
| Chrome | 正常 | 正常 | 保留 | 保留 |
| Firefox | 正常 | 正常 | 保留 | 保留 |
Expires/Max-Age,屬「會話級 Cookie」,瀏覽器進程關閉即銷毀。IE6-9 開新視窗會啟動新進程,舊進程的會話級 Cookie 不共享。Expires,寫入硬碟,跨進程可讀取。<?php
// 在 session_start() 之前設定
$lifetime = 3600 * 24 * 30; // 30 天
session_set_cookie_params($lifetime, '/', '', false, true); // path, domain, secure, httponly
session_start();
// 或直接修改 php.ini
// session.cookie_lifetime = 2592000
// session.cookie_path = /
// session.cookie_httponly = 1
將 Session ID 寫入持久性 Cookie,跨進程即可共享。需注意安全性:建議啟用 httponly、HTTPS 下啟用 secure。
<?php
ini_set('session.use_trans_sid', 1);
ini_set('session.use_only_cookies', 0);
session_start();
PHP 會自動將 PHPSESSID 附加至相對連結/表單 action。缺點: 不美觀、易洩露 Session ID、相對路徑才會自動附加、靜態資源也會帶上參數。
<?php
// 登入成功時
$user_id = 123;
$token = bin2hex(random_bytes(32));
// 存資料庫:user_sessions (user_id, token, expire, ua, ip)
setcookie('auth_token', $token, time() + 86400*30, '/', '', true, true); // 持久、httponly、secure
// 每次請求驗證
session_start();
if (empty($_SESSION['user_id']) && !empty($_COOKIE['auth_token'])) {
// 查資料庫驗證 token,通過則重建 $_SESSION['user_id']
}
不依賴 PHP 原生 Session 機制,完全由應用層控制,跨瀏覽器、跨進程、跨裝置皆穩定。
window.open。window.open('b.php?token=' + getCookie('auth_token'))。