I came across this while checking some browser compatibility for XMLHttp and randomly browser threads on here for the sake of it. Figured i would give my working example that i came up with because i need something similar soon and figured this question could do with a larger example.
Very minimal code at bottom
Please forgive me for this being a little messy, its a raw example.
<?php
// Do not forget session start if copying into your own code..
if (isset($_GET['keepalive'])) {
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header('Content-Type: application/json');
$boolStatusOfSession = TRUE; // Something like: $boolStatusOfSession = (isset($_SESSION['MyTokenWhenSignedIn']) ? TRUE : FALSE);
echo json_encode(array('status'=>$boolStatusOfSession));
exit;
}
?>
<html>
<head></head>
<body>
<p>This script will throttle the mouse movement event to a rate of once per second max and perform a keep alive request to the same page along with a json response of the session status</p>
<p id="debugbox"><b>Server Keep Alive: </b>please wait for the timer (10 seconds)</p>
<p id="debugbox2"></p>
<script>
var elmDebug = document.getElementById('debugbox');
var elmDebug2 = document.getElementById('debugbox2');
var idleStart = Math.floor(Date.now() / 1000);
function keepAlivePoster() {
objHttp = new XMLHttpRequest();
objHttp.onreadystatechange = function() {
var strDebug = "<b>Server Keep Alive: </b> ";
if (objHttp.readyState == XMLHttpRequest.DONE) {
idleStart = Math.floor(Date.now() / 1000);
objResp = JSON.parse(objHttp.responseText);
if (objResp.hasOwnProperty('status') && objResp.status == true) {
// DO STUFF HERE WHEN SIGNED IN (Or do nothing at all)
strDebug += "Signed In, ";
} else {
// DO STUFF HERE WHEN SIGNED OUT (A window reload if your page can handle the session change)
strDebug += "Signed Out, "; // Or does not exist / error.. best to use a int status
}
}
elmDebug.innerHTML = strDebug + "Updated at " + Math.floor(Date.now() / 1000);
elmDebug2.innerHTML = '<b>Mouse Move Event: </b> Idle timer reset to ' + idleStart;
}
objHttp.open('GET', '?keepalive');
objHttp.send(null);
};
function throttleController (callback, limit) { // TAKEN FROM: https://jsfiddle.net/jonathansampson/m7G64/
var wait = false; // Initially, we're not waiting
elmDebug2.innerHTML = '<b>Mouse Move Event: </b> Idle timer reset to ' + idleStart;
return function () { // We return a throttled function
if (!wait) { // If we're not waiting
callback.call(); // Execute users function
wait = true; // Prevent future invocations
setTimeout(function () {wait = false;}, limit); // After a period of time, allow future invocations again
}
}
}
window.addEventListener("mousemove", throttleController(keepAlivePoster, 10000)); // Allow "idleCallback" to run at most 1 time every 10 seconds
</script>
</body>
</html>
Of course there is a bit of code you can remove (the debug and so on, so a bare basic script example would be)
Minimal Code
function keepAlivePoster() {
objHttp = new XMLHttpRequest();
objHttp.open('GET', '?keepalive');
objHttp.send(null);
};
function throttleController (callback, limit) { // TAKEN FROM: https://jsfiddle.net/jonathansampson/m7G64/
var wait = false; return function () {
if (!wait) { callback.call(); wait = true; setTimeout(function () {wait = false;}, limit); }
}
}
window.addEventListener("mousemove", throttleController(keepAlivePoster, 10000));
The last line you would duplicate for any additional events you want to cover, you would also want to make the wait variable on a higher scope / global when you use more than one event.
Why the php status / code
Well first of this would be in another file that is included well before html generation and all that.. But ideally you want the GET request to be as small as possible with a few rules and so on.. So i've disabled the ability for the page to be cached and the json response can easily be used by the browser while offering a simple check to redirect/reload if needed.