Simple question, but I can't seem to find the answer.
My php code takes a really long time to process because I'm generating a report from a large database. I coded an html table to display the results in a web page, but the page loads (and gets sent to clients) before my php code finishes because all the table values are empty. I run the query on phpMyAdmin and it works, but it just takes a long time. Ideas? Are there any other ways I can display the report in a table format besides seeing it in a webpage? Can I make the webpage wait until the code finishes?
There are several approaches
one is using
ob_start();
// processing
ob_flush();
flush();
the next is adding pagination, aka limiting the result size.
SELECT * FROM table LIMIT 0,10
SELECT * FROM table LIMIT 10,10
SELECT * FROM table LIMIT 20,10
of course it all depends on your code, without seeing your code there's only guessing what the reason might be
Can I make the webpage wait until the code finishes?
It's really, really difficult to write PHP code which implements asynchronous database calls - which it would need to do if the PHP script completes before the MySQL script. Just change strip out all the asynchronous handlers in the PHP code and make the MySQL calls blocking and it will not exit before the queries complete - but I very much doubt that is what your code really is doing.
but the page loads (and gets sent to clients)
This is confused too - if you're generating HTMLthen the page is laoded after the HTML is sent to the client - not before.
Simple question
No it's not - it's very confused!
The prudent way
One of the correct approaches, at least one I'd recommend, would be to, upon request from the user, add the job to a queue that is handled by a background process, for example, a PHP command line script running from a cron job. While that is going on, you can periodically request job status from the server via an AJAX call from your webpage, display progress, if you can, and present the user with the result once the job is finished. Since command line PHP scripts don't have time limits, you don't have to worry about timeouts.
Another way is what is implemented, for example, in 37signals' Highrise - they take the request add a job but display a page saying "It will be ready when it's ready," and when it is ready, they send an email to the user saying "Here's your file, come here and download."
The quick fix
To answer the question "Can I make the webpage wait until the code finishes?" – there is the set_time_limit() function that does exactly what you want.
Related
I have a PHP script which contains many database queries, and copies several database tables, and as such, it takes quite a long time to complete. The problem I am getting, is that it is timing out. However, it appears to be completed, which is what is confusing.
The script is suppose to redirect to view once completed. However, even after extending the time limit to 5 minutes, it gives me the timing out error page. However, when I check the database, all of the tables have been copied completely, indicating that the script was completed.
Am I missing something easy here? Is there a general reason it would time out as opposed to redirecting to the view? I would post some of the code, but the entire script is approximately 1000 lines of code, so it seems a bit extensive to show here.
Also, I am using CodeIgniter.
Thanks in advance for your help!
It's possible that the PHP script is not timing out, but the browser you're using has given up waiting for any result. If thats the case you'll need to handle the whole thing differently. For example, run the script in the background and report periodic updates via AJAX or something.
Think of it this way:
Your browser asks your server for a web page and waits for the results.
Your server runs your PHP script, which then asks MySQL to run a query, and waits for results.
MySQL runs the query and returns a result to PHP.
PHP does some more processing and returns a result to the browser.
At step 3, PHP may have timed out and is no longer there. MySQL didn't know that while it was working, it just did its job and then handed a result back to nothing.
At step 4, the browser may have timed out and dropped the connection. PHP wouldn't know that, so it did its job and then returned a result to nothing.
It's two separate timeouts in this example, but your query was completed either way.
I have a form which when submitted, calls a php page (sample.php)
my php page does a lot of execution, which takes around 5 mins of time. i am also printing "Executed!" on my sample.php page.
This Executed gets printed.. only after it has executed everything ( 5mins).
I want my php page to print "Executed" before it does all the processing.
How shuld i go about this?
There have been several solutions posted that use ignore_user_abort() and flush() to continue background work after a page has been delivered to the client. You should start reading the documentation on connection handling on the php web site
However, if you ask for a stable solution, I would design your application in a way that 'sample.php' (the form action) will just recieve a job, adds it to a queue (maybe a database table) and reports that the job has been added. Where another process runs in background (maybe per cron or whatever) and runs the jobs itself. Also I would create a page like 'progress.php' where the progress of a job can be viewed. The response could be json or something like this, so that it can be easily integrated into other pages or used as data feed for the javascript progress bar you've been asked for.
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 working in a tool in PHP that processes a lot of data and takes a while to finish. I would like to keep the user updated with what is going on and the current task processed.
What is in your opinion the best way to do it? I've got some ideas but can't decide for the most effective one:
The old way: execute a small part of the script and display a page to the user with a Meta Redirect or a JavaScript timer to send a request to continue the script (like /script.php?step=2).
Sending AJAX requests constantly to read a server file that PHP keeps updating through fwrite().
Same as above but PHP updates a field in the database instead of saving a file.
Does any of those sound good? Any ideas?
Thanks!
Rather than writing to a static file you fetch with AJAX or to an extra database field, why not have another PHP script that simply returns a completion percentage for the specified task. Your page can then update the progress via a very lightweight AJAX request to said PHP script.
As for implementing this "progress" script, I could offer more advice if I had more insight as to what you mean by "processes a lot of data". If you are writing to a file, your "progress" script could simply check the file size and return the percentage complete. For more complex tasks, you might assign benchmarks to particular processes and return an estimated percentage complete based on which process has completed last or is currently running.
UPDATE
This is one suggested method to "check the progress" of an active script which is simply waiting for a response from a request. I have a data mining application that I use a similar method for.
In your script that makes the request you're waiting for (the script you want to check the progress of), you can store (either in a file or a database, I use a database as I have hundreds of processes running at any time which all need to track their progress, and I have another script that allows me to monitor progress of these processes) a progress variable for the process. When the process begins, set this to 1. You can easily select an arbitrary number of 'checkpoints' the script will pass and calculate the percentage given the current checkpoint. For a large request, however, you might be more interested in knowing the approximate percent the request has completed. One possible solution would be to know the size of the returned content and set your status variable according to the percentage received at any moment. I.e. if you receive the request data in a loop, each iteration you could update the status. Or if you are downloading to a flat file you could poll the size of the file. This could be done less accurately with time (rather than file size) if you know the approximate time the request should take to complete and simply compare against the script's current execution time. Obviously neither of these are perfect solutions, but I hope they'll give you some insight into your options.
I suggest using the AJAX method, but not using a file or a database. You could probably use session values or something like that, that way you don't have to create a connection or open a file to do anything.
In the past, I've just written messages out to the page and used flush() to flush the output buffer. Very simple, but it may not work correctly on every web server or with every web browser (as they may do their own internal buffering).
Personally, I like your second option the best. Should be reliable and fairly simple to implement.
I like option 2 - using AJAX to read a status file that PHP writes to periodically. This opens up a lot of different presentation options. If you write a JSON object to the file, you can easily parse it and display things like a progress bar, status messages, etc...
A 'dirty' but quick-and-easy approach is to just echo out the status as the script runs along. So long as you don't have output buffering on, the browser will render the HTML as it receives it from the server (I know WordPress uses this technique for it's auto-upgrade).
But yes, a 'better' approach would be AJAX, though I wouldn't say there's anything wrong with 'breaking it up' use redirects.
Why not incorporate 1 & 2, where AJAX sends a request to script.php?step=1, checks response, writes to the browser, then goes back for more at script.php?step=2 and so on?
if you can do away with IE then use server sent events. its the ideal solution.
I have a PHP script that takes about 10 minutes to complete.
I want to give the user some feedback as to the completion percent and need some ideas on how to do so.
My idea is to call the php page with jquery and the $.post command.
Is there a way to return information from the PHP script without ending the script?
For example, from my knowledge of this now, if I return the variable, the PHP script will stop running.
My idea is to split the script into multiple PHP files and have the .post run each after a return from the previous is given.
But this still will not give an accurate assessment of time left because each script will be a different size.
Any ideas on a way to do this?
Thanks!
You can echo and flush() output, but that's suboptimal and rather fragile solution.
For long operations it might be good idea to launch script in the background and store/updte script status in shared location.
e.g. you could lanuch script using fopen('http://… call, proc_open PHP CLI process or even just openg long-running script in an <iframe>.
You could store status in the database or in shared memory (using apc_store()).
This will let user to check status of the script at any time (by refreshing page, or using AJAX) and user won't lose track of the script if browser's connection times out.
It also lets you avoid starting same long script twice.