会话在使用 session_regenerate_id 后死亡(true)

Session dying after using session_regenerate_id(true)

提问人:Megan Caza 提问时间:11/7/2023 最后编辑:Salman AMegan Caza 更新时间:11/21/2023 访问量:151

问:

我遵循了一个教程,无论我检查多少次此代码,我都无法让它长期工作。登录后,会话开始,但在应重置的设置间隔时间()后,会话将被销毁,用户注销。60* 30

我缩短了测试时间,将时间设置为每 30 秒刷新一次页面。60 * 3

该会话也在 3 分钟后死亡,尽管该页面是唯一刷新的页面,并且要求位于页面顶部(require_once 'includes/config_session.inc.php';)

如何防止会话死亡并在使用后保持用户登录状态?session_regenerate_id(true)

这是我的 config_session.inc 的代码.php

<?php

ini_set('session.use_only_cookies', 1);
ini_set('session.use_strict_mode', 1);

session_set_cookie_params([
   'lifetime' => 1800, 
    'domain' => 'www.snoozelings.com',
    'path' => '/',
    'secure' => true,
    'httponly' => true
]);

session_start();

if (isset($_SESSION["user_id"])) {
    if (!isset($_SESSION['last_regeneration'])) {
        regenerate_session_id_loggedin();
    } else {
        $interval = 60 * 30;
        if (time() - $_SESSION['last_regeneration'] >= $interval) {
            regenerate_session_id_loggedin();
        }
    }
} else {
    if (!isset($_SESSION['last_regeneration'])) {
        regenerate_session_id();
    } else {
        $interval = 60 * 30;
        if (time() - $_SESSION['last_regeneration'] >= $interval) {
            regenerate_session_id();
        }
    }
}
function regenerate_session_id() {
    session_regenerate_id(true);
    $_SESSION['last_regeneration'] = time();
}

function regenerate_session_id_loggedin() {
    session_regenerate_id(true);
    
    $userID = $_SESSION["user_id"];
    
    $newSessionId = session_create_id();
    $sessionId = $newSessionId . "_" . $userID;
    session_id($sessionId);
    
    $_SESSION['last_regeneration'] = time();
}
PHP 会话 Cookie

评论

0赞 DarkBee 11/7/2023
这回答了你的问题吗?如何在PHP中更改会话超时?
0赞 Megan Caza 11/7/2023
不。我可以延长间隔,使会话持续更长时间。这不是问题所在。问题是 30 分钟后它应该进行一个新的会话,但事实并非如此。它只是在没有创建新会话的情况下死去。
0赞 DarkBee 11/7/2023
默认的最长生存期为 24 分钟(可在运行时验证)。如果您无法增加限制,我建议将设置从 30 降低到 20<?php phpinfo();
0赞 Megan Caza 11/7/2023
就像我说的,我尝试将其设置为仅 3 分钟,但问题仍然存在。
0赞 DarkBee 11/7/2023
您是否在移动网络或 WiFi 上对此进行了测试?参考

答:

2赞 Cubakos 11/17/2023 #1

这是由于 PHP 的会话 COOKIE 在每次请求时或当我们调用函数时没有刷新。session_start

当我们第一次调用会话 时,会话 COOKIE 被创建一次,然后保持原样。session_start

这背后的逻辑是,默认情况下,param 的值为 ,这意味着请参阅:PHP 文档>会话配置session.cookie_lifetime0"until the browser is closed."

您还可以阅读以下错误报告,其中确切地描述了此“问题”。要注意的一个关键点是,如果在浏览器关闭(或会话结束)时未清除会话 cookie,则当用户(相同或更糟)在同一页面上重新打开浏览器时,它将保留会话!

话虽如此,您可以在需要时手动更新会话 COOKIE。在函数中的示例代码中,您希望为登录用户保留会话。regenerate_session_id_loggedin()

因此,您可以在函数末尾添加以下内容:

/**
 * Renew the time left until this session times out.
 * If we do not do this, the session will time out based on the 
 * time when it was created rather than when it was last used.
 * @see https://www.php.net/manual/en/function.session-set-cookie-params.php#100657
 */
if(isset($_COOKIE[session_name()])) {
    setcookie(
        session_name(),
        session_id(),
        time() + (60 * 30),
       '/',
        'www.snoozelings.com',
        true,
        true
    );
}

这应该可以解决超时问题。


作为旁注(与超时无关),在session_regenerate_id的文档中,您可能还需要更改创建自定义会话 ID 的逻辑。上面的文档页面中有一个示例,建议执行以下步骤:

  1. 通过以下方式保存并关闭当前会话session_commit()
  2. 通过以下方式设置新的会话 IDsession_id('YOUR_CUSTOM_ID')
  3. 禁用use_strict_mode
  4. 通过 启动会话,该会话将具有新定义的 ID。session_start()
  5. 使use_strict_mode

这样:

// inside of your regenerate_session_id_loggedin
$newSessionId = session_create_id();

// Customize session ID for current USER.
$sessionId = $newSessionId . "_" . $userID;

// Write and close current session;
session_commit();

// Start session with new session ID
session_id($sessionId);
ini_set('session.use_strict_mode', 0);
session_start();
ini_set('session.use_strict_mode', 1);
// ... rest of your code.

另请注意,调用 which 续订会话 ID,然后创建并分配一个新 ID。 此外,无论其登录状态如何,都会为所有用户调用 the,这是您可能想要也可能不希望看到的。session_regenerate_idsession_regenerate_id


第二点(这也与超时无关):你可以对代码进行一些重构,以免重复某些逻辑。例如:

<?php

ini_set('session.use_only_cookies', 1);
ini_set('session.use_strict_mode', 1);

// Init Session config vars.
$sessionCookieLifetime = 60 * 30;

$mySessionCookieParams = [
    'lifetime' => $sessionCookieLifetime, 
    'domain' => 'www.snoozelings.com',
    'path' => '/',
    'secure' => true,
    'httponly' => true
];

session_set_cookie_params($mySessionCookieParams);

session_start();

if ( ! isset($_SESSION['last_regeneration']) ) {
    regenerateSessionByUserStatus();
} else {
    if (time() - $_SESSION['last_regeneration'] >= $sessionCookieLifetime) {
        regenerateSessionByUserStatus();
    }
}

function regenerateSessionByUserStatus() {
    session_regenerate_id(true);
    
    if (isset($_SESSION["user_id"])) {
        $userID = $_SESSION["user_id"];

        $newSessionId = session_create_id();
        $sessionId = $newSessionId . "_" . $userID;
        session_id($sessionId);

        /**
         * Renew the time left until this session times out.
         * If we do not do this, the session will time out based on the 
         * time when it was created rather than when it was last used.
         * @see https://www.php.net/manual/en/function.session-set-cookie-params.php#100657
         */
        if(isset($_COOKIE[session_name()])) {
            setcookie(
                session_name(), 
                session_id(), 
                time() + $sessionCookieLifetime, 
                $mySessionCookieParams['path'], 
                $mySessionCookieParams['domain'], 
                $mySessionCookieParams['secure'], 
                $mySessionCookieParams['httponly']
            );
        }
    }

    $_SESSION['last_regeneration'] = time();
}