285 votes

php exécute un processus en arrière-plan

J'ai besoin d'exécuter une copie de répertoire à la suite d'une action de l'utilisateur, mais les répertoires sont assez volumineux. J'aimerais donc pouvoir effectuer une telle action sans que l'utilisateur soit conscient du temps nécessaire à la copie pour se terminer.

Toute suggestion serait très appréciée.

3 votes

Ce site stackoverflow.com/questions/5367261/ explique comment procéder sous Windows

393voto

Mark Biek Points 41769

En supposant que cela fonctionne sur une machine Linux, j'ai toujours procédé comme suit :

exec(sprintf("%s > %s 2>&1 & echo $! >> %s", $cmd, $outputfile, $pidfile));

Cela lance la commande $cmd redirige la sortie de la commande vers $outputfile et écrit l'identifiant du processus dans $pidfile .

Cela vous permet de surveiller facilement ce que fait le processus et s'il est toujours en cours.

function isRunning($pid){
    try{
        $result = shell_exec(sprintf("ps %d", $pid));
        if( count(preg_split("/\n/", $result)) > 2){
            return true;
        }
    }catch(Exception $e){}

    return false;
}

0 votes

J'ai essayé votre échantillon. Mais malheureusement cela n'a pas fonctionné dans ce cas. $cmd = "sudo -u sun mplayer /tmp/demo.wav>/dev/null &" ; exec(sprintf("%s > %s 2>&1 & echo $ ! >> %s", $cmd, $outputfile, $pidfile) ) ; echo $pidfile ; // pour que je puisse tuer plus tard ne donne rien.

2 votes

Est-ce que sudo est configuré pour fonctionner sans demander de mot de passe ? Toutes les commandes qui nécessitent une saisie de l'utilisateur ne fonctionneront pas.

0 votes

Oui, il est désactivé, le mode nopassword est activé mais cela ne fonctionne toujours pas. Par exemple #Defaults requiretty Root ALL=(ALL) ALL apache ALL=(ALL) NOPASSWD : ALL

29voto

Eric Goodwin Points 1497

Écrivez le processus en tant que script côté serveur dans le langage qui vous convient (php/bash/perl/etc), puis appelez-le à partir des fonctions de contrôle du processus dans votre script php.

La fonction détecte probablement si io standard est utilisé comme flux de sortie et si c'est le cas, cela définira la valeur de retour. Sinon, elle se termine.

proc_close( proc_open( "./command --foo=1 &", array(), $foo ) );

J'ai testé cela rapidement à partir de la ligne de commande en utilisant "sleep 25s" comme commande et cela a fonctionné comme un charme.

( Réponse trouvée ici )

3 votes

C'est le seul moyen que j'ai trouvé pour le faire fonctionner sur centos. Merci !

0 votes

Merci ! Il y a une incompatibilité entre PHP et BASH. Si vous utilisez un système plus récent, il ne pourra pas se lancer en arrière-plan en utilisant system() ou exec(). Les descripteurs de fichiers semblent rester bloqués même si vous redirigez. Votre méthode a fonctionné. Une autre alternative est d'utiliser un ancien binaire bash pour PHP, mais c'est une folie.

27voto

wlf Points 163

Vous pouvez essayer d'ajouter ceci à votre commande

>/dev/null 2>/dev/null &

eg.

shell_exec('service named reload >/dev/null 2>/dev/null &');

0 votes

Je voulais dire >/dev/null 2>/dev/null &

0 votes

Cela fonctionne pour moi, et je vais utiliser le fichier makefile pour faire quelque chose sur le site du serveur, merci ! (ex. make, make restart)

0 votes

C'est beaucoup plus simple que la réponse acceptée ! (Tant que vous n'avez pas besoin de quelque chose de plus complexe, comme vérifier si le processus est toujours en cours).

18voto

Captain Obvious Points 482

Je voudrais juste ajouter un exemple très simple pour tester cette fonctionnalité sous Windows :

Créez les deux fichiers suivants et enregistrez-les dans un répertoire web :

foreground.php :

<?php

ini_set("display_errors",1);
error_reporting(E_ALL);

echo "<pre>loading page</pre>";

function run_background_process()
{
    file_put_contents("testprocesses.php","foreground start time = " . time() . "\n");
    echo "<pre>  foreground start time = " . time() . "</pre>";

    // output from the command must be redirected to a file or another output stream 
    // http://ca.php.net/manual/en/function.exec.php

    exec("php background.php > testoutput.php 2>&1 & echo $!", $output);

    echo "<pre>  foreground end time = " . time() . "</pre>";
    file_put_contents("testprocesses.php","foreground end time = " . time() . "\n", FILE_APPEND);
    return $output;
}

echo "<pre>calling run_background_process</pre>";

$output = run_background_process();

echo "<pre>output = "; print_r($output); echo "</pre>";
echo "<pre>end of page</pre>";
?>

background.php :

<?
file_put_contents("testprocesses.php","background start time = " . time() . "\n", FILE_APPEND);
sleep(10);
file_put_contents("testprocesses.php","background end time = " . time() . "\n", FILE_APPEND);
?>

Donnez à l'IUSR la permission d'écrire dans le répertoire dans lequel vous avez créé les fichiers ci-dessus.

Donner à IUSR la permission de LIRE et EXECUTER C:\Windows\System32\cmd.exe

Appelez foreground.php à partir d'un navigateur web

Ce qui suit devrait être rendu au navigateur avec les timestamps actuels et le numéro de la ressource locale dans le tableau de sortie :

loading page
calling run_background_process
  foreground start time = 1266003600
  foreground end time = 1266003600
output = Array
(
    [0] => 15010
)
end of page

Vous devriez voir testoutput.php dans le même répertoire que celui où les fichiers ci-dessus ont été enregistrés, et il devrait être vide.

Vous devriez voir testprocesses.php dans le même répertoire que celui où les fichiers ci-dessus ont été sauvegardés, et il devrait contenir le texte suivant avec les timestamps actuels :

foreground start time = 1266003600
foreground end time = 1266003600
background start time = 1266003600
background end time = 1266003610

10voto

Neven Boyanov Points 356

Si vous avez besoin de faire quelque chose en arrière-plan sans que la page PHP attende qu'elle se termine, vous pouvez utiliser un autre script PHP (en arrière-plan) qui est "invoqué" avec la commande wget. Ce script PHP en arrière-plan sera exécuté avec des privilèges, bien sûr, comme tout autre script PHP sur votre système.

Voici un exemple sous Windows utilisant wget à partir des paquets gnuwin32.

Le code d'arrière-plan (fichier test-proc-bg.php) à titre d'exemple ...

sleep(5);   // some delay
file_put_contents('test.txt', date('Y-m-d/H:i:s.u')); // writes time in a file

Le script de premier plan, celui qui invoque ...

$proc_command = "wget.exe http://localhost/test-proc-bg.php -q -O - -b";
$proc = popen($proc_command, "r");
pclose($proc);

Vous devez utiliser le popen/pclose pour que cela fonctionne correctement.

Les options de wget :

-q    keeps wget quiet.
-O -  outputs to stdout.
-b    works on background

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