2

I have a php code as shown below in which session timeout happen after 60 mins when there is no activity. The following code is inside the file /mno.php. My login and logout code is also in the same file /mno.php.

/mno.php

if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 3600)) {
    session_destroy();   // destroy session data in storage
    !isset($_SESSION['pageadmin']);

    /* Update Table (START) */
    $open="false";
    $stmt= $connect->prepare("UPDATE trace_users SET open=? WHERE user_name=?");
    $stmt->bind_param('ss', $open, $_SESSION['user_name']);
    $stmt->execute();
    /* Update Table (END) */

    header('location: /mmo.php');
    exit();
}
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp 

The table trace_users in the code keeps the track of all logged in users. In that table, there are two columns user_name and open. The value is set to true/false when any user log in/log out.

I have included sql query in which I am trying to update a table when there is no activity but unfortunately the column value is not getting set to false for that particular user when no activity happens for 60 mins.

This is what I have tried:

After doing some research, I think I have to run a timer (js/ajax). In the javascript shown below I have calculated the difference between the Last Activity and the Current time. If its more than 60 mins, then it will update a db table. This is what I have tried but I believe more need to be done in order to update a table in db.

<script>
let x = setInterval(function() {

    let lastActivity = <?php echo ($_SESSION['LAST_ACTIVITY']); ?>
    let now = <?php echo time() ?>;
    let difference = now - lastActivity;

    if (difference > 3600) {
        clearInterval(x);
    }
}, 1000
);
</script>   

Problem Statement:

I am wondering what changes I should make in the js (or php) code above so that when there is no activity for 60 mins, it should update the column open to false (in the table trace_users) for that particular user.

enter image description here

Edit 1:

My login code and session history code is in the same file /mno.php. I have placed everything in the same file /mno.php.

user1950349
  • 4,738
  • 19
  • 67
  • 119

4 Answers4

2

I think Vineys and jo0gbe4bstjbs answer is wrong because of when user close browser until 5 seconds, it can't update table after 60 mins and session too. Session deletes just after time in where set in php.ini configuration file. And Do you mind requesting every 5 seconds is it good way to solve this? It is worst for performance. If you want solve this problem with professionalism, you should add "last_request" column and delete "open" column from the table and after every request you should update last_requests value to current unix timestamp. And where getting users you should write:

$time = time() - 3600;

"SELECT * FROM `users` WHERE last_request > $time" //active users
"SELECT * FROM `users` WHERE last_request <= $time" //inactive users

And instead of ajax request every 5 seconds you should write setTimeout with 3600 second delay time which run window.location.href= '/mmo.php'; code. Its way good if you want best performance and exactly result with 60 minute logout

Space Coding
  • 118
  • 6
  • Who told we are doing ajax EVERY 5 minutes? – Vinay Apr 21 '20 at 04:04
  • I'm sorry you wrote 'demo purposes'. But check every 1000 milliseconds too bad for browser. I think you should do setTimeout(function() { alert('you are logged out'); //DO AJAX REQUEST TO close.php } }, 3600000); – Space Coding Apr 21 '20 at 09:22
1

I suppose you realize that this code

if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 3600)) {
    //...
}
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp 

runs on every request and only when a request arrives

Imagine I visit your website and then go out shopping keeping the browser open. What do you think will happen? NOTHING - because there will be no new request sent to you (assuming you haven't implemented any periodic ajax polling / Websocket mechanism)

So the server won't bother about me until I come back from shopping and refresh the page, only then would the server realize "Hmmm..This guy's LAST_ACTIVITY is older than an hour let me update my trace_users table and set open as false for him"

Coming to your proposed solution, it looks good and avoids the complications of websockets/periodic ajax requests

Just need some minor corrections, follow here for a basic demo

<script>

    var lastActivity = <?php echo ($_SESSION['LAST_ACTIVITY']); ?>; //the timestamp of latest page refresh or navigation 
                                                                    //This will remain constant as long as page stays put
    var now = <?php echo time() ?>; //This takes inital value (technically same as LAST_ACTIVITY) from server 
                                    // but later on it will be incremented by javascript to act as counter
    var logoutAfter = 5; //I set 5 sec for demo purposes

    var timer = setInterval(function() {
                    now++;
                    let delta = now - lastActivity;
                    if ( delta > logoutAfter) {
                        alert('you are logged out');
                        clearInterval(timer);
                        //DO AJAX REQUEST TO close.php
                    }
                }, 1000);

</script> 

Here the lastActivity will hold the timestamp when the page was sent by server to browser it will be never changed by scripts on the browser, now is your counter that you will use to track how much time passed since page was loaded on the browser, you'll increment it every second and check if a given amount of time has been crossed

If true do a ajax request (or simply redirect to logout.php) where you would destroy session and update the trace_users table to mark the user as closed

UPDATE

So ajax will be like

$.ajax({      
    url: "/close.php", 
    type: 'POST', // GET also fine
    data: { },
    success: function(data) {
        window.location.href= '/mmo.php';
    },
    error: function(jqXHR, textStatus, errorThrown) {
        alert(textStatus);
    }
}); 

and

close.php

<?php
session_start();
$logoutAfter = 5; //5 sec timeout for testing purposes

// I'm not sure whether the below if condition check is required here or not 
// because we have already checked (whether to timeout or not ) in our javascript 
// and we call close.php only when it's affirmative
// I encourage you to test and find out :)

if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > $logoutAfter)) {
    session_destroy();   // destroy session data in storage
    !isset($_SESSION['pageadmin']);

    /* Update Table (START) */
    $open="false";
    $stmt= $connect->prepare("UPDATE trace_users SET open=? WHERE user_name=?");
    $stmt->bind_param('ss', $open, $_SESSION['user_name']);
    $stmt->execute();
    /* Update Table (END) */

    //header('location: /mmo.php'); //<-- no need of it when url hit by ajax
    exit();
}
else  //<-- note the else
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp 
Vinay
  • 7,442
  • 6
  • 25
  • 48
  • I checked your code and it looks good Viney thanks for the help. I am happy that my approach was right. Thanks for confirming that. According to your proposed solution when there is no activity for 5 seconds then the **(1)** page should log out automatically and bring the user to login.php (where I would destroy session) . **(2)** It should also update the table. – user1950349 Apr 19 '20 at 21:16
  • This is what I have tried https://jsfiddle.net/u68204ca/ I am wondering if you can have a look. In the fiddle, if you can let me know where I need to adjust the **update query** and the following 2 lines which is destroying session. `session_destroy(); // destroy session data in storage !isset($_SESSION['pageadmin']);` – user1950349 Apr 19 '20 at 21:21
  • Thanks for the update. I checked your code and wanted to let you know something. My login code and session history code is in the same file **/mmo.php**. I have placed everything in the same php file **/mmo.php**. I have tried with this code http://sandbox.onlinephpfunctions.com/code/a6aac316ad4a723db8fb2d217dfa437e19d9cbbc and its not working. I am getting the alert messages **you are logged out** and **error** – user1950349 Apr 20 '20 at 16:58
  • @user1950349 codesandbox is a limited environment you need to test on your local system. Use php's effortles inbuilt server `php -S localhost:8080` – Vinay Apr 20 '20 at 17:13
  • Hi, I have shared the sandbox link to show which code I am using in my local system. It would be very messy to copy/paste the code in comments. – user1950349 Apr 20 '20 at 17:15
  • I've updated the code. Have a look at [page.php](http://sandbox.onlinephpfunctions.com/code/3283715ed8abaa1595422f9b40de2daa091cd0bd ) and [mmo.php](http://sandbox.onlinephpfunctions.com/code/59831cd6fd346589f7e9ff0c2b417a4e51be8ab4) – Vinay Apr 21 '20 at 04:18
  • page.php and mno.php they both are different ? – user1950349 Apr 21 '20 at 04:22
  • I checked your page.php and mno.php and I can't see much changes. I am wondering where did you make changes in the above 2 files ? Let me know. – user1950349 Apr 21 '20 at 15:21
  • Seems some issue with sandbox anyway I've posted in a new answer – Vinay Apr 21 '20 at 16:16
  • I tested yoour code and everything is perfectly fine. The one thing which I noticed is that the page is getting log out even when there is an activity on the page. What does no activity actually means ? – user1950349 Apr 24 '20 at 02:53
  • It means any hit to the server whether it be through an AJAX or a simple page reload. That will update the `LAST_ACTIVITY` to "more amount" that will further extend the prospective logout. – Vinay Apr 24 '20 at 03:54
  • Thanks for letting me know. The other thing which I have noticed is when I am setting a session timeout for 60 mins (3600) then the db table was not getting updated but when I am setting a small session timeout lets say 60 seconds then the table gets updated after logout. – user1950349 Apr 25 '20 at 02:19
  • @user1950349 default session validity in php is 24 minutes, you need to increase it to atleast 61 minutes to have this code work. Check `session.gc_maxlifetime` in php.ini – Vinay Apr 25 '20 at 03:39
  • So it means if I remove the all the session code then the page will logout automatically after 24 mins ? – user1950349 Apr 25 '20 at 05:46
  • No not like anything do with auto-logout it merely is a prerequisite in order for sessions to work properly [more](https://stackoverflow.com/a/1270960) – Vinay Apr 25 '20 at 07:50
  • Thanks for letting me know Viney. I just checked php.ini file and the following values are set `session.gc_maxlifetime` **1440(Local Value)** **1440(Master Value)** – user1950349 Apr 25 '20 at 21:43
  • I am wondering why db table is not getting updated when I have setup the session timeout for 60 mins ? I also tried with 61 mins but still db table is not getting updated. – user1950349 Apr 26 '20 at 02:36
  • When I set something less than 60 seconds than the db table is getting updated. – user1950349 Apr 26 '20 at 04:11
  • Can you pls post all relevant code on github or something that supports separate files? – Vinay Apr 26 '20 at 04:46
  • I have put my php code here https://3v4l.org/cNSil and JS code here https://jsfiddle.net/4t1psdo0/ – user1950349 Apr 26 '20 at 05:08
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/212531/discussion-between-viney-and-user1950349). – Vinay Apr 26 '20 at 08:02
0

Page.php

<!-- CODE TO INCLUDE IN HEADER.PHP -->

<?php  
session_start();
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp  
?>



<!-- CLOSE -->

<html>

<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
</head>

<body>

</body>

<script>
let lastActivity = <?php echo ($_SESSION['LAST_ACTIVITY']); ?>; //the timestamp of latest page refresh or navigation
//This will remain constant as long as page stays put
let now = <?php echo time() ?>; //This takes inital value (technically same as LAST_ACTIVITY) from server+
                                // but later on it will be incremented by javascript to act as counter
let logoutAfter = 5; //I set 5 secs for demo purposes


let timer = setInterval(function() {
    now++;
    let delta = now - lastActivity;

    if ( delta > logoutAfter) {
        alert('you are logged out');
        clearInterval(timer);
        //DO AJAX REQUEST TO close.php
        $.ajax({
            url: "/mmo.php",
            type: 'POST', // GET also fine
            data: { },
            success: function(data) {

            },
            error: function(jqXHR, textStatus, errorThrown) {
                console.log("I am inside error");
                alert(textStatus);
            }
        });
    }
}, 1000); //<-- you can increse it( till <= logoutAfter ) for better performance as suggested by @"Space Coding"

</script>

</html>

mmo.php

<?php

$servername = "localhost";
$username   = "username";
$password   = "password";
$dbname     = "myDB";

$connect = new mysqli($servername, $username, $password, $dbname);

if ($connect->connect_error) {
    die("Connection failed: " . $connect->connect_error);
}

session_start();
$logoutAfter = 5; //5 sec timeout for testing purposes

if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > $logoutAfter)) {
    session_destroy();   // destroy session data in storage
    !isset($_SESSION['pageadmin']);

    /* Update Table (START) */
    $open="false";

    $stmt= $connect->prepare("UPDATE trace_users SET open=? WHERE user_name=?");
    $usname = !empty($_SESSION['user_name'])?$_SESSION['user_name']:'';

    $stmt->bind_param('ss', $open, $usname );
    $stmt->execute();
    /* Update Table (END) */

    //header('location: /mmo.php'); //<-- no need of it when url hit by ajax
    exit();
}
else  //<-- note the else
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp  
?>
Vinay
  • 7,442
  • 6
  • 25
  • 48
-1

This is a simple time validation for web page:

$modified_on = isset($SERVER['HTTP_IF_MODIFIED_SINCE']) ? $SERVER['HTTP_IF_MODIFIED_SINCE'] : null;

$current_time = time();

if (!is_null($modified_on) && ($current_time - strtotime($modified_on)) > 3600) {
    session_destroy();
    ...
}

header('Last-Modified: '.gmdate('D, d M Y H:i:s', $current_time).' GMT');

...
OO7
  • 660
  • 4
  • 10