How to check idle time using jQuery and PHP? - javascript

I have a script that uses PHP SESSION. I manage PHP sessions using a class. Within this class I have a method that returns how many seconds remaining before the session expires.
Also, Evey time the user refresh the page or open a new page (new request to the server) the idle time counter starts over $_SESSION['MA_IDLE_TIMEOUT'] = time()+900;
What I am looking to do is display a dialog message 2 minutes before the PHP session expire and check if the user is still on the page or not. If the use clicks "Keep working" then the jQuery script will send PHP AJAX request to renew the session $_SESSION['MA_IDLE_TIMEOUT'] = time()+900;. If the user did not click anything or clicked on "Log out" then the session ends and the user is redirected to the login page.
I did find a nice plugin that will somewhat does the Job jquery-idle-timeout
The issue with this plugin is that it checks if the user is idle using JavaScript (if the keyboard/mouse) are being used. Here is the senario where this script does not help me: lets say my PHP sessions has a limit on 15 minutes/ 900 seconds. A user is reading a super long article on the same page. He/she will be scrolling, they are not really idle "from JavaScript perspective" but from a PHP perspective the use is idle. Then after 20 minutes the user refresh the page, then the user will be logged out since he/she have not sent a new request to the PHP server for over the 900 seconds limit.
How can I solve this problem? is there a better plugin to does the trick? if there something I missed in this plugin that will solve my problem?
Thanks

If the user is not making requests, and is not moving the mouse or keyboard or touching the device, etc., then from the app's point of view the user is "idle" even if their eyeballs are not.
If the user is scrolling you can use javascript to listen for scroll events (via onscroll, for example), but this will not be 100% reliable because (1) depends on javascript, and (2) doesn't work if you are viewing a short article or using a tall/large format monitor (like the ones you can rotate 90 degrees, for example).
Perhaps you could handle this differently: use cookies, single sign-on or similar techniques to pre-authenticate or automatically authenticate requests so that the user's session can safely die and be restarted without the user having to manually login.
The other way you could handle this is to maintain a "ping" process that routinely pings the server (via setInterval(), for example) to keep the session alive, and uses a separate timeout (maybe something like the "Authentication timeout" that ASP.NET uses) to keep track of when the "idle" user should be logged out. Then user actions such as scrolling, requesting pages, focusing in fields, moving mouse, etc., can do a "ping reset" that resets the idle counter to 0.
Example / Concept - leaving as exercise for reader to perfect it:
var idleTime = 0; // how long user is idle
var idleTimeout = 1000 * 60 * 20; // logout if user is idle for 20 mins
var pingFrequency = 1000 * 60; // ping every 60 seconds
var warningTime = 1000 * 60 * 2; // warning at 2 mins left
var warningVisible = false; // whether user has been warned
setInterval(SendPing, pingFrequency);
setInterval(IdleCounter, 1000); // fire every second
function IdleCounter() {
idleTime += 1000; // update idleTime (possible logic flaws here; untested example)
if (console) console.log("Idle time incremented. Now = " + idleTime.toString());
}
function SendPing() {
if (idleTime < idleTimeout) {
// keep pinging
var pingUrl = "tools/keepSessionAlive.php?idleTime=" + idleTime;
$.ajax({
url: pingUrl,
success: function () {
if (console) console.log("Ping response received");
},
error: function () {
if (console) console.log("Ping response error");
}
});
// if 2 mins left, could show a warning with "Keep me on" button
if ((idleTime <= (idleTimeout - (idleTimeout - warningTime))) && !warningVisible) {
ShowTimeoutWarning();
}
} else {
// user idle too long, kick 'em out!
if (console) console.log("Idle timeout reached, logging user out..");
alert("You will be logged off now dude");
window.location.href = "logoff.aspx"; // redirect to "bye" page that kills session
}
}
function ShowTimeoutWarning() {
// use jQuery UI dialog or something fun for the warning
// when user clicks OK set warningVisible = false, and idleTime = 0
if (console) console.log("User was warned of impending logoff");
}
function ResetIdleTime() {
// user did something; reset idle counter
idleTime = 0;
if (console) console.log("Idle time reset to 0");
}
$(document) // various events that can reset idle time
.on("mousemove", ResetIdleTime)
.on("click", ResetIdleTime)
.on("keydown", ResetIdleTime)
.children("body")
.on("scroll", ResetIdleTime);

I use a time cookie to log out an inactive user like this:
`$time = time();
// 5 minutes since last request
if(!empty($_COOKIE['_time'] && $time - $_COOKIE['_time'] >= 300)
{
// log user out
}
setcookie('_time', $time, '/');`
Hope this helps.

Related

Run notification script only once, even though script runs on multiple tabs

I use the following code inside a Tampermonkey script.
function scriptMain () {
setTimeout(function(){
GM_notification ( {
title: 'Refresh Business Manager', text: 'Your about to be logged out of staging, click here to refresh your login.', image: 'https://i.stack.imgur.com/geLPT.png',
onclick: () => {
console.log ("My notice was clicked.");
location.reload();
}
} );
}, 5*1000);
console.log ("Script main code ran.");
}
The code shows a notification whenever a browser tab is open for more than 5 seconds which includes a button to refresh the current browser tab. I wanna use this script to alert me every 20 minutes or so, that one of the logins in the browser is about to auto-logout.
The functionality works as expected, but if I have 5 tabs open from the site where im logged in, I will get 5 notifications when the page is about to run out. I would love to be able to tell from within the Tampermonkey script if this script is already running on another tab, to not execute or to maybe just be able to only show the notification once.
I have been looking into the Tampermonkey documentation for the following Grants:
GM_getTab(callback)
GM_saveTab(tab)
GM_getTabs(callback)
But I dont seem to be able to work out if this functionality would be possible or not.
Can someone help me shine some light on this topic, or perhaps share a solution?
On modern spec-compliant browsers, you can use BroadcastChannel inside the userscript to communicate with other tabs on the same domain. Make the timeout slightly random - add or subtract a few seconds to allow for all the open tabs to coordinate. When sending a notification, also send a message in the BroadcastChannel telling other instances of the userscript to reset their timers as well.
const channel = new BroadcastChannel('logout-notify');
let timeoutId;
function makeTimeout() {
clearTimeout(timeoutId);
timeoutId = setTimeout(function () {
GM_notification({
title: 'Refresh Business Manager', text: 'Your about to be logged out of staging, click here to refresh your login.', image: 'https://i.stack.imgur.com/geLPT.png',
onclick: () => {
console.log("My notice was clicked.");
location.reload();
}
});
channel.postMessage('notified');
}, 1000 * 60 * 20 + (Math.random() * 10000)); // 20 minutes plus up to 10 seconds
}
// When below runs, another tab created a notification
// reset the timeout for this tab, schedule another one for 20ish minutes from now
channel.onmessage = makeTimeout;
// initialize timeout on pageload?
makeTimeout();
This code will result in alerts being shown only once every 20 minutes at most. If you close one tab you were working on, other tabs will take up the slack without interruption.

Chrome on Android : connection become dead after 30 minutes

We are building a chatroom with our own notification system without depending on GCM but with service worker + SSE.
On desktop it is fine , but on mobile android app (which uses cordova-crosswalk , chromium 53 ) .
The long running notification connection become stuck after 20-30 minutes and it is in foreground activity.
It dosen't die with an error , just not reciving data. No error at all which is very weird. No way to reconnect since we do not know if the connection is dead at all.
What would be the cleanest way? Restarting connection every 5 minutes is one idea but it is not clean.
code
runEvtSource(url, fn) {
if (this.get('session.content.isAuthenticated') === true) {
var evtSource = new EventSource(url, {
withCredentials: true
});
}}
Agressive reconnect code
var evtSource = this.runEvtSource(url, fn)
var evtSourceErrorHandler = (event) => {
var txt;
switch (event.target.readyState) {
case EventSource.CONNECTING:
txt = 'Reconnecting...';
evtSource.onerror = evtSourceErrorHandler;
break;
case EventSource.CLOSED:
txt = 'Reinitializing...';
evtSource = this.runEvtSource(url, fn)
evtSource.onerror = evtSourceErrorHandler;
break;
}
console.log(txt);
evtSource.onerror = evtSourceErrorHandler
I normally add a keep-alive layer on top of the the SSE connection. It doesn't happen that often, but sockets can die without dying properly, so your connection just goes quiet and you don't get an error.
So, one way is, inside your get data function:
if(timer)clearTimeout(timer);
timer = setTimeout(reconnect, 30 * 1000);
...process the data
In other words, if it is over 30 seconds since you last got data, reconnect. Choose a value based on the frequency of the data you send: if 10% of the time there is a 60 second gap between data events, but never a 120 second gap, then setting the time-out to something higher than 120 seconds makes sense.
You might also want to keep things alive by pushing regular messages from the server to client. This is a good idea if the frequency of messages from the server is very irregular. E.g. I might have the server send the current timestamp every 30 seconds, and use a keep-alive time-out of 45 seconds on the client.
As an aside, if this is a mobile app, bear in mind if the user will appreciate the benefit of reduced latency of receiving chat messages against the downside of reduced battery life.

Web Workers in Chrome v54 run twice as slow when running in an inactive tab

I have a webapp that plays audio with fade in/out transitions using setTimeout. It is well known that chrome and other browsers throttle setTimeout execution when it is running in an inactive (or background) tab. So to solve this issue, I use this script (https://github.com/turuslan/HackTimer) which patches the Timer API to use Web Workers instead. This allows the volume fading transitions to run in the background so that they will always be executed and completed in the same time regardless if the tab is active. This used to work great in chrome, but now I have noticed that in version 54 (and probably earlier versions) of chrome, the Web Workers are being executed twice as slow when running in an inactive tab. This issue does not happen and works perfectly with FireFox and even IE11!
Is this a chrome bug? Or is it intended behavior? Is there another workaround to this issue? I don't want to require that the webapp to be opened in a separate window, so that is not an option.
Here is a demonstration:
https://jsfiddle.net/2614xsj8/1/
// Open Chrome console and run this then wait a few seconds to see
// it is executing on time. Then open or switch to a new tab and wait
// a few seconds. Come back to see how much slower the setTimeout
// function was being called even when using HackTimer which patches
// the Timer API to use Web Workers
var rate = 1000;
var start = new Date().getTime();
var func = function() {
var now = new Date().getTime();
var time = now - start;
var status = Math.abs(rate - time) <= 50 ? "on time" : (time / rate) + " times slower";
console.log("executed in [" + time + "] milliseconds. " + status);
start = now;
setTimeout(func, rate);
};
setTimeout(func, rate);
<script src="https://cdn.rawgit.com/turuslan/HackTimer/master/HackTimer.js" type="text/javascript"></script>
Using Task Scheduler would be the best way to do it then you don't really on timeout or interval but a specific date
But this requires using service workers instead... which is a bummer. cuz then your site also needs to be whitelisted in order to run service workers (so your site needs a valid SSL cert)
// https://example.com/serviceworker.js
this.ontask = function(task) {
alert(task.data.message);
console.log("Task scheduled at: " + new Date(task.time));
// From here on we can write the data to IndexedDB, send it to any open windows,
// display a notification, etc.
}
// https://example.com/webapp.js
function onTaskAdded(task) {
console.log("Task successfully scheduled.");
}
function onError(error) {
alert("Sorry, couldn't set the alarm: " + error);
}
navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
serviceWorkerRegistration.taskScheduler.add(Date.now() + (10 * 60000), {
message: "It's been 10 minutes, your soup is ready!"
}).then(onTaskAdded, onError);
});

location.reload(true) crashing browser tab

I have a website that uses PHP sessions, and I have implemented the following JS code to check every 60 seconds if a user's sessions is still active:
var timeoutInterval = 60000; // 1 minute
function checkTimeout() {
var timeoutWorker = new Worker("/include/cbpull.js");
timeoutWorker.postMessage('/cloud/timeout.php');
timeoutWorker.onmessage = function (result) {
if (result.data['result'] === false) {
location.reload(true);
}
}
}
function sessionTimeout() {
checkTimeout();
setInterval(checkTimeout, timeoutInterval);
}
sessionTimeout();
However, this code crashes the tab in Google Chrome when the session is timed out and location.reload(true) is called. What can I do to make the code work correctly?
Might the following be what's happening? On a session time-out, you reload the page, which immediately triggers sessionTimeout again, which again finds that the session is (still) expired, which reloads the page...

Time an event using javascript/jquery

Is it possible to trigger an event on a website, say 30 seconds after someone hits the site, even if they move between pages, or would that require some server side coding?
Thanks in advance.
You can use session storage to accomplish this. Javascript Storage data persists across pages and refreshes. Here is some info: http://www.w3schools.com/html/html5_webstorage.asp
// SET THIS ON THE FIRST VISIT. CHECK IF ALREADY SET.
if(typeOf(localStorage.getItem('timer')) == 'undefined'){
localStorage.setItem("timer", "0");
}
setInterval(function(){
// ADD 1 SECOND TO SESSION TIMER
localStorage.setItem("timer", localStorage.getItem("timer")++);
if(localStorage.getItem("timer") == 30){
// TRIGGER YOUR EVENT ON 30 SECONDS
}
}, 1000);

Categories