how to kill a application session when a browser window is closed? - javascript

i have a problem.
I am working on a chatting application. I want to kill the session if user closes the browser window without logging off. I used 'beforeunload' function but it also fires when a postback event is fired so it's not good for me.
Please help if anyone have any idea about it.

If you use polling to get the chat data, you should kill the session if you don't get a polling request from the client for a given time.
Client:
setInterval (pollData, 10000); /* poll for new data each 10 seconds */
Server:
if (clientX.LastPollTime is over 30 seconds ago) {
clientX.killSession();
}

I suggest you to use the Alexanders approach, but In most cases setting interval time wont alone solve this problem. Because the user may be idle for some time and it may exceed the timeout period.
In order to avoid this, yo need to add one more condition over this.
if the user is idle for the timeout period then Just make an AJAX request to server and update the client status as idle.
this will avoid logging off the session if the user is idel for certain time.
And you can terminate the session if the server didnt recieve any response from client in a specified time and the status is not updated to idle (during browser close or any application hangups).

yup dear, it is okey, but in second thing as you specified that that server didn't receive any response, in my code server only checks the application session and it will find it so it will work. what i want that if the user not log off then the page is killed and after that how can we call any ajax or xmlhttp request from client side to set the application session to offline.
so please guys tell me something this is the only thing is not going well. and thanx for your response.

As you said the event window.onbeforeunload fires when the users clicks on a link or refreshes the page, so it would not a good even to end a session.
However, you can place a JavaScript global variable on your pages to identify actions that should not trigger a logoff (by using an AJAX call from onbeforeonload, for example).
The script below relies on JQuery
/*
* autoLogoff.js
*
* Every valid navigation (form submit, click on links) should
* set this variable to true.
*
* If it is left to false the page will try to invalidate the
* session via an AJAX call
*/
var validNavigation = false;
/*
* Invokes the servlet /endSession to invalidate the session.
* No HTML output is returned
*/
function endSession() {
$.get("<whatever url will end your session>");
}
function wireUpEvents() {
/*
* For a list of events that triggers onbeforeunload on IE
* check http://msdn.microsoft.com/en-us/library/ms536907(VS.85).aspx
*/
window.onbeforeunload = function() {
if (!validNavigation) {
endSession();
}
}
// Attach the event click for all links in the page
$("a").bind("click", function() {
validNavigation = true;
});
// Attach the event submit for all forms in the page
$("form").bind("submit", function() {
validNavigation = true;
});
}
// Wire up the events as soon as the DOM tree is ready
$(document).ready(function() {
wireUpEvents();
});
This script may be included in all pages
<script type="text/javascript" src="js/autoLogoff.js"></script>
Let's go through this code:
var validNavigation = false;
window.onbeforeunload = function() {
if (!validNavigation) {
endSession();
}
}
// Attach the event click for all links in the page
$("a").bind("click", function() {
validNavigation = true;
});
// Attach the event submit for all forms in the page
$("form").bind("submit", function() {
validNavigation = true;
});
A global variable is defined at page level. If this variable is not set to true then the event windows.onbeforeonload will terminate the session.
An event handler is attached to every link and form in the page to set this variable to true, thus preventing the session from being terminated if the user is just submitting a form or clicking on a link.
function endSession() {
$.get("<whatever url will end your session>");
}
The session is terminated if the user closed the browser/tab or navigated away. In this case the global variable was not set to true and the script will do an AJAX call to whichever URL you want to end the session
This solution is server-side technology agnostic. It was not exaustively tested but it seems to work fine in my tests
PS: I already posted this answer in this question. I am not sure I should answer multiple questions that are similar or post a reference?

If you have control of sessionID cookie, just set its lifetime to 0, that makes the session die on browser close. The lifetime of the session on the open window can be controled from the server side storing the time last seen in the session and checking
if(isset($_COOKIE[session_name()])) {
setcookie(session_name(), $_COOKIE[session_name()], 0, "/"); // die # browser close
}
if(isset($_SESSION['last_time'])){
if( ( time() - $_SESSION['last_time'] ) > 300 ){ // 5 minutes timeout
// here kill session;
}
}
$_SESSION['last_time'] = time();
In the client side you can use the Daniel Melo's answer. I'm using it with one small change:
function endSession() {
// $.get("<whatever url will end your session>");
// kill the session id
document.cookie = 'MYOWNSESSID=; path=/';
}
The only pending matter is that i can't wireup events to input type[buttons] yet, i have made it with raw code, but the all thing works.

Related

Dealing with session along multiple tabs

Recently came across this problem. The scenario is, let's say I have two tabs open (A and B), I login with Tab A authenticates redirects to the home page. Then selected a link instead of just entering, I right click and pick "Open link in a new tab" thus having Tab B. At this point I start navigating for 30 mins a alert pop up saying my "Session has been finish. Please login again.". Instead of being redirected to the Login page I was redirected to the home page. (The alert must be coming for Tab A)
If I was dealing with only one Tab this isn't an Issue after the alert I would go directly to the Login Page.
I have two set of codes one handles the actual session expiration and the other gives out the alert.
This code is for the alert:
function idleLogout() {
var t;
window.onload = resetTimer;
window.onmousemove = resetTimer;
window.onmousedown = resetTimer;
window.onclick = resetTimer;
window.onscroll = resetTimer;
window.onkeypress = resetTimer;
function logout() {
alert("Session has been finish. Please login again.");
window.location.href = '{{url("")}}';
}
function resetTimer() {
clearTimeout(t);
t = setTimeout(logout, {{ env('SESSION_LIFETIME')*60*1000 }} );
}
}
idleLogout();
Code is working as intended but it can be implemented better.
Btw, if it matters using PHP Laravel 5
The problem is that you're using JavaScript to handle your timeouts. JavaScript (by default) is only confined to a single tab. While you could make use of COOKIES in JavaScript to communicate between tabs, it would make far more sense to handle session timeouts through server-side SESSION variables, which persist across tabs.
A thirty minute forced timeout can be achieved in PHP, courtesy of this answer:
if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 1800)) {
// last request was more than 30 minutes ago
session_unset(); // unset $_SESSION variable for the run-time
session_destroy(); // destroy session data in storage
}
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp
Hope this helps.

How can I do a javascript that only runs once

I have this jquery code:
$(document).ready(function(){
$(".body").hide();
setTimeout(function() {
$(".body").show()
}, 2000);
setTimeout(function() {
$(".img").fadeOut(1000)
}, 1000);
});
And I'd like it so that it will only work when the page is first clicked on. So when you reload the page or navigate through the site and navigate back to it the script above won't execute.
You can use localStorage to store values at the browser level, so next time a user visits your site they will get the same data. If you set a flag when they visit your site then you can tell the first time they visit, due to that flag not being set.
Here's that change added to your code, with corresponding comments...
$(document).ready(function(){
// check localStorage to see if we've run this before. If we have then do nothing
if (!localStorage.getItem("first-run")) {
// set a flag in localStorage so we know we've run this before.
localStorage.setItem("first-run", true);
$(".body").hide();
setTimeout(function() {
$(".body").show()
}, 2000);
setTimeout(function() {
$(".img").fadeOut(1000)
}, 1000);
}
});
Try something like this.
$(document).ready(function() {
if(!localStorage.visited) {
//do first page load stuff
...
localStorage.visited = true;
}
});
There are already solutions here using localStorage; however, a value set in localStorage will remain until the user clears their browser data. This means that your code will never run again unless you specifically do extra work to check how long it has been set, etc.
If you would like it to run again when they visit the page later you should use sessionStorage:
...data stored in sessionStorage gets cleared when the page session
ends. A page session lasts for as long as the browser is open and
survives over page reloads and restores. Opening a page in a new tab
or window will cause a new session to be initiated, which differs from
how session cookies work.
This will allow the code to run on a new visit to the page, but reloading or navigating away/back will not trigger it because the sessionStorage is still set. However, if they close the tab/window and come back to it later, the code will run again.
$(document).ready(function() {
if(!sessionStorage.visited) {
sessionStorage.visited = true;
...
//other code
}
});

How to stop update panel current process and call button click event

In my ASP.NET page my users can check the customer balance before sending any payment. Balance update label is inside the Update Panel and sometimes it takes longer than usual to check the customer balance, so users might want to just cancel the checking and proceed to next step.
Is there any way to stop the current Update Panel event (while it's running and taking too long) and call some button Click event by using JavaScript?
You can use code like this to cancel the refresh of the UpdatePanel.
var divElem = 'AlertDiv';
var messageElem = 'AlertMessage';
Sys.Application.add_load(ApplicationLoadHandler)
function ApplicationLoadHandler(sender, args)
{
Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest(CheckStatus);
}
function CheckStatus(sender, args)
{
var prm = Sys.WebForms.PageRequestManager.getInstance();
if (prm.get_isInAsyncPostBack() & args.get_postBackElement().id == 'CancelRefresh') {
prm.abortPostBack();
}
else if (prm.get_isInAsyncPostBack() & args.get_postBackElement().id == 'RefreshButton') {
args.set_cancel(true);
ActivateAlertDiv('visible', 'Still working on previous request.');
}
else if (!prm.get_isInAsyncPostBack() & args.get_postBackElement().id == 'RefreshButton') {
ActivateAlertDiv('visible', 'Retrieving headlines.');
}
}
function ActivateAlertDiv(visString, msg)
{
var adiv = $get(divElem);
var aspan = $get(messageElem);
adiv.style.visibility = visString;
aspan.innerHTML = msg;
}
if(typeof(Sys) !== "undefined") Sys.Application.notifyScriptLoaded();
However, the processing of the ASP.NET request will continue in the background.
If the user cannot navigate until this is complete, it could be the ASP.NET session locking stopping your second request from starting until the first one is complete. You could try checking the Response.IsClientConnected property in the code of your first request and abort it if false. You may need to check this in a separate thread if your main thread is busy doing the processing, but it depends on the architecture of your application.
A simpler suggestion is to try disabling session, or setting it to read only if your page does not make use of it or write to it (quoted from this answer):
If your page does not modify any session variables, you can opt out of most of this lock.
<% #Page EnableSessionState="ReadOnly" %>
If your page does not read any session variables, you can opt out of this lock entirely, for that page.
<% #Page EnableSessionState="False" %>
If none of your pages use session variables, just turn off session state in the web.config
<sessionState mode="Off" />
I found a solution in C#. This code is put inside the code that updates the UpdatePanel control:
Thread th = new Thread(DoSomething);
th.Start();
if (!th.Join(TimeSpan.FromSeconds(3)))
{
th.Abort();
}
If the UpdatePanel takes longer than 3 secs to update then it just aborts the current thread.

Is it possible to know how long a user has spent on a page?

Say I've a browser extension which runs JS pages the user visits.
Is there an "outLoad" event or something of the like to start counting and see how long the user has spent on a page?
I am assuming that your user opens a tab, browses some webpage, then goes to another webpage, comes back to the first tab etc. You want to calculate exact time spent by the user. Also note that a user might open a webpage and keep it running but just go away. Come back an hour later and then once again access the page. You would not want to count the time that he is away from computer as time spent on the webpage. For this, following code does a docus check every 5 minutes. Thus, your actual time might be off by 5 minutes granularity but you can adjust the interval to check focus as per your needs. Also note that a user might just stare at a video for more than 5 minutes in which case the following code will not count that. You would have to run intelligent code that checks if there is a flash running or something.
Here is what I do in the content script (using jQuery):
$(window).on('unload', window_unfocused);
$(window).on("focus", window_focused);
$(window).on("blur", window_unfocused);
setInterval(focus_check, 300 * 1000);
var start_focus_time = undefined;
var last_user_interaction = undefined;
function focus_check() {
if (start_focus_time != undefined) {
var curr_time = new Date();
//Lets just put it for 4.5 minutes
if((curr_time.getTime() - last_user_interaction.getTime()) > (270 * 1000)) {
//No interaction in this tab for last 5 minutes. Probably idle.
window_unfocused();
}
}
}
function window_focused(eo) {
last_user_interaction = new Date();
if (start_focus_time == undefined) {
start_focus_time = new Date();
}
}
function window_unfocused(eo) {
if (start_focus_time != undefined) {
var stop_focus_time = new Date();
var total_focus_time = stop_focus_time.getTime() - start_focus_time.getTime();
start_focus_time = undefined;
var message = {};
message.type = "time_spent";
message.domain = document.domain;
message.time_spent = total_focus_time;
chrome.extension.sendMessage("", message);
}
}
onbeforeunload should fit your request. It fires right before page resources are being unloaded (page closed).
<script type="text/javascript">
function send_data(){
$.ajax({
url:'something.php',
type:'POST',
data:{data to send},
success:function(data){
//get your time in response here
}
});
}
//insert this data in your data base and notice your timestamp
window.onload=function(){ send_data(); }
window.onbeforeunload=function(){ send_data(); }
</script>
Now calculate the difference in your time.you will get the time spent by user on a page.
For those interested, I've put some work into a small JavaScript library that times how long a user interacts with a web page. It has the added benefit of more accurately (not perfectly, though) tracking how long a user is actually interacting with the page. It ignore times that a user switches to different tabs, goes idle, minimizes the browser, etc.
Edit: I have updated the example to include the current API usage.
http://timemejs.com
An example of its usage:
Include in your page:
<script src="http://timemejs.com/timeme.min.js"></script>
<script type="text/javascript">
TimeMe.initialize({
currentPageName: "home-page", // page name
idleTimeoutInSeconds: 15 // time before user considered idle
});
</script>
If you want to report the times yourself to your backend:
xmlhttp=new XMLHttpRequest();
xmlhttp.open("POST","ENTER_URL_HERE",true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
var timeSpentOnPage = TimeMe.getTimeOnCurrentPageInSeconds();
xmlhttp.send(timeSpentOnPage);
TimeMe.js also supports sending timing data via websockets, so you don't have to try to force a full http request into the document.onbeforeunload event.
The start_time is when the user first request the page and you get the end_time by firing an ajax notification to the server just before the user quits the page :
window.onbeforeunload = function () {
// Ajax request to record the page leaving event.
$.ajax({
url: "im_leaving.aspx", cache: false
});
};
also you have to keep the user session alive for users who stays long time on the same page (keep_alive.aspxcan be an empty page) :
var iconn = self.setInterval(
function () {
$.ajax({
url: "keep_alive.aspx", cache: false });
}
,300000
);
then, you can additionally get the time spent on the site, by checking (each time the user leaves a page) if he's navigating to an external page/domain.
Revisiting this question, I know this wouldn't be much help in a Chrome Ext env, but you could just open a websock that does nothing but ping every 1 second and then when the user quits, you know to a precision of 1 second how long they've spent on the site as the connection will die which you can escape however you want.
Try out active-timeout.js. It uses the Visibility API to check when the user has switched to another tab or has minimized the browser window.
With it, you can set up a counter that runs until a predicate function returns a falsy value:
ActiveTimeout.count(function (time) {
// `time` holds the active time passed up to this point.
return true; // runs indefinitely
});

Session time out using Javascript or jQuery

How can I redirect to the login page when the session has completed? The code should check that the user sits idle for some time and then does any other client side event. If it finds this condition, it should check the session time out, and if session completes, redirect to login page.
Checking for inactivity on a webpage will be like an attempt to listen multitude of event. This also means that if there is user interaction the a function (event handler) is going to be called quite a lot of times. If this handler/function is going to some ajax send/receive stuffs then it could ultimately make your user interface perform poorly.
Why not make the session expiration period short and auto log out the user after? That way if the user is truly active then most probably there will a request for a page within that time frame. You could also set up a timer based event which when fired will simply send dummy request to server to refresh the session as a way of letting the server know that the user is still active but just not ready to request another page yet. This would be the case where a user is editing a long text or something like that.
I hope it helps.
Session Logout after 5 minutes
<sctipt>
var interval;
$(document).on('mousemove', function () {
clearInterval(interval);
var coutdown = 5 * 60, $timer = $('.timer'); // After 6 minutes session expired (mouse button click code)
$timer.text(coutdown);
interval = setInterval(function () {
$timer.text(--coutdown);
if (coutdown === 0) {
alert("Session expired User successfully logout.");
window.location = "UserLogin.aspx";
}
}, 1000);
}).mousemove();
var interval;
$(document).on('keydown', function () {
clearInterval(interval);
var coutdown = 7 * 60, $timer = $('.timer'); // After 6 minutes session expired (keyboard button press code)
$timer.text(coutdown);
interval = setInterval(function () {
$timer.text(--coutdown);
if (coutdown === 0) {
alert("Session expired User successfully logout.");
window.location = "UserLogin.aspx";
}
}, 1000);
}).mousemove();
<sctipt>
<div class="timer">
Time of session display on page
</div>

Categories

Resources