Suppose user requests an action, the page is equipped with ajax so the request has been made through javascript and the status of task are updating every 10 seconds.
The problem is if the user close the page at this time the task would be lost?
I want the php request, continue and complete even if the user closed the page.
How can I do that?
It's tough to be sure without a more intimate explanation. You may need to investigate cronjobs though, this is typically a server specific task in which set up depends on the kind of server you're running. If you have an admin control panel through your host it may have a section for setting up such tasks.
At the very least you could potentially detect partially finished work and then finish it up after a certain amount of inactive time from the user.
The other possibility is to simply do that check every page refresh, this would be server independent, but relies on being able to unreliably finish half-done tasks whenever a page is refreshed instead of guaranteeing it gets cleaned up at a specific time.
Related
I am currently creating a stock market simulation and am working on the moment that the user logs into the simulation. I have a PHP script that will generate a certain price for a company four times and update it into my MySQL database while running. I currently have the following code:
PHP:
if (isset($_SESSION['userId']))
{
$isPlaying = 0;
while ($isPlaying <= 3)
{
$priceTemp = (rand(3300, 3700) / 100);
$sql = "UPDATE pricestemp SET price = $priceTemp WHERE companyName = 'Bawden';";
mysqli_query($conn, $sql);
sleep(1);
$isPlaying++;
}
echo '<h1>Welcome to the simulation</h1>';
}
I am aiming for these updates to happen in the background once the user has logged into the simulation. When refreshing my database every second, the updated prices are shown which is one of my objectives. However, what I would like it to do is still load the HTML onto the page (to say "Welcome to the simulation") while updating the database with every second with an updated price.
So far, when I log in, I have to wait 4 seconds before the HTML will load. In the future, I hope to have it consisently updating until a certain condition is met but when I have set an infinite loop earlier the HTML never loaded.
What do I have to do to allow the HTML to load once logged in and have the prices being generated and updated in the MySQL database in the background with no delay in either of these tasks happening?
You have a fundamental misunderstanding of how web-based requests work.
What you need to understand is that PHP is a server-side language. PHP generates any combination of HTML, CSS, JavaScript, JSON, or any other forms of data you want and sends it to your web browser when it's finished. While it's doing that, it can also manage data within a database or perform any other number of actions, but it will never send what the web browser can make use of until it finishes setting everything up. So if you're within an infinite loop, it will never finish and therefore nothing will be sent back to the web browser.
To remedy this, you need to use something called "asynchronous JavaScript", more commonly referred to as "ajax". Specifically, you first send some initial HTML to the web browser in one request and let the request end immediately. This allows the user to see something without waiting around for an indefinite period of time. Then, on the web browser end, you can use JavaScript to automatically send a second request to the server. During this second request to the server, you can perform your data processing and send back some data when you're finished to display to the user.
If you want to periodically update what you show the user, then you would repeat that second request to refresh what is shown on the user's webpage.
Any time you see some kind of "real-time" updating on a website, it's not coming from a single, persistently open connection to the web server--it's actually a series of repeated, broken up requests that periodically refresh what you see.
Broken down, standard web request workflows look something like this:
Web browser asks the web server for the webpage. Web browser waits for a reply.
Web server generates the webpage and sends the webpage to the web browser. Web server is done.
Web browser receives the webpage and shows it to the user. Web browser stops waiting for a reply.
Web browser runs any JavaScript it needs to run and requests data from the web server. Web browsers waits for a reply.
Web server processes the request and sends the requested data back to the web browser. Web server is done.
Web browser receives the requested data and updates the HTML on the webpage so the user can see it. Web browser stops waiting for a reply.
As you can see, each series of requests is 1) initiated by the web browser, 2) processed by the web server, and 3) any replies from the web server are then handled by the web browser after the web server is finished up. So each and every request goes browser -> server -> browser. If we add steps 7., 8., and 9. to the above, we will see them repeat the exact same pattern.
If you want to avoid adding JavaScript into the mix, preferring to refresh the entire page every time, then keep your data processing short. Optimize your database calls, fix your infrastructure (make sure your server and database have a LAN connection, that your hardware is good enough, etc.), make your code more efficient... do whatever you need to do to keep the processing time to a minimum.
This is all incredibly simplified and not 100% accurate, but should hopefully help you with your specific problem. The short version of all of this is: you can't show your HTML and process your data at the same time the way you're doing things now. You need to fundamentally change your workflow.
You have to do this in 2 network calls. The first network call should fetch the html. Then you have to use Javascript to fire another call to update your data. Once that api call returns it will update the html.
The scheduling model to manage the frequency of a background operation based on the frequency of requests at the front end is a very difficult problem. It's also a problem you don't need to solve. The data doesn't need to be changed when nobody is looking at it. You just need to store when the data was last looked at and apply greater deltas to older data.
I've recently finished my application and I've got a huge problem. I need to allow only 1 user to access it at a time. There is an index page accessible for every user everytime and "start" button. When user clicks start, the application locks and other ppl need to wait until the user finishes. When the user closes tab/browser, the application has to unlock automatically. Each user has 5 minutes to use my app.
I partially solved my problem, but it still doesn't work properly - on every site I set the jquery script that every 5 seconds triggers "extend.php" file on the server ($.get() function). The php file modifies time.txt file (it changs it to time()+5) and the script on the intex site checks whether (time()>time.txt content). So that when the uses closes tab/browser, the app is accessible. Obviously my app is also based on sessions (when the user closes browser, he loses access).
On some computers it simply doesn't work (it seems jquery doesnt trigger extend.php file and it makes my app accessible all the time).
So my question is: do you see any other ways to solve my problem?
The descr might be messy but I wanted to describe everything strightforward ;)
Regards.
Try using an a jQuery unload function so that when they click the close button your web browser executes one last line of script before the user exits. Example:
$(window).unload(function(){
"your php function to unlock the app here"
});
Hope this helps.
Your method is OK, it should work. Yes, node.js, or any other server side javascript can be used to do the same, but having a script triggered is by far the easiest solution. You really should focus your time to investigate further on what machines it is not working.
If it is restrained to 5 minutes, then set it to expire in 5 minutes. You can use a counter in jquery to show how much time is available. When it hits the expiration then notify the user time is up. Once time has expired or the user is finished with the app update the time.txt to time() or however you normally handle it when the app is accessible. No polling and 1 update.
You can put a LOCK on a mysql table when a user is online and unlock it when they are offline.
The only issue is if your code forgets to unlock.
I'm working with some existing PHP/MySQL code. I'm logging/tracking certain activities into a MySQL database. Certain access points are being logged. The number of times a user logs-into the system is counted. But, I need to also log the amount of time a user is logged-in, as well as the time the user is in a certain section of the Web site.
Since PHP is a stateless environment, for the most part, what's the best way to record the end-point(s); or when the user logs-out?
Note: I can't force the user to log out, as the browser can just be closed. Maybe I could just put up an AJAX timer that would count the minutes? If so, should I treat activities and time logged-in as different tables of information (MySQL)?
Edit: I forgot to mention we do have jQuery available.
Like you said, you can't force the user to logout, and you can't know for sure whether he's looking at your page or playing Pinball.
A solution would be an AJAX request every, say 5 minutes, to tell your application that the user is active. Unfortunately, if your user has locked his screen and went to play Pinball, you still don't know exactly what he is doing. Also, doing AJAX requests at intervals like this will increase server load, especially in a multi-user environment.
The best solution I think is to simply store the start_time of the user (when he logs in), then to update the end_time at every action he does, and with a session timeout.
Per example:
I log in at 5:00. Update the start_time to 5:00.
I browse to foo.php at 5:01. Update the end_time to 5:01.
I browse to bar.php at 5:03. Update the end_time to 5:03.
I go for a coffee at 5:05.
I come back at 5:15 and my session expired, I need to relogin.
So, you know I spent roughly 3 minutes on your application, since the last action I did was at 5:03 (5:03 - 5:00 = 3). Of course, you can't know exactly if it was 3 or 5 minutes. But you can assume, most of the times anyway, that if I don't do anything on your application (i.e.: execute a script, call, etc.), that I'm not using it.
Obviously, if you can capture JavaScript events like window close it's even better, or if I sign out manually: you update the end_time accordingly.
You need to capture two events.
The onCLose() event for the page and hook that into an ajax call back to your logging system.
The onClick() event for your logout button and hook it into the save ajax handler.
The onClose event will allow you to capture when either the tab/broswer is closed and the onCLick event is obvious.
Now this will not capture times when the browser dies, the machine loses power etc. so there will be instances where you will have gaps and those can be corrected by your login event handler and simply tag the last login event as logout out on the next login. This will however lead to outliers in your tracking of time spent logged in and you will need to statistically deal with those in your reporting.
You can use an extra PHP script that records the last activity and call it via ajax.
You can use javascript to monitor if the user is still active (moved mouse or pressed a key in the last 5 minutes etc.)
EDIT: Almost forgot the important part: your java script must make an ajax request eery X seconds.
So if there was no request in x+tollerance seconds you can consider the session as dead.
I have a buy.php page where user selects a product, enters some data like his name, address etc. Next he clicks on the "Buy" button to move to the Payment Gateway site for inputting his Credit Card no + CVV no etc. And at this point, without clicking on the 'Pay' button on this page, he closes the browser or his Computer gets switched off. This Transation ID is saved in Session.
How to track this situation and save it as "User Aborted" against his transaction ID in the Database in PHP?
The way we dealt with this issue was to keep the status of the transaction in the database as "incomplete" (or "aborted" in your case) from the beginning. When the payment is completed, the transaction status is changed to "completed".
You can't handle browser events (which is client-side) via php (server-side)
Use jQuery function .unload() which is supposed to be triggered on browser window closing
Documentation: http://api.jquery.com/unload/
Note: Nothing can take care about situation when Client Computer goes power-off instantly (not using Start > Switch Off or similar OS feature)
Note 2: Nothing in webpage can take care about crashed or killed browser
While you can potentially utilize Javascript to capture the browser's close event, unless you want to do something very quickly and aren't looking for any sort of feedback as to its success you might want to try a different approach.
From what you said above it would seem that you are trying to classify a given transaction as aborted, and you can do that simply by keeping track of different transaction stages in your database back-end. Have different stages for the given transaction and then set it to "aborted" if it was about to be processed and has been hung in that stage for a given amount of time.
Internally in PHP a connection status is maintained. There are 3
possible states:
0 - NORMAL
1 - ABORTED
2 - TIMEOUT
When a PHP script is running
normally the NORMAL state, is active. If the remote client disconnects
the ABORTED state flag is turned on. A remote client disconnect is
usually caused by the user hitting his STOP button. If the PHP-imposed
time limit (see set_time_limit()) is hit, the TIMEOUT state flag is
turned on.
This page will answer your question I guess.
Approach suggested by Aleks G is the best - however, as secondary measure, you may introduce some kind of 'heartbeats' between browser and server.
For example, issue AJAX requests over specified interval of time, letting server know that user is 'alive' (page is opened in his browser).
However, I repeat, this can be used only as secondary measure and you can't rely on it to set transaction status. There's no definite way to know whether user/browser is 'still there'.
In my php application, I'm using $_SESSION to track whether a user is logged in. If a user leaves any page on my site at http://mysite.com and goes to http://someotherwebsite.com, I want to automatically log them out, such that if they return to any page on http://mysite.com, they need to login again.
Is there an easy way to do this?
You cannot explicitly tell when an user leaves your site, your best bet would to be to implement a timeout on your sessions.
As most of the answers have said, you could check with the JavaScript event onbeforeunload but the user can by-pass this by disabling JavaScript or, as BalusC had pointed out, using a web browser that does not support it, such as Opera.
Therefore, I strongly believe implementing a timeout on your sessions is the best way to force a logout.
You could perform an AJAX call in the onbeforeunload event to some server side script that will kill the session.
Except for putting a timeout on your sessions - not really. The only way that comes to mind is the onbeforeunload JavaScript event that fires when the user leaves the current page, but that event doesn't know where the user is going. You could however, if you really want to do this, maybe build something based on the following hacky workaround (untested):
set an onbeforeunload event that sends an AJAX call to your server. (How to do this successfully - so the call gets through before the page gets closed - is an issue of its own, a search for "onbeforeunload ajax" on SO should yield some results.
The Ajax call would start a countdown saying that this user's session is about to die in, say, fifteen seconds.
If the user is leaving your site, the countdown applies.
If the user is going to a different page on your site, you clear any "die" countdowns when serving the next page.
This is likely to be shaky because it could happen that an Ajax request starting a countdown arrives at the server after the next page has already eliminated that countdown. But if you really need to do this, this may be a direction. Works for users with JS enabled only, of course.
A second idea how to implement this would be to put an extremely low timeout on sessions (e.g. 90 seconds), and to put an iframe on every page you serve. That iframe would then make a call to the page every 60 seconds.
This would work without JavaScript, but could create annoying clicking noises in older versions of Internet Explorer (I don't know whether that stopped in 6 or 7?)
You can't (but your sessions will time out automatically after a while ; so you could set the timeout to a short time).
From what I know about PHP (which isn't much) would your application ever know they left the site? If you go to someotherwebsite.com, your code isn't called again until they return.
Unfortunately Not Really,
This is one of the big problems with web applications. Your applications has no way of knowing that the browser has moved on to a different website.
As ChristohpeD mentions you can set the session timeout.
Just remember that your site will only refresh the time when the server recieves a post or some kind of javascript ping.
Hope That Helps