BACKGROUND:
Right now, in our company we have a PHP based app to automate our report building. It works like this:
- A webpage with a form generates a ini file with some configurations that is saved localy
- a PHP CLI script accepts the ini file generated on step 1 and based on it, creates a directory with documents whose data is fetched from the internet. (takes between 5 and 10 minutes to complete)
- Another web form explores the content of the folder, does some validation and shows the contents of the directory as a preview.
Between any of those steps, user input is needed and sometimes the user needs to interrupt the script 2 to correct some of the ini values.
PROBLEM:
We want to run the cli script in the web browser, so that after the user clicks a “build” button, the ini file (or an array) is generated and automatically passed to the second script. But the idea is to have that script run independently (simulating another “thread”), verbosing everything it is doing along the way in order to let the user interrupt if he needs to. Something like running the script in the command line, in which each step is verbosed.
We though using AJAX, but it waits for the server to complete its answer before printing anything in the web browser. An iFrame doesn’t work also since we can’t manipulate its src attributes and contents with javascript.
So, how can we “simulate” a command shell output? any tip n the right direction would be very appreciated.
NOTE: The script will be always used in “localhost”, no need for remote access!
SOLUTION
I ended up doing something even easier, based on the sugestions:
- Dumped the contents of the form ($_POST) to a session var $_SESSION[‘FORM’].
- Created a $_SESSION[form-complete] flag that would be set to true when user clicked the “build” button.
- If the $_SESSION[form-complete] was true, the server would show an iframe pointing to the “CLI SCRIPT” whose arguments were the previously dumped session variables.
- The CLI Script also has
ob_implicit_flush(true); ob_end_flush();
so that the output won’t be cached. - At the end of the script the $_SESSION variable is clean and the session destroyed
Advertisement
Answer
An iFrame doesn’t work also since we can’t manipulate its src attributes and contents with javascript.
You can, provided that the iframe resides on the same host as the parents pages (e.g. localhost
). AJAX naturally doesn’t support cross-domain requests either, so if you have AJAX working, iframes will follow too.
Your easiest bet will be to pipe the output to a temporary file and then have your ‘separate thread’ be an iframe/AJAX calls that retrieves the output. If it’s running on localhost, then bandwidth optimisations for this would be a bit pointless (unless the log gets really long).
A little example:
Suppose we want to run ./long_script
. This is how we can do it.
system('./long_script > /tmp/file 2>&1 &');
(pipe all output to /tmp/file, then run it in the background)Make a PHP script that does something like this (you’ll need a secure way of getting the filename, preferably a session variable, or a sanitized
$_GET
variable):<pre><?php echo file_get_contents('/tmp/file'); ?></pre><script>setTimeout("window.location.reload()", 1000);</script>
Put that PHP script in an iframe. The Javascript will cause an auto-reload every 1s.
Alternative:
You can use popen to have a process handle, fread then flush the data (set ob_implicit_flush(true)
) to the browser (so it doesn’t wait to get all the output from the process, and push it all at once).