javascript - Inactive/browser close - change status to 0 and back to 1 when user returns

867

I am trying to get my website to set online users' status to 0 when they are inactive or close the browser. If they reopen the website or get back from idling (after timeout), I want the status to get back to 1 (unless they have been fully logged out due to long absence from the site)

Here is what I tried so far:

Inactive.php

include 'db.php';
mysql_query("UPDATE users SET status = 0 WHERE user_id = ".$_SESSION['user_id']."");

Check if browser closed

window.onbeforeunload = function() {
        $.ajax({
            url: 'inactive.php',
            type: 'GET',
            async: false,
            timeout: 4000
        });
    };

Check for idle timeout

var IDLE_TIMEOUT = 60; //seconds
var _idleSecondsCounter = 0;
document.onclick = function() {
    _idleSecondsCounter = 0;
};
document.onmousemove = function() {
    _idleSecondsCounter = 0;
};
document.onkeypress = function() {
    _idleSecondsCounter = 0;
};
window.setInterval(CheckIdleTime, 1000);

function CheckIdleTime() {
    _idleSecondsCounter++;
    var oPanel = document.getElementById("SecondsUntilExpire");
    if (oPanel)
        oPanel.innerHTML = (IDLE_TIMEOUT - _idleSecondsCounter) + "";
    if (_idleSecondsCounter >= IDLE_TIMEOUT) {
        alert("Time expired!");
        document.location.href = "inactive.php";
    }
}

My query doesn't seem to work. How can I tell it which user to check every x seconds?

611

Answer

Solution:

Thewindow.onbeforeunload is going to produce a race condition and won't be very reliable. Also you would want to usewindow.addEventListener('beforeunload', function () {...}); instead

Thealert inCheckIdleTime will halt execution of thejavascript, so the user will have to interact (clickOK) to log out. Otherwise that approach seems fine.

Now for when a user leaves the page, generally you would set your cookies to expire on leaving the site, but it seems you want to have a running tally in your website of the active users.

For that you would probably want a two step approach, actively setting flags and timestamp for "last active." And also running a garbage collection script that sets user to "inactive" if you have not seen any activity from them in a bit.

In the event that you needed truely realtime logs of active users, you might be want to look intoNode.js in particularSocket.IO which can deal much better with real time client-server IO.

Its likely far easier to run a query that updates the users to say that they are in fact active

 <script>
 setInterval(function () {
      $.post('active.php');
 }, 
 15000 // every 15 seconds
 );
 </script>

in active.php (assuming you add a newlast_activeDATETIME, anduser_id is an int:

 mysql_query("UPDATE users SET status = 1, `last_active` = NOW() WHERE user_id = ". (int)$_SESSION['user_id']."");
 mysql_query("UPDATE users SET status = 0 WHERE `status` = 1 AND `last_active` < DATE_SUB(NOW(), INTERVAL 15 SECOND)"); // set all in active who have  not pinged in the last 15 seconds

Here might be how the schema looks

 CREATE TABLE `users`
    `id` IN NOT NULL,
    `status` INT(1) DEFAULT 0,
    `last_active` DATETIME
 );

you likely want to play around a bit with that "inactive" interval, and consider creating an index.

116

Answer

Solution:

Revised code

This code will make reference to the example I wrote available here >> jquery-idle with jquery-ui Dialog

Libraries used :

Embedded Library Example:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="http://thorst.github.io/jquery-idletimer/prod//src/idle-timer.js"></script>
<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/themes/smoothness/jquery-ui.css" />
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>

Without jQuery dialog :

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="http://thorst.github.io/jquery-idletimer/prod//src/idle-timer.js"></script>

Please keep in mind that you may switch out the dialog code with whatever your prefered dialog method is. I included jquery-ui for dialog to keep things as simple as possible. This also does not handle thebeforeunload event, as you have that covered in your code, however I would suggest read further here >> beforeunload stackoverflow article <<

Explanation

HTML


This line of code is for the placeholder where the countdown timer will be stored. To simplify things, I also use this when the timer has expired to display "Session Expired"

<div id="sessionSecondsRemaining" class="page_speed_755981839"></div>

This is a very simple Modal dialog using jQuery UI. You can expand on it or replace it at your leisure.

<div id="dialog-confirm" title="Logout" >
<p><span >Your session has expired.</span></p>
</div>

Without jQuery Dialog

<div id="sessionSecondsRemaining" class="page_speed_1429257054"></div>

CSS


This is just a small hack due to a bug in the grayed background not displaying properly for jQuery UI modal dialogs (why has this not been fixed yet -- facepalm )

/* override jquery ui overlay style */
.ui-widget-overlay {
   background-image: none !important; /* FF fix */
   background: #000 url(images/new-ui-overlay.png) 50% 50% repeat-x;
}

Without jQuery Dialog

  • No CSS needed

Javascript


This section is where you can configure the parameters for jquery-idletimer.

        var
            session = {
                //Logout Settings
                inactiveTimeout: 10000,     //(ms) The time until we display a warning message
                warningTimeout: 10000,      //(ms) The time until we log them out
                minWarning: 5000,           //(ms) If they come back to page (on mobile), The minumum amount, before we just log them out
                warningStart: null,         //Date time the warning was started
                warningTimer: null,         //Timer running every second to countdown to logout
                logout: function () {       //Logout function once warningTimeout has expired
                    //window.location = settings.autologout.logouturl;
                },

                //Keepalive Settings
                keepaliveTimer: null,
                keepaliveUrl: "",   // set the Keep Alive URL here (aka keepalive.php)
                keepaliveInterval: 5000,     //(ms) the interval to call said url
                keepAlive: function () {
                    $.ajax({ url: session.keepaliveUrl });
                }
            }
        ;

To add 'keepalive.php' support, simply set the full URL for where keepalive.php is located (and any parameters you wish to pass, since you are using sessions, you shouldn't need any).

                keepaliveUrl: "http://example.com/keepalive.php",   // set the Keep Alive URL here (aka keepalive.php)

This line, initializes and sets the value in the #sessionSecondsRemaining div.

                $('#sessionSecondsRemaining').html(Math.round((session.warningTimeout - diff) / 1000));

This section is where you would put the code that controls your dialog warning the user of a session expiration countdown (usually #sessionSecondsRemaining would be in this dialog)

                $( "#dialog-confirm" ).dialog({
                    resizable: false,
                    height:140,
                    modal: true,
                    buttons: {
                        "Extend": function() {
                            clearTimeout(session.warningTimer);
                            $( this ).dialog( "close" );
                        },
                        Cancel: function() {
                            session.logout();
                            $( this ).dialog( "close" );
                        }
                    }
                });

Without jQuery Dialog

  • Remove the last block

If you notice, 'Extend', terminates the warning timer, and Cancel calls the logout function (also configurable above)

Lastly, this block is very important to what happens in the event the timer counts down to zero, and for controlling the display of the countdown inside #sessionSecondsRemaining

                    if (remaining >= 0) {
                        $('#sessionSecondsRemaining').html(remaining);
                    } else {
                        $( '#dialog-confirm' ).dialog( "close" );
                        clearInterval(session.warningTimer);
                        $( '#sessionSecondsRemaining' ).html('Session Expired');
                        session.logout();
                    }

Under theelse, is probably the only spot you will really need to modify in the above block. In there, I call thesession.logout() function (should really be the last line after dialogs are cleaned up, but this is just a demo). This is where you close the dialogs, and/or redirect the user to the session expired page, or display the message. If staying on the same page, make sure toclearInterval(session.warningTimer);. If not, then that line does not matter.

Without jQuery Dialog

                    if (remaining >= 0) {
                        $('#sessionSecondsRemaining').html(remaining);
                    } else {
                        clearInterval(session.warningTimer);
                        session.logout();
                    }

keepalive.php

if (session_status() !== PHP_SESSION_ACTIVE) { session_start(); }
include 'db.php';
$maxtimeout = 15; // Seconds for max timeout before forcing session reset on other users.
mysql_query("UPDATE users SET status = 1 WHERE user_id = ".$_SESSION['user_id']."");
mysql_query("UPDATE users SET status = 0 WHERE user_id <> ".$_SESSION['user_id']." AND (UNIX_TIMESTAMP() - UNIX_TIMESTAMP(`timestamp_field`)) > " . $maxtimeout . "";

This task should be set to run server-side to cleanup the database from any strays (if you have a lot of activity, then you won't need this script)

cron.php

include 'db.php';
// Set this for a longer timeout than in keepalive.php
$maxtimeout = 90; // Seconds for max timeout before forcing session reset on other users.
mysql_query("UPDATE users SET status = 0 WHERE (UNIX_TIMESTAMP() - UNIX_TIMESTAMP(`timestamp_field`)) > " . $maxtimeout . "";
862

Answer

Solution:

This is what I am apply at my system to keep track user still online. I make the client site ping back every minute telling the DB he still online.

About the detect browser close you can check out this Close/kill the session when the browser or tab is closed by Daniel Melo

<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
</head>
<body>
<script type="text/javascript">
var timeLeft = Number(60);

setInterval(function(){
    timeLeft--;
    if(timeLeft<0){
        expiredLogout();
    }
    $("#timer").html(timeLeft);
    //If timer less than 30, show message to user will logout soon
    if(timeLeft<30){
        $("#logoutMsg").show( "slow" );
    }else{
        $("#logoutMsg").hide( "slow" );
    }
    $("#logoutMsg").html('You will logout soon, in '+timeLeft+' sec.');
},1000);
//Initial Function
$(function() {
    //Mouse move top up the time left value;
    $(document).mousemove(function(event) {
        timeLeft = Number(60);
    });
    stillAlive();
    //Every 1 minute ping the active.php
    setInterval(function(){ stillAlive();},60000);
});
//Redirect to other page if time out 
function expiredLogout(){
    window.location = "inactive.php";
};
function stillAlive(){
    //Update userID 1 still active
    var postVal = {userID:1};
    $.post("active.php", postVal, null, "json")
    .success(function(data) {})
    .error(function() {})
    .complete(function() {});
};
</script>
<label id="timer"></label>
<div id="logoutMsg"></div>
</body>
</html>

Demo

388

Answer

Solution:

The first question would be how you define "idle". What terminates an "idle" period? Bringing the focus to the browser window? Scrolling the page? Clicking on the page? Clicking a button? Clicking a link? - The latter seems to be the approach most sites use, and this can be done on the server side alone: If the user did not open another page on your site for, say, 5 minutes, then he is considered idle. After 15 minutes he is logged out by the system.

People are also looking for solutions to the problem: php - I want to put register page link in magento subcategory

Source

Didn't find the answer?

Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.

Ask a Question

Write quick answer

Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.

Similar questions

Find the answer in similar questions on our website.