skip to Main Content

I followed a tutorial and no matter how many times I check this code, I can’t get it to work long term. Upon login the session starts,but after the set interval time when it should reset (60* 30), the session gets destroyed and the user is logged out.

I’ve shortened the time to test this, setting the time to 60 * 3 and continuously refreshing the page every 30 seconds.

The session also died after 3 minutes, despite that page being the only one refreshed and the require being at the top of the page (require_once 'includes/config_session.inc.php';)

How can I prevent the session from dying and keep the user logged in after using session_regenerate_id(true)?

Here is the code for my 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();
}

2

Answers


  1. This is due to the PHP’s session COOKIE not being refreshed upon each request or when we are calling the session_start function.

    The session COOKIE is being created once when we first call the session_start and then it is left as is.

    The logic behind this is that by default the session.cookie_lifetime param has a value of 0, meaning "until the browser is closed."
    see: PHP docs > Session configuration.

    You can also read the following bug report which describes exactly this "issue". One key point to keep from the comments there, is that if session cookie is not cleared upon browser closer (or session end), when a user, same or worse another one, reopens the browser on the same page, it will have kept the session!

    Having said that, you can manually update the session COOKIE when needed. In your sample code that would be in the regenerate_session_id_loggedin() function since, you want to keep session for logged-in users.

    So you can add the following at the end of the function:

    /**
     * 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
        );
    }
    
    

    That should fix the timeout problem.


    As a side note (irrelevant to the timeout), from the docs for the session_regenerate_id, you may also need to change your logic for creating a custom session ID. There is an example in the docs page above that suggest the following steps:

    1. Save and close current session via session_commit()
    2. Set new session ID via session_id('YOUR_CUSTOM_ID')
    3. Disable use_strict_mode
    4. Start session via session_start(), which will have the newly defined ID.
    5. Enable use_strict_mode

    like so:

    // 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.
    
    

    Also note, that you call session_regenerate_id which renews the session ID and then you create and assign a new one.
    Furthermore, the session_regenerate_id is being called for all users regardless of their logged-in status, which is something you may or may not want.


    And a second note (this too is irrelevant to the timeout): You can make some refactoring to your code in order to not repeat some logic. e.g.:

    <?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();
    }
    
    
    Login or Signup to reply.
  2. Use session_write_close() Before session_regenerate_id(true):
    After regenerating the session ID, it’s a good practice to call session_write_close() before continuing with the script. This ensures that the session data is written and closed before the new ID is generated. For example:

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

    or

    Check session.gc_maxlifetime Configuration:
    Ensure that the PHP configuration setting session.gc_maxlifetime is set to a value equal to or greater than the session lifetime you’ve specified. This setting defines the number of seconds after which data will be seen as ‘garbage’ and potentially cleaned up.

    session.gc_maxlifetime = 1800
    

    at the end . please ensure that session_start() is called at the very beginning of each page before any output is sent to the browser. If there is any output or whitespace before the session starts, it can cause issues.

    <?php
    session_start();
    require_once 'includes/your_config.inc.php';
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search