Sending Ajax Call When User Exits - javascript

I want to remove user stored data in my database when the user exits the page. A window dialog box will come up asking if the user really wishes to exit the page. Upon confirming to leave, an Ajax call should be sent to PHP confirming the action. Is it possible for PHP to receive the call in time and execute the command? If not, are there any other ways to verify that the Ajax call is sent successfully and the command is executed?

If you need very short-lived data (only relevant while the user is on the page), a database is not the right tool. Databases are designed to store long-lived data.
I suggest you use sessions instead. Here's a quick intro. Basically, sessions allow you to persist data across http requests, but to expire that data after a short while.
Start the session when the user logs in or opens your entry page, and store in $_SESSION any data you want to access while the user is on the page.
entry or login page
<?php
if(session_status()===PHP_SESSION_NONE) session_start();
... work through your script
//store data you'll need later
$_SESSION['username'] = 'Linda';
$_SESSION['age'] = 22;
$_SESSION['expires'] = time()+ 60*15; //expires in 15 minutes
The next time the user makes a request, test whether the session is still active. If so you can get the data from session, and refresh expiration. If the session has expired, you can destroy the data.
protected page
<?php
if(session_status()===PHP_SESSION_NONE) session_start();
if(isset($_SESSION['expires']) && $_SESSION['expires'] > time()){
//session is still active. extend expiration time
$_SESSION['expiration'] = time() + 60*15;
//retrieve data
$user = $_SESSION['username'];
.... run your script
}else{
//either the session doesn't exist or it has expired because the user
//left the page or stopped browsing the site
//destroy the session and redirect the user
session_destroy();
header('Location: /login.php');
}

You should not use unreliable, hacky and annoying methods. The only events that come close to your needs are window.onbeforeunload and window.unload but popups are usually blocked in those events (hence the hacky) and when blocked the remainder code as well.
There is also the issue that closing a tab will fire the events, closing the browser however will skip them and its all dependent if the browser actually supports it.
Perhaps use an ajax call every 5 minutes to detect if the page is still running and update a database with that time.
Now with a server cronjob you should select all rows with a time < now() - 300 and then you should have a list of browsers that recently connected but are not sending any signal anymore.
Or you could save the data in localstorage every 10 seconds so then there is no need to do all this?

Try This:
<script>
window.onbeforeunload = function (event) {
var message = 'Important: Please click on \'Save\' button to leave this page.';
if (typeof event == 'undefined') {
event = window.event;
//ajax call here
}
if (event) {
event.returnValue = message;
}
return message;
};
</script>

Related

Laravel Auth Polling - Session Is Getting Reset With Ajax Call

I am trying to set up some polling on the Front End to check for inactive users and boot them to the login screen if they stay inactive for too long. The problem is, every time I make the ajax call, it is reseting the session and acting as if the user is active, even if I remain inactive in the app. It seems as though the ajax call is causing the session to act as if the user is active. Is there a way to made an AJAX call without it reseting the session like that? I tried to add the route in my api.php routes but if I check for Auth via those routes I just get false every time (cannot access Auth::user()). Any work arounds to this issue.
Code & Information:
Using SESSION_DRIVER=file (I know one work around is to use the database driver but I'd rather try and keep it file if possible)
UserController.php
public function userLoginPoll(Request $request)
{
$statusArray = [
'logged_in' => Auth::check()
];
return $statusArray;
}
web.php
Route::get('/users_api/userLoginPoll', 'UserController#userLoginPoll');
poll.js
$.poll(3000, function(retry){
$.get('/users_api/userLoginPoll', function(data){
if(data.logged_in){
retry();
}else{
window.location = '/login';
}
});
});
Using This Polling JQ Plugin

Countdown timer to logout of application [duplicate]

This question already has answers here:
How do I expire a PHP session after 30 minutes?
(17 answers)
Closed 5 years ago.
I have developed a staff record system for my company. The problem im facing is that the staff leaves their systems logged on and even forget to logout. I want the system to logout the user after leaving the system idle for 10 minutes. I have virtually no idea on how to go about it. I need your help
I've built functionality similar to what you're trying to achieve in the past using jQuery Idle. It detects mouse and keyboard activity and only times out when a user is truly inactive.
https://github.com/kidh0/jquery.idle
Example:
$(document).idle({
onIdle: function(){
windlow.location.href = '/logout.php';
},
idle: 10000
})
You can use this kind of code.
<!-- //for 10 minutes // the easiest one!-->
<meta http-equiv="refresh" content="600;url=logout.php" />
Keep in mind the logout.php need some code like this
session_start();
session_destroy();
unset($_SESSION);
header("Location: 'index.php?stayedToLong=yes');
exit;
Or SESSION in php something like
session_start();
//measure the time
$_SESSION['loggedTime'] = time();
//10 minutes
if($_SESSION['loggedTime'] < time()+10*60)
{
session_destroy();
unset( $_SESSION );
header("Location: 'index.php?stayedToLong=yes');
exit;
}
In the index.php page from the redirection index?stayedToLong=yes, you can show the page like this.
if(isset($_GET['stayedToLong']) && $_GET['stayedToLong']=='yes')
{
echo 'You have are disconnected after 10 minutes';
}
There's a couple of methods here. First off, your server should be clearing sessions after a certain time has elapsed. Your server should also have some way to refresh that session, typically an api endpoint of some sort that simply refreshes the session to keep it active.
In combination with that, in order to avoid an issue where your server session has ended but your front end session has not, you'll want to use a timer in javascript that requests the session value every few minutes. If that session ever returns inactive then you'll want to either display a modal or popup allowing the user to continue their session or you'll want to just automatically redirect them to a page that tells the user their session has expired.
In javascript your solution might look something like the following.
function confirmSessionRefresh(){
if( confirm('Your session will expire in 1 minute. Click Ok to continue or cancel to log out in 1 minute.') ){
fetch('/api/refreshsession');
setTimeout(confirmSessionRefresh, 540000);
}
}
setTimeout(confirmSessionRefresh, 540000); // 9 minutes (to allow 1 minute to respond to the prompt.

Java script, PHP

I have a scenario where I need to execute a logout function in php, this function deletes the user from DB and informs another application through sockets. This function should be called when the user closes the browser or tab. I have tried various scenarios posted by others and nothing seems to work in chrome(Version 57.0.2987.110) and firefox.
Following is the examples I tried along with links,
My sample Code
<script type="text/javascript">
var str = 'delete';// this will be set to 'Apply' if the form is submitted.
function logout(){
location.href = 'Logout.php';
}
function pageHidden(evt){
if (str==='delete')
logout();
}
window.addEventListener("pagehide", pageHidden, false);
</script >
Examples I tried....
// 1st approach
//window.addEventListener("beforeunload", function (e) {
/// var confirmationMessage = "Do you want to leave?";
// (e || window.event).returnValue = confirmationMessage;
// return confirmationMessage;
// });
// 2nd approach
// window.onbeforeunload = myUnloadEvent;
// function myUnloadEvent() {
// console.log("Do your actions in here")
// }
// 3rd approach
$(window).on('beforeunload', function() {
return 'Your own message goes here...';
});
checked the following urls
1. window.onunload is not working properly in Chrome browser. Can any one help me?
2. https://webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/ - I followed this approach. Tried some other approaches as well.
3. I can't trigger the unload event in Chrome etc....
Any help is much appreciated, because if the user closes the browser an entry remains in the DB and this is not allowing any new user to login.
You shouldn't rely on JavaScript for sever-side code. It's actually entirely possible to achieve what you're looking for, purely with PHP. Just make sure to 'kill' the session before starting it:
session_set_cookie_params(0);
session_start();
session_set_cookie_params(0) will tell the browser that any exisiting session should only exist for another 0 seconds. Essentially, this means that a user will automatically 'log out' immediately. This way, you don't have to rely on client-side code, which is susceptible to all measure of interrupts such as power outages.
Hope this helps! :)
The correct way to logout is related to how they are logged in.
In PHP, the login state is typically managed by sessions. By default the timeout is 24 minutes of inactivity, but you can easily reduce it.
When a user logs out, you typically reset one or more session variables, and, while you’re at it, kill off the current session, and delete the session cookie.
However, you cannot rely on a user to log out, and many typically just wander off. This is why there is always a relatively short timeout on sessions.
If you want to automatically logout when the tab is closed, you will need JavaScript to intercept the process with window.onbeforeunload and then use Ajax to send the logout to the server.
As regards the database, you normally do not record the login state in the database. You may record the login time, and if you like, the logout time, but remember that may be never.

Backend only alternative to javascript periodic function call?

I have the following in my js file that is included in the main .cshtml page of my ASP.NET MVC application:
var ajax_call = function () {
$.ajax({
type: "GET",
cache: false,
url: "/Session/Index/",
success: function (result) {
if (!(result.length > 0)) {
window.location.href = '/Home/Index/'
}
}
});
};
var interval = 1000 * 60 * .2; // where X is your every X minutes---.2 -> every 12 seconds
setInterval(ajax_call, interval);
The goal is to check if the session is still valid (the SessionController only returns a result if the session is active), otherwise the browser gets redirected to Home/Index, where HomeController has a global authorization attribute that redirects to the login page if the log in is not a valid session.
My questions are, is this a valid approach? It works (if I login in with a user, then open a new window and log in with the same user in the new window, the old window gets redirected to the login screen shortly after, depending on where it is in the 12 second cycle), but is there a way I can do such a thing entirely in the backend?
Thank you.
The goal is to check if the session is still valid
This is not a good approach, because a request to a server will rest the session timeout to 0. It means you are making session alive forever. If a user forgets to close the browser and leave the computer open, other can still access the account.
Here is the approach I use in my websites inspired by banking/credit card websites.
By default, Session Time out is 20 minutes (you can adjust the way you want). So, I let timer run at client side. When it reaches 19 minutes, I display a popup message with a minute count down timer.
If use does not close the popup, I redirect to logout page.
Here is the concept and sample code, but you do not need to use Telerik control to achieve it.

Best way to detect when a user leaves a web page?

What is the best way to detect if a user leaves a web page?
The onunload JavaScript event doesn't work every time (the HTTP request takes longer than the time required to terminate the browser).
Creating one will probably be blocked by current browsers.
Try the onbeforeunload event: It is fired just before the page is unloaded. It also allows you to ask back if the user really wants to leave. See the demo onbeforeunload Demo.
Alternatively, you can send out an Ajax request when he leaves.
Mozilla Developer Network has a nice description and example of onbeforeunload.
If you want to warn the user before leaving the page if your page is dirty (i.e. if user has entered some data):
window.addEventListener('beforeunload', function(e) {
var myPageIsDirty = ...; //you implement this logic...
if(myPageIsDirty) {
//following two lines will cause the browser to ask the user if they
//want to leave. The text of this dialog is controlled by the browser.
e.preventDefault(); //per the standard
e.returnValue = ''; //required for Chrome
}
//else: user is allowed to leave without a warning dialog
});
Here's an alternative solution - since in most browsers the navigation controls (the nav bar, tabs, etc.) are located above the page content area, you can detect the mouse pointer leaving the page via the top and display a "before you leave" dialog. It's completely unobtrusive and it allows you to interact with the user before they actually perform the action to leave.
$(document).bind("mouseleave", function(e) {
if (e.pageY - $(window).scrollTop() <= 1) {
$('#BeforeYouLeaveDiv').show();
}
});
The downside is that of course it's a guess that the user actually intends to leave, but in the vast majority of cases it's correct.
In the case you need to do some asynchronous code (like sending a message to the server that the user is not focused on your page right now), the event beforeunload will not give time to the async code to run. In the case of async I found that the visibilitychange and mouseleave events are the best options. These events fire when the user change tab, or hiding the browser, or taking the courser out of the window scope.
document.addEventListener('mouseleave', e=>{
//do some async code
})
document.addEventListener('visibilitychange', e=>{
if (document.visibilityState === 'visible') {
//report that user is in focus
} else {
//report that user is out of focus
}
})
Thanks to Service Workers, it is possible to implement a solution similar to Adam's purely on the client-side, granted the browser supports it. Just circumvent heartbeat requests:
// The delay should be longer than the heartbeat by a significant enough amount that there won't be false positives
const liveTimeoutDelay = 10000
let liveTimeout = null
global.self.addEventListener('fetch', event => {
clearTimeout(liveTimeout)
liveTimeout = setTimeout(() => {
console.log('User left page')
// handle page leave
}, liveTimeoutDelay)
// Forward any events except for hearbeat events
if (event.request.url.endsWith('/heartbeat')) {
event.respondWith(
new global.Response('Still here')
)
}
})
I know this question has been answered, but in case you only want something to trigger when the actual BROWSER is closed, and not just when a pageload occurs, you can use this code:
window.onbeforeunload = function (e) {
if ((window.event.clientY < 0)) {
//window.localStorage.clear();
//alert("Y coords: " + window.event.clientY)
}
};
In my example, I am clearing local storage and alerting the user with the mouses y coords, only when the browser is closed, this will be ignored on all page loads from within the program.
One (slightly hacky) way to do it is replace and links that lead away from your site with an AJAX call to the server-side, indicating the user is leaving, then use that same javascript block to take the user to the external site they've requested.
Of course this won't work if the user simply closes the browser window or types in a new URL.
To get around that, you'd potentially need to use Javascript's setTimeout() on the page, making an AJAX call every few seconds (depending on how quickly you want to know if the user has left).
What you can do, is open up a WebSocket connection when the page loads, optionally send data through the WebSocket identifying the current user, and check when that connection is closed on the server.
Page Visibility API
✅ The Page Visibility API provides events which can be watch to know when a document becomes visible or hidden.
✅ When the user minimizes the window or switches to another tab, API triggers a visibilitychange event.
✅ We can perform the actions based on the visibilityState
function onVisibilityChange() {
if (document.visibilityState === 'visible') {
console.log("user is focused on the page")
} else {
console.log("user left the page")
}
}
document.addEventListener('visibilitychange', onVisibilityChange);
For What its worth, this is what I did and maybe it can help others even though the article is old.
PHP:
session_start();
$_SESSION['ipaddress'] = $_SERVER['REMOTE_ADDR'];
if(isset($_SESSION['userID'])){
if(!strpos($_SESSION['activeID'], '-')){
$_SESSION['activeID'] = $_SESSION['userID'].'-'.$_SESSION['activeID'];
}
}elseif(!isset($_SESSION['activeID'])){
$_SESSION['activeID'] = time();
}
JS
window.setInterval(function(){
var userid = '<?php echo $_SESSION['activeID']; ?>';
var ipaddress = '<?php echo $_SESSION['ipaddress']; ?>';
var action = 'data';
$.ajax({
url:'activeUser.php',
method:'POST',
data:{action:action,userid:userid,ipaddress:ipaddress},
success:function(response){
//alert(response);
}
});
}, 5000);
Ajax call to activeUser.php
if(isset($_POST['action'])){
if(isset($_POST['userid'])){
$stamp = time();
$activeid = $_POST['userid'];
$ip = $_POST['ipaddress'];
$query = "SELECT stamp FROM activeusers WHERE activeid = '".$activeid."' LIMIT 1";
$results = RUNSIMPLEDB($query);
if($results->num_rows > 0){
$query = "UPDATE activeusers SET stamp = '$stamp' WHERE activeid = '".$activeid."' AND ip = '$ip' LIMIT 1";
RUNSIMPLEDB($query);
}else{
$query = "INSERT INTO activeusers (activeid,stamp,ip)
VALUES ('".$activeid."','$stamp','$ip')";
RUNSIMPLEDB($query);
}
}
}
Database:
CREATE TABLE `activeusers` (
`id` int(11) NOT NULL,
`activeid` varchar(20) NOT NULL,
`stamp` int(11) NOT NULL,
`ip` text
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Basically every 5 seconds the js will post to a php file that will track the user and the users ip address. Active users are simply a database record that have an update to the database time stamp within 5 seconds. Old users stop updating to the database. The ip address is used just to ensure that a user is unique so 2 people on the site at the same time don't register as 1 user.
Probably not the most efficient solution but it does the job.

Categories