I have a page streaming mjpegs. I used ffmpeg to generate the mjpegs, and it uses enough CPU that I would like to only have it run when someone is actively viewing the page. My thought was to start it with exec() however, it keeps running when I leave the page, and actually starts multiple instances if I then go back to the page.
Is there a way to kill a process when someone is no longer on a page? My only thought was to use ajax to send a keep alive signal to another program on the server which would kill the process if the signal isn't recieved for > 10 seconds, however it seems like there must be a less convoluted method for doing this.
There's no way to know from PHP when a user leaves the page unless you make another request from javascript, your approach of the ajax request is a good idea. You can also use the javascript event onbeforeunload to make a request when the user unloads the page to terminate the process.
Related
I am making an AJAX call to a PHP script that takes a long time to run. Now, assume it takes 20 minutes to run. Also assume that I either refreshed or closed then opened the web page that intiated the call. My questions are:
Does my PHP scrip stop running?
If it keeps running, how can I force a response back to the page after it was refreshed?
Thanks.
************* UPDATE *************
Some are asking why I have a script that takes a long time. I think it is my fault of not explaining the following:
a. This script is only available to site admins, and is not available to the general public
b. This script will perform some heavy lifting, such as data manipulation and database related stuff, and will require a long time to run
c. I am using AJAX so that I could still return to the main page, with a spinner showing that the script is running, while the script actually runs in the back end, and the call back function will remove the spinner and display a message of either success/failure status.
No it will stop running.
You should be using a cron job instead to run a script that will take 20 minutes.
Dont forget to set the time limit to at least 20 minutes for that page!
Does my PHP script stop running?
Yes, PHP will cease execution if the browser disconnects (which it will on refresh/close). You can use ignore_user_abort(true) to prevent this, but I don't think that would be the best option for what you want.
If it keeps running, how can I force a response back to the page after it was refreshed?
No because the connection is gone, there is nothing to send a response back to. It would be more appropriate to invoke your long process as a background process when the ajax calls it, and immediately return a response, leaving the background process to work. You can use regular ajax calls to query if the process is complete (update a database for example on completion).
From the docs:
The default behaviour is however for your script to be aborted when the remote client disconnects.
My website runs simplexml commands to pull data from 2 different websites, and doesn't finish loading the page until after the functions have their responses.
This is really only 1-2 seconds, but it is noticable when regular webpages take milliseconds to load.
Since this code is already in PHP functions, how can I most efficiently load the page and execute the code after? I'm assuming that by the time the page loads, the functions will have executed as well, its just that the browser itself won't refresh and finish loading til execution completes.
Hope this makes sense to you.
Unfortunately, php runs on the server side before the page is loaded. That is what allows it to provide dynamically generated content to the page. If you want to load the page and then run the php functions, you should check out AJAX.
Ajax uses javascript to call external functions and change content on the page without a reload.
Create a webpage without calling any of these functions. Add some JavaScript to that page to make AJAX requests to PHP scripts that call the functions, then adds the returned results to the page.
You have a few options.
AJAX call -- once the important stuff loads, have JS send word to the server that it needs to do some process to complete loading. (rennekon and Dan Grossman seem to have already suggested this).
iframe similar to AJAX, but it does not require JS. Placed at the bottom of the HTML it can let the server know something needs to finish without worrying about any other rendering. (this can actually also be accomplished by any number of tags which make HTTP requests. img attacks are notorious for allowing this with vulnerable sites.)
Spawn a new thread. This is a bit more difficult/annoying, but it does not rely on user feedback to finish processing. You also may not be able to do this on most servers, but it is one way to finish processing in the background.
You can create a cron that would talk to the 2 different websites and store the data you need periodically and then when your page runs it would talk to the local version that cron stored for you taking the communication off of page render time
I have a PHP script something like:
$i=0;
for(;$i<500;++i) {
//Do some operation with files numbered 0 to 500;
}
The thing is, the script works and displays the end results, but the operation takes a while and watching a blank screen can be frustrating. I was thinking if there is some way I can continuously update the page at the client's end, detailing which file is currently being worked upon. That is, can I display and continuously update what is the current value of $i?
The Solution
Thanks everyone! The output buffering is working as suggested. However, David has offered valuable insight and am considering that approach as well.
You can buffer and control the output from the PHP script.
However, you may want to consider the scalability of this design. In general, heavy processes shouldn't be done online. Your particular case may be an edge in that the wait is acceptable, but consider something like this as an alternative for an improved user experience:
The user kicks off a process. This can be as simple as setting a flag on a record in the database or inserting some "to be processed" records into the data.
The user is immediately directed to a page indicating that the process has been queued.
An offline process (either kicked off by the PHP script on the server or scheduled to run regularly) checks the data and does the heavy processing.
In the meantime, the user can refresh the page (manually, by navigating elsewhere and coming back to check, or even use an AJAX polling mechanism to update the page) to check the status of the processing. In this case, it sounds like you'd have several hundred records in a database table queued for processing. As each one finishes, it can be flagged as done. The page can just check how many are left, which one is current, etc. from the data.
When the processing is completed, the page shows the result.
In general this is a better user experience because it doesn't force the user to wait. The user can navigate around the site and check back on progress as desired. Additionally, this approach scales better. If your heavy processing is done directly on the page, what happens when you have many users or the data processing load increases? Will the page start to time out? Will users have to wait longer? By making the process happen outside of the scope of the website you can offload it to better hardware if needed, ensure that records are processed in serial/parallel as business rules demand (avoid race conditions), save processing for off-peak hours, etc.
Check out PHP's Output Buffering.
Try to use:
flush();
http://php.net/manual/ru/function.flush.php
Try the flush() function. Calling this function forces PHP to send whatever output it has so far to the client, instead of waiting for the script to end.
However, some web servers will only send the output once the entire page is done being built, so calling flush() would have no effect in this case.
Also, browsers themselves buffer input, so you may run into problems there. For example, certain versions of IE won't start displaying the page until 256 bytes has been received.
I am looking for a way to start a function on form submit that would not leave the browser window waiting for the result.
Example:
User fills in the form and press submit, the data from the form via javascript goes to the database and a function in php that will take several seconds will start but I dont want the user to be left waiting for the end of that function. I would like to be able to take him to another page and leave the function doing its thing server side.
Any thoughts?
Thanks
Thanks for all the replies...
I got the ajax part. But I cannot call ajax and have the browser move to another page.
This is what I wanted.
-User fills form and submits
-Result from the form passed to database
-long annoying process function starts
-user carries on visiting the rest of the site, independent of the status on the "long annoying process function"
By the way and before someone suggests it. No, it cannot be done by cron job
Use AJAX to call the php script, and at the top of the script turn on ignore_ user_ abort.
ignore_user_abort(true);
That way if they navigate away from the page the script will continue running in the backround. You can also use
set_time_limit(0);
to set a time limit, useful if you know your script will take a while to complete.
The most common method is:
exec("$COMMAND > /dev/null 2>&1 &");
Ah, ok, well you're essentially asking therefore, does PHP support threading, and the general answer is no... however...
there are some tricks you can perform to mimick this behaviour, one of which is highlighted above and involves forking out to a separate process on the server, this can be acheived in a number of ways, including the;
exec()
method. You also may want to look here;
PHP threading
I have also seen people try to force a flush of the output buffer halfway through the script, attempting to force the response back to the client, I dont know how successful this approach is, but maybe someone else will have some information on that one.
This is exactly what AJAX (shorthand for asynchronous JavaScript + XML) is for;
AJAX Information
It allows you to code using client side code, and send asynchronous requests to your server, such that the user's browser is not interuppted by an entire page request.
There is alot of information relating to AJAX out there on the web, so take a deep breath and get googling!
Sounds like you want to use some of the features AJAX (Asynchronous Javascript and XML - google) have to offer.
Basically, you would have a page with content. When a user clicks a button, javascript would be used to POST data to the server and begin processing. Simultaneously, that javascript might load a page from the server and then display it (eg, load data, and then replace the contents of a DIV with that new page.)
This kind of thing is the premise behind AJAX, which you see everywhere when you have a web page doing multiple things simultaneously.
Worth noting: This doesn't mean that the script is running "in the background on the server." Your web browser is still maintaining a connection with the web server - which means that the code is running in the "background" on the client's side. And by "background" we really mean "processing the HTTP request in parallel with other HTTP requests to give the feel of a 'background' running process"
I have a process I want to run in the background of a page. The process will take a while to run, lets say a few minutes.
I have it set up so that from the page I can click on a button to start the process off, wait a bit and then it will finish and I can have the page update notifying me that the process was run successfully. I'm doing this with prototype and php.
What I want to do is have status updates while the process is running. So it could update a the page letting me know how many records have been processed so far or update a status bar or something like that.
Is this possible? I'm just not a huge JS guru and I can do the basic functionality I've already described but was wondering if it was possible to extend it to do this little extra bit as I haven't had any luck googling or looking through the docs.
With just PHP you'll pretty much end up doing polling. You'll need to spawn your long-running process in the background, and for example write to a database of file what it's progress is.
The browser can then call a different php script every x seconds, which reports back with this status.
Polling sucks though, but that's what you're stuck with, with PHP.