"Heartbeats" from client to server in PHP/JS - php

I am trying create a small web application that allows a user to "login" and "logout."
What I am currently having a problem with is allowing the client to send constant "heartbeats" or messages to the server to notify that it is still active.
This is more of a logical question. What I want to do is have a while(1) loop in php that checks if n number of heartbeats have been skipped. I still want the client and server to be able to interact while this loop is going on (essentially I want the server to behave as if it has a separate "check_for_heartbeats" thread.
How does one accomplish this using php? I am running XAMPP at the moment. Any help would be much appreciated.
Edit: To clarify, what I want to do is be able to catch a browser close event even on instances where the window.unload event won't fire (e.g. a client gets disconnected from the internet). In this case, having a thread to monitor heartbeats seems to be the most intuitive solution, though I'm not sure how to make it happen in php.
Edit 2: isLoggedIn() is just helper function that checks to see if a session boolean variable ($_SESSION['is_logged_in')) is set.
Edit Final: Okay, so I now understand exactly what the comments and responses were saying. So to paraphrase, here is the potential solution:
Have Javascript code to send "heartbeats" to the server. The server will add a timestamp associated with these beats.
Modify the database to hold these time stamps
Query the entire "timestamps" table (more likely a 'users' table with a 'timestamp' attribute), and see if the difference between NOW and last timestamp is greater than some threshold.
"Log off" any users passed this threshold.
The only issue is if there is just one user logged in or if all users lose connection at the same time - but in these cases, no one else will be there to see that a user has lost connection.
This is a combination of multiple responses, but I think chris's response takes care of the majority of the issue. Thank you to both chris and Alex Lunix for the helpful contributions. :D
Here is a code snippet for a better explanation
Server Side:
function checkBeats()
{
while(isLoggedIn())
{
// it's been > 30 secs since last heartbeat
if((time() - $_SESSION['heartbeat']) > 30)
{
logout();
break;
}
}
}

What i usually do is call a php file using javascript (jQuery) and update a database or whatevery you like. This question might answer yours: Whats the easiest way to determine if a user is online? (PHP/MYSQL)

You could use ajax to heartbeat a script that changes the heartbeats session variable, and just at the top of every script do this check (put it in a function and call that of course):
// it's been > 30 secs since last heartbeat
if((time() - $_SESSION['heartbeat']) > 30)
{
logout();
}
Edit:
If you want the database to reflect that status instantly instead of when they next visit the page, you'll need to use MySQL. Without using another program (such as a java program) to check the database the only thing I can think of is to add this at the top of every page (in a function that gets called of course):
mysql_query("UPDATE `users` SET `loggedin`=0 WHERE heartbeat<".time()-30);
Which would update every user, which means the accuracy of the loggedin value would be set by the frequency of page views.

Related

PHP page to execute a background process

I have a PHP script to pull user specific data from a 3rd party source and dump it into a local table, which I want to execute every X mins when a user is logged in, but it takes about 30 seconds to run, which I don't want the user to experience. I figured the best way of doing this would be to timestamp each successful pull, then place some code in every page footer that checks the last pull and executes the PHP script in the background if it was more than X minutes ago.
I don't want to use a cron job to do this, as there are global and session variables specific to the user that I need when executing the pull script.
I can see that popen() would allow me to run the PHP script, but I can't seem to find any information relating to whether this would be run as the visitor within their session (and therefore with access to the user specific global or session variables) or as a separate session altogether.
Will popen() solve my problem?
Am I going about this the right way or is there a better method to execute the script at intervals while the user is logged in?
Any help or advice is much appreciated, as always!
Cheers
Andy
Maybe an idea to put the session data also in a table.
That way you can easily access it from your background process. You only have to pass the session_id() or the user id as argument so the process knows which user it is currently processing.
No, because PHP still needs to wait on the process started by popen() before it can exit
Probably not, because the solution doesn't fit the architectural constraints of the system
Your reasoning for not using a cron job isn't actually sound. You may have given up on exploring that particular path too quickly and drawn yourself into a corner with trying to fit a square peg in a round hole.
The real problem you're having is figuring out how to do inter-process communication between the web-request and the PHP running from your crontab. This can be solved in a number of ways, and more easily then trying to work against PHP's architectural constraints.
For example, you can store the session ids in your database or some other storage, and access the session files from the PHP script running in your crontab, independently of the web request.
Let's say you determine that a user is logged in based on the last request they made to your server by storing this information in some data store as a timestamp, along with the current session id in the user table.
The cron job can startup every X minutes, look at the database or persistence store for any records that have an active timestamp within the given range, pull those session ids and do what's needed.
Now the question of how do you actually get this to scale effectively if the processing time takes more than 30 seconds can be solved independently as well. See this answer for more details on how to deal with distributed job managers/queues from PHP.
I would use Javascript and AJAX requests to call the script from the frontend and handle the result.
You could then set the interval in JavaScript and send an AJAX-Request each interval tick.
AJAX is what you need:
http://api.jquery.com/jquery.ajax/
The use the method "success" to do something after those 30 seconds.

Not allowing access to the specific webpage if it is opened by the other person at the same time

I have developed a website in which server side coding is done through PHP and I am using MySQL database. There is a specific page on my site that should be opened only once at a time, that is, if it is opened by one person at the same time, the second person should get a message "This page is opened by someone, you can't use it at this time" I thought of a logic that I store timestamp in the database and compare the time from the database and if it's same as that time then it means the page is opened by the other person so access should be restricted. But I don't find this logic reliable. Could there be any other logic that could be implemented?
Obviously this is quite an open question and impossible to give a complete solution to without actually seeing your database/code.
However, here would be a pretty stable logic:
User attempts to access current page.
1) PHP checks DB if session_on_page is not Y.
1a) If Y: Error Message, page in use.
1b) If not Y allow user to access and set session_on_page_user to the users login id or username etc.
2) On page load, start AJAX session that re-logs Y every 5 seconds along with current username.
2.1) Using JavaScript, check for onunload and run a AJAX function that sets session_on_page to N and also wipes session_on_page_user.
That process will be fine if it's simply for viewing data. If there's also any forms/edits being made whilst on the page I would suggest hashing the current time along with user name to create a fairly secure hashkey that is unique to that user and compare it against server time when performing any updates. You may want to go even more secure than this depending on your case scenario. You could use PHP sessions to double check also and potentially even some Apache handling.
Like I said, it's quite a broad question so we can only really give suggestions to logic.

Communication between web page and php script triggered from this web page

I have here an myAction function in some controller. And it has one class instance:
public function myAction() {
...
$myAnalyzer = new Analysis();
$myAnalyzer->analyze();
...
}
Let say this function analyze() takes 10 mins. That means it blocks my.phtml 10 mins, which is unacceptable. What I want is to render my.phtml first and then to show intermediate result from analyze() on my.phtml.
function analyze() {
...
foreach($items as $rv) {
...
...
// new result should be stored in db here
}
}
As far as I know, it's impossible, for there is just one thread in PHP. So I decided to ajax-call from my.phtml to run myAnalyzer instance.
First question: is that right? Can I do it in myAction() without blocking?
OK, now I run myAnalyzer using some script, say worker.php, from my.phtml with the help of javascript or JQuery.
Second question: how can I know when each foreach-loop ends? In other words, how can I let worker.php send some signal (or event) to my.phtml or zend framework. I do NOT want to update my.phtml on a time basis using javascript timer. That's all that I need to know, since intermediate data is supposed to be stored in DB.
Third question: the myAnalyzer muss stop, when user leaves pages. For that I have this code.
window.onbeforeunload = function(e) {
// killer.php kills myAnalyzer
};
But how can javascript communicate with myAnalyzer? Is there something like process-id? I mean, when worker.php runs myAnalyzer, it registers its process-id in zend framework. And when user leave page, killer.php stops myAnalyzer using this process-id.
I appreciate the help in advance.
First Q.: Yeah, I'm afraid that is correct.
Second Q.: I do not understand what do you mean here. See code example below
foreach($data => $item) {
...
}
//code here will be executed only after foreach loop is done.
Third Q.: Take a look at this page. You can set this to false (But I suppose it is already like that) and send something to client from time to time. Or you can set it to true and check if user is still connected with connection_aborted function. What I mean here is that you can run your worker.php with ajax and configure your request so browser will not disconnect it because of timeout (so connection will be kept while user stay on page). But it will be closed if user leave the page.
EDIT:
About second question. There are few options:
1) you may use some shared memory (like memcached, for instance). And call server with another ajax request from time to time. So after each loop is ended - you put some value into memcached and during request you can check that value and build response/update your page based on that value
2) There is such thing like partial response. It is possible to get some piece of response with XMLHTTPRequest, but as I remember - that is not really useful at this moment as it is not supported by many browsers. I do not have any details about this. Never tried to use it, but I know for sure that some browsers allow to process portions of response with XMLHTTPRequest.
3) You can use invisible iframe to call your worker.php instead of XMLHTTPRequest. In this case you can send some piece of where you can put a javascript which will call some function in parrent window and that function will update your page. That is one of Long-polling COMET implementations if you want to get some more information. There are some pitfalls (for instance, you may need to ensure that you are sending some specyfic amount of symbols in response in order to get it executed in some browser), but it is still possible to use (some web browser chats are based on this).
2) and 3) is also good because it will solve your third question problem automatically. At the same time 1) may be simpler, but it will not solve a problem in third question.
One more thing - as you will have long running script you must remember that session may block execution of any other requests (if default file based PHP session is used - this will happen for sure)

Detecting If User Has Signed Out Of Chat

I have made a simple chat application in PHP/Ajax/MySQL.
I am regularly calling these two methods-
setInterval("GetChatParticipants()",5000);
setInterval("GetChatMessages()",1000);
Now as per client design, there's no Logout or Sign Out button, so I want to detect when user closes the browser and at that time I have to delete the participant record from the database. I dont want to use onbeforeunload as Chrome refuses to accept Ajax requests on window unload event.
So I am thinking of implementing in Ajax by making repeated reqests. But the question is how exactly shall I do that. Shall I update the Participant table with last_active_time and if the difference between current time and that last_active_time is , say, more than 10 min, then I should delete the user? Is it a practical solution or could there be a better one?
You have the best solution IMO. In Javascript create a "ping" function that pings every minute / two minutes etc with a session ID unique to that browser/session. Have a sessions table on your server and update when you get a ping. Have another script that looks for entries that have not been pinged for long periods and close the sessions.
I've had this structure running for thousands of concurrent users on one site, and I had to drop the ping down from 1 minute to every 2 minutes when load got heavyish (that was on 2 load balanced servers while running the rest of the site too). Obviously you make your ping approx 45% of the time-out time (so if one fails, a second should hit). It's a simple process that can handle the load.
Edit: don't use "setInterval" for the ping, but user "setTimeout" when each ping either returns or fails. Otherwise, with setInterval, if your server gets too loaded then the pings queue, never respond and queue some more. You get a meltdown of the server as all server sockets are used, then you can't connect by ssh to fix it... not a moment I was proud of.
Yes it is practical solution and then only one you can rely on, so, no matter what else you use in addition to that, this one final check should be in your logic at all times. Said that, combining several methods will give you more possibilities to detect user leaving early. Add onbeforeunload for browsers that support it. Add "log out" button for clients coming from insecure location that want to log out right now when leaving PC and finally, check for inactivity.
Yes, it is practical solultion. The only difference is where to store information about user ping. You can do it in database or in key-value storage like memcached. I prefer the second one as I think it takes lesser resources.

How to reset a timer every minute if there is no query to the database?

I have a basic server in PHP and from the mobile device I send data and save the server every 1 minute.
But when ever my mobile phone loses the connection, I would like to set a counter on the server and if the mobile does not insert anything the database longer than 2 min. I would like to call a function in the server saying that your mobile lost connection. Every time the mobile phone sends the data to the server, timer will be reset.
I am not familiar to PHP but I searched and couldn't find any similar things. I am sure there must be an easy way of doing it. setting a listener or creating a count down timer.
You can't set a timer in your PHP code as it runs only when a client requests a page.
As you doesn't have an access to CRON jobs, you can't do it from CLI side either.
However, some webservices allow you to periodically call a page of your choice, so you can save() on every http://something/save.php call. Take a look at http://www.google.fr/search?ie=UTF-8&q=online+cron for more informations.
Note that if someone get the save() url, he can easily overload your server. Try to secure it as most as possible, maybe with a user/password combination passed as parameters.
Finally I got it worked. What I learned is that the server cant do anything if there is no request:) So I created a timestamp field in the database and update the current time with the request. Of course before updating the field gets it and compare it with the current time and see when was the last request. and find out the time difference. if the time difference bigger than 2 min change the position. I hope this helps other people as well.

Categories