Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run process with realtime output in PHP

I am trying to run a process on a web page that will return its output in realtime. For example if I run 'ping' process it should update my page every time it returns a new line (right now, when I use exec(command, output) I am forced to use -c option and wait until process finishes to see the output on my web page). Is it possible to do this in php?

I am also wondering what is a correct way to kill this kind of process when someone is leaving the page. In case of 'ping' process I am still able to see the process running in the system monitor (what makes sense).

like image 473
Maksim Vi. Avatar asked Aug 15 '09 04:08

Maksim Vi.


4 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>";
like image 102
egafni Avatar answered Oct 21 '22 00:10

egafni


This is a nice way to show real time output of your shell commands:

<?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 doesn't work on every server I have tried it on though, I wish I could offer advice on what to look for in your php configuration to determine whether or not you should pull your hair out trying to get this type of behavior to work on your server! Anyone else know?

Here's a dummy example in plain PHP:

<?php
header("Content-type: text/plain");

disable_ob();

for($i=0;$i<10;$i++) 
{
    echo $i . "\n";
    usleep(300000);
}

I hope this helps others who have googled their way here.

like image 45
Robb Avatar answered Oct 21 '22 00:10

Robb


Checked all answers, nothing works...

Found solution Here

It works on windows (i think this answer is helpful for users searching over there)

<?php
    $a = popen('ping www.google.com', 'r'); 
    
    while($b = fgets($a, 2048)) { 
        echo $b."<br>\n"; 
        ob_flush();flush(); 
    }

    pclose($a); 
?>
like image 13
Pixsa Avatar answered Oct 21 '22 00:10

Pixsa


A better solution to this old problem using modern HTML5 Server Side Events 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 Agile Toolkit framework)

like image 7
romaninsh Avatar answered Oct 20 '22 23:10

romaninsh