php - 使用 session_regenerate_id(true) 后 session 终止

标签 php session-cookies

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

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

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

使用 session_regenerate_id(true) 后如何防止 session 终止并保持用户登录状态?

这是我的 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 的 session COOKIE 没有在每次请求时或我们调用 session_start 时刷新。功能。

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

这背后的逻辑是默认情况下session.cookie_lifetime参数的值为 0 ,意思是"until the browser is closed." see: PHP docs > Session configuration .

您还可以阅读以下bug report它准确地描述了这个“问题”。注释中需要注意的一个关键点是,如果在浏览器关闭(或 session 结束)时未清除 session cookie,则当用户(相同或更差的另一个用户)在同一页面上重新打开浏览器时,它将保留 session !

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

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

/**
 * 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 的文档,您可能还需要更改创建自定义 session ID 的逻辑。上面的文档页面中有一个示例,建议执行以下步骤:

  1. 通过 session_commit() 保存并关闭当前 session
  2. 通过 session_id('YOUR_CUSTOM_ID') 设置新的 session ID
  3. 禁用use_strict_mode
  4. 通过 session_start() 开始 session ,它将具有新定义的 ID。
  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.

另请注意,您调用 session_regenerate_id这会更新 session ID,然后您创建并分配一个新 session ID。 此外,session_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();
}

关于php - 使用 session_regenerate_id(true) 后 session 终止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77435811/

相关文章:

php - 使用 die() 时 SQL 语句中的结果数量不同

PHP OOP PDO 错误显示

php - 将负数变为 0 的默认 php 函数

internet-explorer - Zend Framework - Internet Explorer - phpsessid cookie 问题

authentication - 基于 cookie 的 session /身份验证的替代方案

php - 处理 Facebook 异常

php - jQuery 自动完成结果应显示为组合框

java - 如果我 setMaxAge(-1),持久跟踪器 cookie 是否会变成 session cookie

javascript - 与第三方网站共享 session cookie 的最佳方式是什么?

php - 使用 session 创建多页 PHP 表单