HOWTO · PHP
在 PHP 中設定會話超時
本教程說明如何在 PHP 中追蹤閒置時間,並以 30 分鐘為限實作工作階段逾時。
本頁內容
PHP 不會自動讓應用程式工作階段在閒置一段指定時間後逾時。若要實作 30 分鐘逾時,請將上次請求的時間存入 $_SESSION,在每次請求時將它與目前時間比較,並在時間差達到或超過 1,800 秒時採取相應措施。閒置時間結束後,必須等到下一個請求才會偵測到逾時;瀏覽器停止傳送請求的當下,伺服器無法立即採取動作。
如何在 PHP 中追蹤工作階段逾時
請先呼叫 session_start(),再讀取或變更 $_SESSION。第一次收到請求時尚無已儲存的活動時間,因此要先初始化。後續請求則將儲存的時間與 time() 比較。若已達到 1,800 秒的限制,就清除工作階段資料並結束請求;否則更新活動時間,讓 30 分鐘的計時重新開始。
執行以下範例:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
<?php
session_start();
$timeoutSeconds = 30 * 60;
$now = time();
if (isset($_SESSION['last_activity']) &&
$now - $_SESSION['last_activity'] >= $timeoutSeconds) {
session_unset();
session_destroy();
echo "Session expired" . PHP_EOL;
exit;
}
$_SESSION['last_activity'] = $now;
echo "Session active" . PHP_EOL;
Session active
第一次請求會初始化 last_activity,並走有效工作階段的處理路徑。之後每次請求都會先檢查前一次儲存的時間戳,再更新它。提供的執行證據顯示,有效工作階段路徑的訊息是 Session active,結束代碼為 0;證據並未顯示逾時路徑曾經執行。在應用程式中,請將這項檢查放在呼叫 session_start() 之後、受保護的操作之前,避免逾時的請求仍被當作已驗證請求處理。
閒置 30 分鐘後銷毀工作階段
逾時後,範例會同時使用 session_unset() 和 session_destroy()。session_unset() 會移除目前的工作階段變數,而 session_destroy() 會移除作用中的工作階段處理常式所儲存的工作階段資料。銷毀伺服器端資料本身不會移除瀏覽器中的工作階段 Cookie。若應用程式也需要讓該 Cookie 失效,就必須使用相同的名稱、路徑與網域設定傳送已過期的 Cookie;Cookie 的處理方式取決於應用程式的工作階段設定。
這是應用程式層級的逾時:只有請求抵達執行檢查的程式碼時才會進行檢查。PHP 的工作階段儲存期限設定是用來管理儲存資料的清理,與這項逐次請求執行的閒置政策不同。請參閱 PHP 手冊中的 session_unset() 函式 和工作階段設定選項。
使用 unset() 移除工作階段變數
使用 unset($_SESSION['cart']) 可移除單一項目,同時保留其他工作階段項目。若使用者只要移除某項狀態(例如購物車),而不結束整個工作階段,這種做法就很合適。單靠這項操作無法實作閒置逾時。若有一組相關值,請將它們存放在陣列鍵之下,並只用 unset($_SESSION['account_state']) 移除該鍵;如果後續的逾時檢查需要 registered 元素,就不要把整個陣列改成時間戳。
呼叫 session_start() 後,即可使用 $_SESSION 超全域變數。請參閱 PHP 手冊中的 $_SESSION。
將工作階段 ID 重新產生與逾時處理分開
session_regenerate_id() 會替換目前的工作階段識別碼;它不會測量閒置時間、不會銷毀工作階段資料,也不會自動要求使用者重新登入。請依應用程式的驗證流程,在適當時機將它用於識別碼輪替政策,並與逾時檢查分開處理。舊工作階段資料是否保留,取決於函式選項與工作階段處理方式,因此不要把重新產生識別碼本身視為登出,也不要據此認定先前的識別碼已無法使用。
session_id() 函式會讀取目前的識別碼,而 session_start() 會繼續使用與請求相關的工作階段。詳情請參閱 PHP 手冊中的 session_regenerate_id() 函式 和 session_id() 函式。