3

How would I execute a shell script from PHP while giving constant/live feedback to the browser? I understand from the system function documentation:

The system() call also tries to automatically flush the web server's output buffer after each line of output if PHP is running as a server module.

I'm not clear on what they mean by running it as a 'server module'.

Example PHP code:

<?php

system('/var/lib/script_test.sh');

Example shell code:

#!/bin/bash

echo "Start..."
for i in {1..10}
do
        echo "$i..."
        sleep 1
done
echo "Done."

What this does: It will wait about 10 seconds and then flush to the output buffer.

What I want this to do: Flush to the output buffer after each line of output.

Highway of Life
  • 22,803
  • 16
  • 52
  • 80
  • server module = PHP embedded inside the webserver (e.g. mod_php), and not running in 'cgi' mode. – Marc B Mar 20 '12 at 17:37

2 Answers2

2

This can be done using popen() which gives you a handle to the stdout of whatever process you open. Chunks of data can be sent to the client using ob_flush(), the data can be displayed using an XHR.

rook
  • 66,304
  • 38
  • 162
  • 239
  • Of course, the browser is under no obligation whatsoever to DISPLAY it as it comes in. Really the best thing would be to use ajax polling or something and actually run the process in a non-blocking manner. – Tyler Eaves Mar 20 '12 at 17:38
  • @TylerEaves, good thoughts. Although I'm using an AJAX call to load the PHP page that is running the shell script, so if I can constantly flush using `popen()`, that would be ideal for my situation. – Highway of Life Mar 20 '12 at 18:08
  • The way I did this in an app I implemented (not PHP though) was to assign a job id in the outer page, and then I had a table with the structure jobid / message / timestamp (unix integer style). For each line/group of output I insert into the message table. Every second (this was an intranet app so latency was low). I polled via ajax, passing in the job id and the timestamp of the last message processed, and returned a json array of timestamps and text. Prepended the text on to my message div. Done. Simple. Would work for multiple users. – Tyler Eaves Mar 20 '12 at 18:12
  • @Highway of Life Yep thats the idea. – rook Mar 20 '12 at 18:12
  • The XHR in Internet Explorer will not let you read a partial response and so in IE, you will only get the info on the page when the shell script has completely finished. See: http://css.dzone.com/articles/partial-xmlhttprequest – MrCode Mar 20 '12 at 18:57
2

One option is to write to a file in the shell script, on each step to say where it's up to. On your web page, use an ajax call every X seconds/minutes. The ajax call will call a PHP script which reads the status file and returns the status or completed steps.

The advantage to this approach is the page live information will be available to multiple visitors, rather than just the one that actually initiated the shell script. Obviously that may or may not be desirable depending on your needs.

The disadvantage of course is the longer the ajax interval, the more out of date the update will be.

MrCode
  • 63,975
  • 10
  • 90
  • 112