Java script, PHP - javascript

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.

Related

IE resubmitting authentication header on failed login

I am supporting an application that uses basic authentication and is working mostly correctly, but on IE it is sending the authentication header twice when the authentication attempt fails.
var authorizationBasic = btoa(stUsername + ":" + stPassword);
loginRequest.open("POST", stUrl, true,stUsername, stPassword);
loginRequest.setRequestHeader("WWW-Authenticate", "Basic "+authorizationBasic);
loginRequest.withCredentials = true;
loginRequest.onreadystatechange = function () {
if (loginRequest.readyState == 4){
... some logic....
}
}
loginRequest.send();
This code is working fine on other browsers, but IE uses 2 authentication attempts every time the user makes the call.
When I get to the first call in the onreadystate it already has sent the duplicated headers. Anyone knows how to fix this?
Thank you,
Update 1: checking the expected behavior the browser is supposed to send an opening request without the credentials:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication
And on the 401 error is supposed to answer back with the credentials, this is the behavior I'm seeing on Chrome using fiddler, but IE sends the credentials on both requests causing the double hit to the login attempts counter. Is this a bug, or is there any way to modify this behavior?
After much searching I was able to find a hacked solution to this, please don't judge me for it and let me know if you find something better. I still think this is an IE bug and it might get fixed in the future.
var authorizationBasic = btoa(stUsername + ":" + stPassword);
document.execCommand("ClearAuthenticationCache", false); (1)
loginRequest.open("HEAD", vUrl, true,"whatever","blah"); (2)
loginRequest.setRequestHeader("WWW-Authenticate", "x-Basic "+authorizationBasic);
loginRequest.setRequestHeader("Authorization", "Basic "+authorizationBasic); (3)
loginRequest.withCredentials = true;
loginRequest.onreadystatechange = function () {
if (loginRequest.readyState == 4){
if (loginRequest.status == 200) {
var dummyReq = fGetRequest();
dummyReq.open("HEAD", vUrl, false,stUsername, stPassword);
dummyReq.setRequestHeader("WWW-Authenticate", "x-Basic "+authorizationBasic); (4)
window.location.href = vUrl;
Here's how it works:
This is the part that I hate the most, it clears authentication information of ALL open sessions on IE, have to use it with care, when I wasn't using it I was getting weird results, so I'm trying to modify my log out procedure to avoid the use of this instruction.
IE sends this username and password on the first request (the one that is supposed to have no authentication information), you can put whatever fake information here, just be sure you don't use a real username. If we don't send this information we'll get the login prompt.
Here goes the real authentication information, the status of the request on the readystatechange event will depend on this information.
After you have checked credentials do the regular login requests, if you don't do this you will get the login prompt.
I'm still using the regular authentication method with all other browsers. If you know of a better solution, please let me know.

Sending Ajax Call When User Exits

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>

Simple form submission with Firebase; can I detect when offline?

I'm using Firebase perhaps slightly unconventionally -for simple form submission. Submission of my website's contact form simply results in:
ref.push({name:'dr foo', email:'1#2.com', message:'bar'}, myCallback);
The Firebase is hooked up to Zapier to send the site owner an email. All works well, but I'd like to be able to handle the user loosing their connection. When Firebase can't reach the server I'd like to display: "Please check your connection", or a similar message when the user hits the send button. The "Thanks, we'll be in touch"-type message should only be displayed on a successful write.
At first I tried including an if (error) branch in the callback, but of course disconnection is not something that Firebase considers an error as it "catches up" when it can.
I also tried the code in the docs which monitors .info/connected. While this wouldn't display a message on a form submission attempt, I was thinking I could instead display a warning if disconnected. The sample worked intermittently (Chrome 39, Firefox 30, Linux Mint), but the lag between disconnection and the event firing means it's probably not suitable for this case.
Is what I'm trying to do possible?
It indeed seems that the .info/connected values only changes once some other data transfer occurs (and fails).
The only way I can come up with is by using the transaction mechanism with applyLocally set to false. E.g.
function testOnlineStatus() {
var ref = new Firebase('https://your.firebaseio.com/');
ref.child('globalcounter').transaction(function(count) {
return (count || 0) + 1;
}, function(error, committed, snapshot) {
if (error) {
alert('Are you offline?');
}
}, false /* force roundtrip to server */);
}
setInterval(testOnlineStatus, 2000);
This one triggered for me after about 15 seconds.

Removing someone from a user hash on navigating away from a page / page close

I'm building a Node.js / Socket.io project.
I have a hash of Users based on their websocket id. When a user makes the following request i'd like to add them to a group of users viewing that page.
app.get('/board/:id', function(req, res){}
I'd like to keep something like
Browsing = {
username : id,
username : id,
...
}
However i'm unsure how to remove a user lets say if they navigate off the page. Is there some kind of function that gets called upon page leave?
Partial Solution:The following seems to do the trick on Chrome:
$(window).unload(function(){
var username = $('#username').text();
var pid = currentProject;
var data = {
username: username,
id : pid
}
socket.emit('leaving-page', data);
})
... Is there some kind of function that gets called upon page
leave? ...
Yes, but it is not reliable.
The way the people keep track of who is online and who isn't, is usually like this:
Add the time when the user last refreshed/visited a page
set a limit to you consider them offline
You could intercept the event which corresponds to leaving a page. There are several ways to do it, have a look at the following links and let me know if any suits your needs and if I can answer any more explicit questions about them:
Intercept page exit event
Best way to detect when a user leaves a web page?
jquery unload
with the last link you could do something like this:
$(window).unload(function() {
//remove the user from your json object with delete json_object[key];
});
Hope this helps.
Since you're using Socket.io, the server will know when the user has left the page because the socket will be disconnected. Simply listen for the disconnect event.
io.sockets.on('connection', function (socket) {
...
socket.on('disconnect', function () {
// The user on `socket` has closed the page
});
});
Better yet, take advantage of namespaces and let Socket.io handle all of the connection/disconnection (it's doing it anyway -- no need to duplicate effort).
On the client,
socket = io.connect('http://example.com/pagename');
pagename need not point to a valid URL on your domain – it's just the namespace you'll use in the server code:
io.sockets.clients('pagename')
Gets you all of the clients currently connected to the pagename namespace.

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