79 votes

Exécution d'un processus avec sortie en temps réel en PHP

J'essaie d'exécuter un processus sur une page Web qui renverra ses résultats en temps réel. Par exemple, si je lance le processus 'ping', il devrait mettre à jour ma page chaque fois qu'il renvoie une nouvelle ligne (actuellement, lorsque j'utilise exec(command, output), je suis obligé d'utiliser l'option -c et d'attendre que le processus se termine pour voir la sortie sur ma page web). Est-il possible de faire cela en php ?

Je me demande également quelle est la manière correcte de mettre fin à ce type de processus lorsque quelqu'un quitte la page. Dans le cas du processus 'ping', je suis toujours en mesure de voir le processus en cours d'exécution dans le moniteur système (ce qui est logique).

105voto

Erik49 Points 464

Cela a marché pour moi :

$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>";

39voto

Robb Points 131

C'est une bonne façon d'afficher la sortie en temps réel de vos commandes shell :

<?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);

Vous aurez besoin de cette fonction pour empêcher la mise en mémoire tampon de la sortie :

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');
    }
}

J'aimerais pouvoir donner des conseils sur ce qu'il faut rechercher dans votre configuration php pour déterminer si vous devez ou non vous arracher les cheveux en essayant d'obtenir ce type de comportement sur votre serveur ! Quelqu'un d'autre le sait ?

Voici un exemple fictif en PHP :

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

disable_ob();

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

J'espère que cela aidera d'autres personnes qui ont cherché sur Google à venir ici.

5voto

raminious Points 83

essayez ceci (testé sur une machine Windows + serveur wamp)

        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();

3voto

Nathacof Points 222

Si vous cherchez à exécuter des commandes système via PHP, consultez le site, la documentation sur l'exécution .

Je ne recommanderais pas de le faire sur un site à fort trafic, car le fait de forker un processus pour chaque requête est un processus assez lourd. Certains programmes offrent la possibilité d'écrire leur identifiant de processus dans un fichier de sorte que vous puissiez vérifier et terminer le processus à volonté, mais pour des commandes comme ping, je ne suis pas sûr que ce soit possible, consultez les pages de manuel.

Il est préférable d'ouvrir simplement un socket sur le port que vous pensez écouter (par exemple, le port 80 pour HTTP) sur l'hôte distant. Ainsi, vous saurez que tout se passe bien dans l'espace utilisateur, ainsi que sur le réseau.

Si vous essayez de sortir des données binaires, regardez dans la fonction d'en-tête de php et assurez-vous que vous définissez le bon type de contenu et contenu-disposition . Examen la documentation pour plus d'informations sur l'utilisation/la désactivation du tampon de sortie.

1voto

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X