session_regenerate_id

(PHP 4 >= 4.3.2, PHP 5, PHP 7, PHP 8)

session_regenerate_id 使用新生成的會話 ID 更新現(xiàn)有會話 ID

說明

session_regenerate_id(bool $delete_old_session = false): bool

session_regenerate_id() 在不修改當前會話中數(shù)據(jù)的前提下使用新的 ID 替換原有會話 ID。

如果啟用了 session.use_trans_sid 選項, 那么必須在調用 session_regenerate_id() 函數(shù)之后開始進行輸出工作, 否則會導致使用原有的會話 ID。

警告

當前的 session_regenerate_id 并沒有很好的處理在諸如移動數(shù)據(jù)網絡和 WiFi 網絡不穩(wěn)定的場景。 因此,調用 session_regenerate_id 函數(shù) 可能會導致會話丟失。

你不應該直接銷毀舊的會話所關聯(lián)的數(shù)據(jù), 而是應該使用時間戳機制來控制對于已經失效的會話 ID 的訪問。 否則,可能會在并發(fā)訪問的場景下導致會話數(shù)據(jù)不一致、 會話丟失等情況,甚至可能引發(fā)客戶端(瀏覽器)創(chuàng)建很多無用的會話 ID。 但是,另外一方面來講,立即刪除會話中的數(shù)據(jù) 可以防止會話劫持攻擊。

參數(shù)

delete_old_session

是否刪除原 ID 所關聯(lián)的會話存儲文件。 如果你需要避免會話并發(fā)訪問沖突,那么不應該立即刪除會話中的數(shù)據(jù)。 如果你需要防止會話劫持攻擊,那么可以立即刪除會話數(shù)據(jù)。

返回值

成功時返回 true, 或者在失敗時返回 false。

范例

示例 #1 A session_regenerate_id() 示例

<?php
// 注意:下列不是完整的代碼,只是一個示例

session_start();

// 檢查會話被銷毀的時間戳
if (isset($_SESSION['destroyed'])
    && 
$_SESSION['destroyed'] < time() - 300) {
    
// 通常不會發(fā)生這種情況。如果發(fā)生,那么可能是由于不穩(wěn)定的網絡狀況或者被攻擊導致的
    // 移除用戶會話中的認證信息
    
remove_all_authentication_flag_from_active_sessions($_SESSION['userid']);
    throw(new 
DestroyedSessionAccessException);
}

$old_sessionid session_id();

// 設置會話銷毀時間戳
$_SESSION['destroyed'] = time(); // 從 PHP 7.0.0 開始, session_regenerate_id() 會自動保存會話數(shù)據(jù)

// 如果直接調用 session_regenerate_id() 函數(shù)可能會導致會話丟失的情況,
// 參見下面的例程
session_regenerate_id();

// 新創(chuàng)建的會話不需要時間戳
unset($_SESSION['destroyed']);

$new_sessionid session_id();

echo 
"Old Session: $old_sessionid<br />";
echo 
"New Session: $new_sessionid<br />";

print_r($_SESSION);
?>

當前的會話模塊未能很好的處理在網絡不穩(wěn)定的時候導致會話丟失的場景。 你需要自行管理會話 ID 避免調用 session_regenerate_id 導致會話丟失。

示例 #2 Avoiding lost session by session_regenerate_id()

<?php
// 注意:下列不是完整的代碼,只是一個示例
// my_session_start() 和 my_session_regenerate_id()
// 函數(shù)可以避免在網絡不穩(wěn)定的情況下導致會話丟失的問題。
// 并且還可以避免用戶會話被攻擊者利用

function my_session_start() {
    
session_start();
    if (isset(
$_SESSION['destroyed'])) {
       if (
$_SESSION['destroyed'] < time()-300) {
           
// 通常不會發(fā)生這種情況。如果發(fā)生,那么可能是由于不穩(wěn)定的網絡狀況或者被攻擊導致的
           // 移除用戶會話中的認證信息
           
remove_all_authentication_flag_from_active_sessions($_SESSION['userid']);
           throw(new 
DestroyedSessionAccessException);
       }
       if (isset(
$_SESSION['new_session_id'])) {
           
// 尚未完全過期,可能是由于網絡不穩(wěn)定引起的。
           // 嘗試再次設置正確的會話 ID cookie。
           // 注意:如果你需要移除認證標記,那么不要嘗試再次設置會話 ID。
           
session_commit();
           
session_id($_SESSION['new_session_id']);
           
// 現(xiàn)在有了新的會話 ID 了。
           
session_start();
           return;
       }
   }
}

function 
my_session_regenerate_id() {
    
// 如果由于不穩(wěn)定的網絡導致沒有創(chuàng)建會話 ID,
    // 那么就創(chuàng)建一個
    
$new_session_id session_create_id();
    
$_SESSION['new_session_id'] = $new_session_id;
    
    
// 設置銷毀時間戳
    
$_SESSION['destroyed'] = time();
    
    
// 保存并關閉會話
    
session_commit();

    
// 使用新的會話 ID 開始會話
    
session_id($new_session_id);
    
ini_set('session.use_strict_mode'0);
    
session_start();
    
ini_set('session.use_strict_mode'1);
    
    
// 新的會話不需要這 2 個數(shù)據(jù)了
    
unset($_SESSION['destroyed']);
    unset(
$_SESSION['new_session_id']);
}
?>

參見