Check if user closed the page in PHP? - javascript

I made a chat using PHP and JavaScript chat and there is a disconnect button which removes user from the chat removing him from user list first. But if the user closes browser then he will remain in the user list. How do I check if he left?
This must be done without putting any handles on page closing in JS because if user kills the browser then he will remain in chat.
By the way , JS script always sends a request to the PHP page which constantly checks for new messages in a loop and when there are some, the script prints them out and exits. Then it repeats all over again.
EDIT : How do I make a heartbeat thing in PHP? If a user closes the page the script execution will be terminated therefore we won't be able to check if the user is still connected in the same script.

Sorry, there is no reliable way of doing this, that's the way HTTP was built - it's a "pull" protocol.
The only solution I can think of is that "valid" and logged in clients must query the server in a very small interval. If they don't, they're logged out.

you could send a tiny ajax call to your server every 5 seconds. and users that doesn't do this aren't in the room any more

You answered your own question: if you don't detect a request for new messages from a user over a given length of time (more than a few seconds), then they left the room.
The nature of HTTP dictates that you need to do some AJAX type of communication. If you don't want to listen for the "give me more messages" request (not sure why you wouldn't want to), then build in a heartbeat type communication.

If you can't modify the JS code for some reason, there really is little you can do. Only thing you can do with PHP is to check if there's been for example over 15 minutes from the last activity, the user has left. But this is in no way a smart thing to do – a user might just sit and watch the conversation for 15 minutes.
Only proper way to do is using AJAX polling in set intervals if you want to do it reliably.
You noted that a user polls the server for new messages constantly, can't you use that to detect if user has left?

Maintain a list of active users on the server, as well as the last time they connected to the chat to request new messages.
When a user connects to check for messages update their time.
Whenever your code runs iterate through this list and remove users who haven't connected in too long.
The only failure is that if the number of users in the channel drops to zero, the server wont notice until someone comes back.

To address your edit, you can ignore client termination by using ignore_user_abort.

Using javascript u can do the following :
<script type="text/javascript">
window.onunload = unloadPage;
function unloadPage()
{
alert("unload event detected!");
}
</script>
Make the necessary ajax call on the unloadPage() function to ur PHP Script

Request a PHP script that goes a little something like this, with AJAX:
register_shutdown_function("disconnect_current_user");
header('Content-type: multipart/x-mixed-replace; boundary="pulse"');
while(true) {
echo "--pulse\r\n.\r\n";
sleep(2);
}
This way, you won't constantly be opening/closing connections.

The answers to all the questions asked by the OP are covered in the section in the manual about connection handling:
http://uk3.php.net/manual/en/features.connection-handling.php
No Ajax.
No Javascript.
No keep alives.
C.

Related

Differentiate browser close event and logout

1) I need the following requirement to be satisfied:
Client's request(Long running process) should wait till the server is serving the request.
Current solution:
Client initiates the request followed by ping request every 5 sec to check the request status and
with that also maintains the session.
2) If the client moves to other tab in the application and comes back, The client should still show the process status and server should continue working on the request.
3) If the client closes the browser or logs out, the server should stop the process.
PS : Need the functionality for all the browsers after IE-9,Chrome and Firefox.
There are many ways to skin a cat, but this is how I would accomplish it.
1, assign unique identifier to the request (You most likely have done this as you're requesting the ready state every few seconds).
Set a member of their session data to the unique ID.
Set all your pages to load the JS needed to continually check the process, but the JS should NOT use any identifier.
In the script that parses the ajax request, have it check the session for the unique identifier, and update an internal system (file or database) with the time of the last request and the unique identifier.
and push back details if there are details to be pushed.
In another system(like a cron system) or within the process itself(if in a loop for example) have it check the same database or file system that gets updated with the timestamp for the unique identifier and the last timestamp. If the timestamp is too old, lets say 15 seconds (remember page load times may delay the 5 second interval), then kill the process if cron'd, or suicide the process if within the process script itself.
Logout will kill the session data, thus making the updating of the table/file impossible(and a check should be there for this) and that will make it so that in the next few seconds from logout, the process stops.
You will not be able to find a reliable solution for logout. window.onbeforeunload will not allow you to communicate with the server (you can only prompt the user using only the built-in dialog, and that's pretty much it). Perhaps, instead of finding a solution on capturing logout/abandon, add some logic to the server's process to wait for those pings (maybe allow 30 seconds of no-comm before abandoning); that way you're not wasting server's cycles that much and you still have the monitoring working as before.

Send data to client page from mysql database without refreshing page (timeout)

I created a tabulation system for beauty pageants that show judges score on a projector. I created a presentation page for that using Codeigniter.
The HTML from that presentation page is purely written in Javascript. The page refreshes each second to get real-time data sent by the judges.
The not-so-cool thing about this logic is that when the page writes a lot of data, the page blinks every second. So the refreshing of the page is noticeable and somewhat disturbing.
This is a snippet of the code I'm working on.
$(document).ready(function() {
getJudgesScore();
setInterval(function(){
if (getNumFinalists() == 0)
getJudgesScore();
else {
window.open ('presentationFinalists','_self',false)
}
},1000);
});
You can imagine how much data is being sent and received every time this code is executed.
To sum this up, what I want to accomplish is instead of the client asking for data every second, the server initiates the connection every time a new data is saved to the database. Thank you for taking your time reading my concern.
This might help you to take necessary data from mysql server and send to client page.
Timer jquery run for after perticular time of interval.
<script src="../JS/Timer/jquery.timer.js"></script>
var timer = $u.timer(function() {
getJudgesScore();
});
timer.set({time: 1000, autostart: true});
refer this link also
https://code.google.com/p/jquery-timer/source/browse/trunk/jquery.timer.js?r=12
What you are attempting is a tricky -- but not impossible -- proposition.
#Chelsea is right -- the server can't genuinely initiate a connection to the client -- but there are several technologies that can emulate that functionality, using client connections that are held open for future events.
Those that come to mind are EventSource, Web Sockets, and long polling... all of which have various advantages and disadvantages. There's not one "correct" answer, but Google (and Stack Overflow) are your friends.
Of course, by "server," above, I'm referring to the web server, not the database. The web server would need to notify the appropriate clients of data changes as it posts them to the database.
To get real-time notification of events from the MySQL server itself (delivered to the web server) is also possible, but requires access to and decoding of the replication event stream, which is a complicated proposition. The discovered events would then need to result in an action by the web server to notify the listening clients over the already-established connections using one of the mechanisms above.
You could also continue to poll the server from the browser, but use only exchange enough data via ajax to update what you need. If you included some kind of indicator in your refresh requests, such as a timestamp you received in the prior update, or some kind of monotonic global version ID such as the MySQL UUID_SHORT() function generates, you could send a very lightweight 204 No Content response to the client, indicating that the browser did not need to update anything.

Wait until a callback address is called

I am programming an educational web in PHP and JS and I interact with another webpage that corrects for me some programming exercises.
I don't know when this correction will finish, but this correction webpage calls a given address when the correction is available.
Is it possible to wait for that result with PHP or JS and then do some stuff (not just showing the result to the user), even if the user closes the tab?
Thanks in advance.
STEP BY STEP explanation:
A student is trying to do a programming exercise. The statement of the exercise is shown, as well as other details to complete it.
When he thinks he has reached a solution, he uploads his code. Then, he can wait (or not) for the correction to finish.
My web page uploads then the code file (with other files as well as an address to callback when it finishes) to the corrector webpage.
I keep waiting until the callback is made.
When the correction is finished, I do some stuff like assigning a grade to the student and, if he/she stayed on the same page, he/she can see details of the correction.
The correction is done by another webpage and I don't know when it would finish, but when it finishes it calls a given adress (for example: www.example.com/ex1sub1usr1 ).
The doubts are between step 2 and 3. It is possible to do all this process with PHP/JS? If not, what are the alternatives?
Updated Answer
Create a PHP script on your server which updates your grade database when visited with a specially formulated URL, eg. http://yourserver.com/update.php?user=2429&sub=1&ex=1
specify this as the target URL when you submit for correction
if you are restricted to your /ex1sub1usr1 format then just use regex to parse the URL
When user refreshes (or returns to your site) the data should be appropriately pulled from your PHP backend
For bonus points, you could have your submission screen (or the entire website) intermittently poll another PHP script URL on your server (with XHR) for an "updated" flag, and live update the page.
Considerations
Your only major concern will then be ensuring that the form data (ie. their code) is submitted completely. Consider using XHR to submit your form data and temporarily enabling a window closure warning until upload is complete.
Original "Answer"
Since there isn't much information to go by here, I will have to make a few assumptions:
you presumably can't reliably spawn a process to watch the associated results address
you don't need to notify the user immediately (push notifications), but they need eventually see their result, eg. when they return to your page
results stay around for a while
as you mention, this must work even if the user closes the tab
Given this scenario, I would merely check the results page when the user returns to your site.
Just store the results address in session vars - either via PHP or a cookie - then when the user returns you can perform any unfinished checks and update accordingly.
NB: Should further information surface in the question I will gladly provide further details
You can perform all necessary actions on a script behind the given address that is called by the remote website after the excersises have been corrected.
It is absolutely not possible to show/do anything on client side if the user has closed the tab.

Triggering a DB call on browser leaving current page?

I've got an application that I intend to set a lock flag in my database that would exclude others from viewing that same page if set.
However, once set - I have no idea how to "unset" it. I could make it up to the user to unset the flag, but that seems unnecessary.
I'd want to simply look for the browser to leave the page, make a call to the database, and unlock the page.
How does one do this "type" (not looking for the exact way) of thing with JSF/Javascript/jQuery (all options)
There's really not a reliable way to do this, that I've seen anyway.
You can use the browser's onbeforeunload event to tell the server, "Hey I'm leaving the page now.". The issue is you can't actually block the page from unloading. If the user is actually closing the browser, any open sockets are going to be closed immediately. Your web server may or may not get the request in time. I've had very flaky results with this approach.
One approach that might work is to employ some sort of timeout mechanism. The page would ping the server every 30 seconds or what not, saying "I'm still here." If the server did not get this update after a few minutes, it would invalidate the session and free up that document. Perhaps this could be optimized by checking for the last ping when someone new came along. One issue with this is if someone left the page, the next user might have to wait a minute or two before they could go to the page. You'd then have to find a ping frequency that doesn't flood your server with traffic, but also doesn't make the next user have to wait too long.
It's also possible to combine these two methods. When the user leaves the page, trap the onbeforeunload event and immediately invalidate the session. However, if it didn't work, the session would time out after a minute of not being pinged.
Are there better solutions?
If you really need to lock a document in a web app so multiple users can't edit it, you might want to investigate your overall design. Are you afraid of users clobbering data? If so, maybe employ a mechanism that can resolve merge conflicts, or detect if both sets of changes can be combined.
If you wanted to go truly Web 2.0, you could design something similar to Google Docs, where changes appear live as they're made. No need for a Save button anywhere!
Sending a "keep-alive signal" might be an option. Something along these lines on the frontend side, combined with session cookies.
setInterval(function() {
var img = new Image();
var src = "http://examle.com/keepalive.gif?cachebuster=" +
Math.ceil(Math.random() * 10000 );
}, 1000);

How to detect browser closing?

In my web app, when a user logs in, I add his Id to a vector of valid Ids in the servlet, when he logs out, I remove his Id from the vector, so I can see how many current users are active, if a user forgets to log out, my servelt generated html has :
<meta http-equiv="Refresh" content="30; url=My_Servlet?User_Action=logout&User_Id=1111">
in the tag to automatically log him out.
But I've noticed many users are there for ever, never logged out. I found out why, by closing their browsers, they never manually or automatically logged out, so their user Ids will never be removed from the valid user Ids vector.
So, my question is : how do I detect users closing their browsers, so my servlet can remove their Ids from the vector ?
I see some light at the end of the tunnel, but there is still a problem, my program has something like this :
Active User List :
User_1 : Machine_1 [ IP_1 address ]
User_2 : Machine_2 [ IP_2 address ]
User_3 : Machine_3 [ IP_3 address ]
...
How do I know, from the session listener, which user's session has ended and therefore remove him from my list?
I was hoping when the session ends, the HttpServlet's destroy() method would be called and I can remove the user Id in there, but it never gets called when user closes his browser, why? And is there any other method in the HttpServlet that gets called when a session closes?
There is no way to know on the server-side (unless you are using some JavaScript to send a message to the server) that the browser has closed. How could there be? Think of how HTTP works - everything is request and response.
However, the application server will track when Sessions are active and will even tell you when a Session has been destroyed (such as due to time-out). Take a look at this page to see how to configure a HttpSessionListener to receive these events. Then you can simply keep track of the number of active sessions.
The number of active sessions will lag behind the actual number of current users, since some period of (configurable) time has to elapse before a session is timed out; however, this should be somewhat close (you can lower the session-timeout to increase the accuracy) and it is a lot cleaner and easier than 1) tracking Sessions yourself or 2) sending some asynchronous JavaScript to the server when a browser is closed (which is not guaranteed to be sent).
I suggest you remove the ID when the Servlet engine destroys the session. Register a HttpSessionListener that removes the user's ID when sessionDestroyed() is called.
Diodeus's idea will only help you detect that the session is over more immediately.
in JavaScript you can use the onbeforeclose event to pass a call back to the server when the user closes the browser.
I typically use a synchronous Ajax call to do this.
I had to do that recently, and after some searches, I found some solutions on the Net... all of them non working universally!
onbeforeclose and onclose events are used for this task. But there are two catches: they are fired when the user reload the page or even just change the current page. There are tricks to see if the event is actually a window/page/tab closing (looking at some Dom properties going haywire on closing event), but:
They are browser dependent
The tricks are undocumented, thus brittle
And actually they vary along the browser version/update...
And worst of all, these events are now ignored by most modern browsers, because they have been abused by rogue ads popping out windows when browser was closing. They are not fired in Safari, Opera, IE7, etc.
As pointed out, most Web applications with login destroy the user session after a while, eg. half an hour. I was asked to logout on browser closing to free faster a precious resource: licenses. Because users often forget to log out...
The solution I gave was to ping with an Ajax request (sending the user ID) the server on regular intervals (say 1 minute). If the server receives no ping for, say, 3 minutes, it disconnect the user.
There is no foolproof way to do what you're trying to do, but both sblundy and Diodeus have plans that will cover most circumstances. There is nothing you can do about someone who turns off Javascript in their browser, or their internet connection goes down, or their power goes out. You should just cull sessions after a certain period of inactivity (which I think is what sblundy's suggestion of listening for session destruction will do).

Categories

Resources