Run a process with real-time output in PHP

I am trying to start a process on a web page that will return its result in real time. For example, if I start the β€œping” process, it should refresh my page every time it returns a new line (right now, when I use exec (command, output), I have to use the -c option and wait until the process ends to see the output on my web page). Is it possible to do this in php?

I am also wondering what is the right way to kill such a process when someone leaves the page. In the case of the ping process, I can still see the process running on the system monitor (which makes sense).

+54
linux php process apache real-time
Aug 15 '09 at 4:23
source share
10 answers

This worked for me:

$cmd = "ping 127.0.0.1"; $descriptorspec = array( 0 => array("pipe", "r"), // stdin is a pipe that the child will read from 1 => array("pipe", "w"), // stdout is a pipe that the child will write to 2 => array("pipe", "w") // stderr is a pipe that the child will write to ); flush(); $process = proc_open($cmd, $descriptorspec, $pipes, realpath('./'), array()); echo "<pre>"; if (is_resource($process)) { while ($s = fgets($pipes[1])) { print $s; flush(); } } echo "</pre>"; 
+69
May 26 '11 at 19:48
source share
β€” -

This is a good way to show the output of your shell commands in real time:

 <?php header("Content-type: text/plain"); // tell php to automatically flush after every output // including lines of output produced by shell commands disable_ob(); $command = 'rsync -avz /your/directory1 /your/directory2'; system($command); 

You will need this function to prevent output buffering:

 function disable_ob() { // Turn off output buffering ini_set('output_buffering', 'off'); // Turn off PHP output compression ini_set('zlib.output_compression', false); // Implicitly flush the buffer(s) ini_set('implicit_flush', true); ob_implicit_flush(true); // Clear, and turn off output buffering while (ob_get_level() > 0) { // Get the curent level $level = ob_get_level(); // End the buffering ob_end_clean(); // If the current level has not changed, abort if (ob_get_level() == $level) break; } // Disable apache output buffering/compression if (function_exists('apache_setenv')) { apache_setenv('no-gzip', '1'); apache_setenv('dont-vary', '1'); } } 

It does not work on every server on which I tried it, although I would like to advise you to look in your php configuration to determine if you need to pull your hair out trying to get this type of behavior to work on your server! Does anyone else know?

Here is a dummy example in simple PHP:

 <?php header("Content-type: text/plain"); disable_ob(); for($i=0;$i<10;$i++) { echo $i . "\n"; usleep(300000); } 

Hope this helps other people who went here along the way.

+32
May 10 '11 at 21:30
source share

try this (tested on windows + wamp server computer)

  header('Content-Encoding: none;'); set_time_limit(0); $handle = popen("<<< Your Shell Command >>>", "r"); if (ob_get_level() == 0) ob_start(); while(!feof($handle)) { $buffer = fgets($handle); $buffer = trim(htmlspecialchars($buffer)); echo $buffer . "<br />"; echo str_pad('', 4096); ob_flush(); flush(); sleep(1); } pclose($handle); ob_end_flush(); 
+5
Jul 15 '13 at 16:08
source share

A more efficient solution to this old problem using modern events on the HTML5 server side is described here:

http://www.w3schools.com/html/html5_serversentevents.asp




Example:

http://sink.agiletoolkit.org/realtime/console

Code: https://github.com/atk4/sink/blob/master/admin/page/realtime/console.php#L40

(Implemented as a module in the Agile Toolkit infrastructure)

+5
Jan 30 '15 at 20:55
source share

If you want to run system commands through PHP, the documentation is exec .

I would not recommend doing this on a site with high traffic, but marking up the process for each request is a rather complicated process. Some programs provide the ability to write your process ID to a file that you can verify and terminate the process as you like, but for commands like ping, I'm not sure if this is possible, check the man pages.

You might be better served by simply opening the socket on the port you expect to listen to (IE: port 80 for HTTP) on the remote host, so you know that everything is going fine in userland as well as on the network.

If you are trying to output binary data to the php header function and make sure you select the correct content-type and content disposition . See the documentation for more information on using / disabling the output buffer.

+2
Aug 15 '09 at 5:11
source share

First check if flush () works. If so, well, if it is not, it probably means that the web server is buffering for some reason, for example, mod_gzip is turned on.

For something like ping, the easiest method is to loop inside PHP, run ping -c 1 repeatedly and call flush () after each exit. Assuming PHP is configured to cancel when the HTTP connection is closed by the user (usually this is the default, or you can call ignore_user_abort (false) to make sure), then you don't have to worry about ping processes running either.

If you really need you to only start the child process once and display its output continuously, it can be more difficult - you will probably have to run it in the background, redirect the output to a stream, and then PHP will echo that stream back to the user alternates with regular calls to flush ().

+2
Aug 15 '09 at 5:14
source share

For use on the command line:

 function execute($cmd) { $proc = proc_open($cmd, [['pipe','r'],['pipe','w'],['pipe','w']], $pipes); while(($line = fgets($pipes[1])) !== false) { fwrite(STDOUT,$line); } while(($line = fgets($pipes[2])) !== false) { fwrite(STDERR,$line); } fclose($pipes[0]); fclose($pipes[1]); fclose($pipes[2]); return proc_close($proc); } 

If you are trying to run a file, you may need to grant execution permissions first:

 chmod('/path/to/script',0755); 
+2
Apr 01 '14 at 15:31
source share

I tried various PHP execution commands on Windows and found that they are very different.

  • Doesn't work for streaming: shell_exec , exec , passthru
  • Type of work: proc_open , popen - "type", because you cannot pass arguments to your command (that is, not working with my.exe --something , it will work with _my_something.bat ).

The best (easiest) approach:

  • You need to make sure that your exe executes the cleanup commands (see print cleanup issue ). Without this, you will most likely receive batches of approximately 4096 bytes of text, no matter what you do.
  • If you can, use header('Content-Type: text/event-stream'); (instead of header('Content-Type: text/plain; charset=...'); ). However, this will not work in all browsers / clients! Streaming will work without this, but at least the first lines will be buffered by the browser.
  • You can also disable the header('Cache-Control: no-cache'); cache header('Cache-Control: no-cache'); .
  • Disable output buffering (either in php.ini, or using ini_set('output_buffering', 'off'); ). It can also be done in Apache / Nginx / any server you use in front.
  • Compression rotation (either in php.ini or with ini_set('zlib.output_compression', false); ). It can also be done in Apache / Nginx / any server you use in front.

So, in your C ++ program, you are doing something like this (again, for other solutions see the problem with printing cleanup ):

 Logger::log(...) { printf (text); fflush(stdout); } 

In PHP you do something like:

 function setupStreaming() { // Turn off output buffering ini_set('output_buffering', 'off'); // Turn off PHP output compression ini_set('zlib.output_compression', false); // Disable Apache output buffering/compression if (function_exists('apache_setenv')) { apache_setenv('no-gzip', '1'); apache_setenv('dont-vary', '1'); } } function runStreamingCommand($cmd){ echo "\nrunning $cmd\n"; system($cmd); } ... setupStreaming(); runStreamingCommand($cmd); 
+2
Jul 29 '15 at 8:34
source share

Checked all the answers, nothing works ...

Solution Found Here

It works on windows (I think this answer is useful for users searching there)

 <?php $a = popen('ping www.google.com', 'r'); while($b = fgets($a, 2048)) { echo $b."<br>\n"; ob_flush();flush(); } pclose($a); ?> 
+1
Sep 07 '17 at 16:37 on
source share

Try changing the php.ini file set "output_buffering = Off". You should be able to get real-time output on the Use system command page instead of the exec .. command, the system will reset the output

0
Sep 15 '09 at 20:38
source share



All Articles