3
votes

As stated in the title, db table trace_users is not getting updated when no activity happens for 30 mins but its get updated when its 6 mins.

The following code (both JS and PHP) is inside the same php file mno.php.

I am storing the last activity of user through this line let lastActivity = <?php echo time(); ?> ; present in the script below.

<?php
session_start();     
if (isset($_GET['action']) && $_GET['action'] == "logout")
{
    session_destroy(); // destroy session data in storage
    !isset($_SESSION['admin']);
    $open = "false";
    $write = "0";
    $stmt = $connect->prepare("UPDATE trace_users SET open=?, write=? WHERE user_name=?");
    $usname = !empty($_SESSION['user_name']) ? $_SESSION['user_name'] : '';
    $stmt->bind_param('sss', $open, $write, $usname);
    $stmt->execute();
}
?>
<script>
    jQuery(document).ready(function($) {

        let lastActivity = <?php echo time(); ?> ;  // storing last activity of user

        let now = <?php echo time(); ?> ;

        let logoutAfter = 360;

        let timer = setInterval(function() {
            now++;
            let delta = now - lastActivity;
            console.log(delta);
            if (delta > logoutAfter) {
                clearInterval(timer);
                //DO AJAX REQUEST TO close.php
                $.ajax({
                    url: "/abc/mno.php",
                    type: 'GET',
                    data: {
                        action: 'logout'
                    }, // Line A
                    success: function(data) {
                        console.log(data); // Line B
                    },
                    error: function(jqXHR, textStatus, errorThrown) {
                        alert(textStatus);
                    }
                });
            }
        }, 1000);
    }); 
</script>

Problem Statement:

I am wondering what changes I should make in the code above so that when no activity happens for 30 mins (1800 seconds) then the db table should also get updated.

Case1 (Not Working) : 1800 seconds (page logs out, db doesn't update)
Case2 (Working) : 360 seconds (page logs out, db gets updated)

The values inside session.gc_maxlifetime are 1440(Local Value) 1440(Master Value)

This is what I have tried/debugged:

On the network tab, I am getting Request Method GET when session timeout is set 6 mins and 60 mins.

4
Session by default will be destroyed after 20 minutes automatically, it works for 6 min since there is a session it doesn’t for 30.estinamir
@bestinamir My above code works perfectly fine. When I have setup the session timeout for 30 mins (1800 seconds), the only thing which it doesn't do that it doesn't update the table, it do logs out.user1950349
I changed the value from 30 mins to 6 mins and saw its working for 6 mins. When I am setting 6 mins, I am getting a GET (200) request on network tab. That is what I have trieduser1950349
When I am setting 60 mins, I am getting same GET (200) request on the network tab.user1950349
While editing your question is encouraged, please try to "chunk" or "batch" your edits to reduce the amount of noise. You have recently made a very large number of edits in a very short period of time.Cody Gray

4 Answers

2
votes

You need to pass to the javascript some sort of permanent UID that identifies the user even after the session expires.

For the sake of simplification, I'm using user_name that already exists in your code. But you can also assign an UUID for each user, so that one can't guess another user's name and can't modify their stats.


First, you'll pass the $_SESSION['user_name'] from PHP to the JS closure.

let userName = "<?php echo $_SESSION['user_name']; ?>";  // don't forget to wrap the JS string value in quotes or apostrophes

Then, you'll pass it in the AJAX request payload.

data: {
    action: 'logout',
    user_name: userName  // added param
},

Finally, you'll overwrite the value that is sent to DB (if it's sent with the payload)

$usname = !empty($_SESSION['user_name']) ? $_SESSION['user_name'] : '';  // original line
if (isset($_GET['user_name']) && !empty($_GET['user_name'])) {
    $usname = $_GET['user_name'];
}
$stmt->bind_param('sss', $open, $write, $usname);  // original line

Complete updated code:

<?php
if (isset($_GET['action']) && $_GET['action'] == "logout")
{
    session_destroy(); // destroy session data in storage
    !isset($_SESSION['pageadmin']);
    $open = "false";
    $write = "0";
    $stmt = $connect->prepare("UPDATE trace_users SET open=?, write=? WHERE user_name=?");
    $usname = !empty($_SESSION['user_name']) ? $_SESSION['user_name'] : '';
    if (isset($_GET['user_name']) && !empty($_GET['user_name'])) {
        $usname = $_GET['user_name'];
    }
    $stmt->bind_param('sss', $open, $write, $usname);
    $stmt->execute();
}
?>
<script>
    jQuery(document).ready(function($) {

        let lastActivity = <?php echo time(); ?> ;  // storing last activity of user

        let now = <?php echo time(); ?> ;

        let logoutAfter = 10;

        let userName = "<?php echo $_SESSION['user_name']; ?>";

        let timer = setInterval(function() {
            now++;
            let delta = now - lastActivity;
            console.log(delta);
            if (delta > logoutAfter) {
                clearInterval(timer);
                //DO AJAX REQUEST TO close.php
                $.ajax({
                    url: "/abc/mno.php",
                    type: 'GET',
                    data: {
                        action: 'logout',
                        user_name: userName
                    }, // Line A
                    success: function(data) {
                        console.log(data); // Line B
                    },
                    error: function(jqXHR, textStatus, errorThrown) {
                        alert(textStatus);
                    }
                });
            }
        }, 1000);
    }); 
</script>

Few notes at the end:

  • It's bad practice to combine PHP, HTML and JS altogether in one file.
  • There are some parts of your code that are not easily reproducible and I had to guess from the context (e.g. i guessed that the session is already set, jQuery is used but there's no <script src="...jquery.js">, there's a DB query but no separate SQL import to try it quickly). Please read and apply the knowledge from How to create a Minimal, Reproducible Example in your next question, so that more people are able or willing to help you with it.
1
votes

The problem is that you are not changing anything that will prevent the session from expiring after N seconds, you are just coding your script in a way that it will destroy the session after this time. The session gc (garbage colector) executes periodically and deletes old sessions and when that happens, $_SESSION['LAST_ACTIVITY'] will be deleted as well.

You must either try to prevent the gc from deleting sessions or change the logic in your application.

1
votes

PHP process does not sit indefinitely and does not have program structure as a loop ala Node.js server, which won’t allow you to react to session expiry since it’s not a process that invalidates it, but rather a simple timestamp associated with session that is checked every time you attempt to work with it.

The solution I offer is a simple script that is ran every N minutes to perform a comparison of last user activity timestamp (which, I assume is updated on the request for that user) against expiry period (in you case it is 30 minutes). You can also set session expiry to 30 minutes, though strictly it’s not necessary. If the time difference will exceed 30 minutes, you update the timestamp for the user in your table, and invalidate their session if necessary. The script can be ran through cron or its alternatives and go through all users you require to perform a check.

Do not forget to handle the case when user is logged out on the server but client does not know about it and may continue sending logout requests - raising alert box is rather unclear (it is better to return HTTP Unauthorized code and handle it differently - redirecting to login screen, for example)

0
votes

There are two things you need to fix.

1). Set the ajax request to be async:false.

$.ajax({
    url: "/abc/mno.php",
      type: 'GET',
      async: false,   //  <---- ADDED ASYNC FALSE
      data: {
        action: 'logout'
    }, // Line A
     success: function(data) {
        console.log(data); // Line B
      },
     error: function(jqXHR, textStatus, errorThrown) {
         alert(textStatus);
       }
 });

2). Destroy the session after performing the SQL Query.

<?php
session_start();     
if (isset($_GET['action']) && $_GET['action'] == "logout")
{
    !isset($_SESSION['pageadmin']);
    $open = "false";
    $write = "0";
    $stmt = $connect->prepare("UPDATE trace_users SET open=?, write=? WHERE user_name=?");
    $usname = !empty($_SESSION['user_name']) ? $_SESSION['user_name'] : '';
    $stmt->bind_param('sss', $open, $write, $usname);
    $stmt->execute();
    session_destroy(); // destroy session data in storage <---- DESTORY AT THE END
}
?>