Shell asynchrone exec en PHP

j'ai un script PHP qui doit invoquer un script shell mais qui ne se soucie pas du tout de la sortie. Le script shell fait un certain nombre d'appels SOAP et est lent à compléter, donc je ne veux pas ralentir la requête PHP pendant qu'elle attend une réponse. En fait, la requête PHP devrait être capable de quitter sans terminer le processus shell.

j'ai regardé dans les différents exec() , shell_exec() , pcntl_fork() , etc. fonctions, mais aucun d'entre eux semblent offrir exactement ce que je veux. (Ou, s'ils le font, ce n'est pas clair pour moi comment.) Des suggestions?

182
demandé sur Boaz 2008-10-21 20:02:10

13 réponses

S'il" ne se soucie pas de la sortie", ne pourrait-on pas appeler l'exec du script avec le & pour background le processus?

MODIFIER - en intégrant ce @ AdamTheHut , a commenté à ce post, vous pouvez l'ajouter à un appel à exec :

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

qui redirigera à la fois stdio (premier > ) et stderr ( 2> ) vers /dev/null et lancera en arrière-plan.

Il y a d'autres façons de faire la même chose, mais c'est le plus simple à lire.


Une alternative à la double ci-dessus-redirect:

" &> /dev/null &"
197
répondu warren 2017-05-23 10:31:29

j'ai utilisé à pour ceci, car il commence vraiment un processus indépendant.

<?php
    `echo "the command"|at now`;
?>
51
répondu Czimi 2011-08-06 18:07:39

sur linux vous pouvez faire ce qui suit:

$cmd = 'nohup nice -n 10 php -f php/file.php > log/file.log & printf "%u" $!';
$pid = shell_exec($cmd);

ceci exécutera la commande à la commande prompty et ensuite juste retourner le PID, que vous pouvez vérifier pour > 0 pour s'assurer qu'il a fonctionné.

cette question est similaire: PHP a-t-il un threading?

18
répondu Darryl Hein 2017-08-04 16:27:21

pour tous les utilisateurs de Windows: j'ai trouvé un bon moyen d'exécuter un script PHP asynchrone (en fait il fonctionne avec presque tout).

est basé sur les commandes popen() et pclose (). Et fonctionne bien sous Windows et Unix.

function execInBackground($cmd) {
    if (substr(php_uname(), 0, 7) == "Windows"){
        pclose(popen("start /B ". $cmd, "r")); 
    }
    else {
        exec($cmd . " > /dev/null &");  
    }
} 

code Original de: http://php.net/manual/en/function.exec.php#86329

16
répondu LucaM 2016-10-25 15:12:07

php-executer-un-fond-processus a quelques bonnes suggestions. Je pense que le mien est assez bonne, mais je suis partial :)

12
répondu Mark Biek 2017-05-23 11:47:19

sous Linux, vous pouvez démarrer un processus dans un nouveau thread indépendant en ajoutant un ampli à la fin de la commande

mycommand -someparam somevalue &

sous Windows, vous pouvez utiliser la commande" start "DOS

start mycommand -someparam somevalue
6
répondu Leo 2008-10-21 22:46:46

le droit chemin(!) c'est de

  1. fork ()
  2. setsid ()
  3. execve ()

fourchettes, setsid dire au processus en cours de devenir un maître Un (aucun parent), execve dire au processus appelant d'être remplacé par le appelé. pour que le parent puisse cesser de fumer sans nuire à l'enfant.

 $pid=pcntl_fork();
 if($pid==0)
 {
   posix_setsid();
   pcntl_exec($cmd,$args,$_ENV);
   // child becomes the standalone detached process
 }

 // parent's stuff
 exit();
5
répondu 2008-11-14 15:31:56

j'ai utilisé ceci...

/** 
 * Asynchronously execute/include a PHP file. Does not record the output of the file anywhere.  
 * Relies on the PHP_PATH config constant.
 *
 * @param string $filename  file to execute
 * @param string $options   (optional) arguments to pass to file via the command line
 */ 
function asyncInclude($filename, $options = '') {
    exec(PHP_PATH . " -f {$filename} {$options} >> /dev/null &");
}

(où PHP_PATH est un const défini comme define('PHP_PATH', '/opt/bin/php5') ou similaire)

il passe en arguments via la ligne de commande. Pour les lire en PHP, voir argv .

4
répondu philfreo 2010-07-19 20:25:46

la seule façon que j'ai trouvé qui a vraiment travaillé pour moi était:

shell_exec('./myscript.php | at now & disown')
3
répondu Gordon Forsythe 2012-02-08 18:11:32

j'ai aussi trouvé Symfony Processus de la Composante utile pour cela.

use Symfony\Component\Process\Process;

$process = new Process('ls -lsa');
// ... run process in background
$process->start();

// ... do other things

// ... if you need to wait
$process->wait();

// ... do things after the process has finished

Voir comment cela fonctionne dans son dépôt GitHub .

2
répondu Anton Pelykh 2017-11-10 15:44:30

utilisez un fifo nommé.

#!/bin/sh
mkfifo trigger
while true; do
    read < trigger
    long_running_task
done

ensuite, chaque fois que vous voulez lancer la tâche longue exécution, il vous suffit d'écrire une nouvelle ligne (non bloquante dans le fichier de déclenchement).

aussi longtemps que votre entrée est plus petite que PIPE_BUF et que c'est une seule opération write() , vous pouvez écrire des arguments dans le fifo et les faire apparaître comme $REPLY dans le script.

1
répondu geocar 2008-11-14 15:47:02

vous pouvez également exécuter le script PHP comme démon ou cronjob : #!/usr/bin/php -q

1
répondu Ronald Conco 2015-02-08 00:50:12

sans file d'attente d'utilisation, vous pouvez utiliser le proc_open() comme ceci:

    $descriptorspec = array(
        0 => array("pipe", "r"),
        1 => array("pipe", "w"),
        2 => array("pipe", "w")    //here curaengine log all the info into stderror
    );
    $command = 'ping stackoverflow.com';
    $process = proc_open($command, $descriptorspec, $pipes);
0
répondu Kris Roofe 2016-12-21 10:18:55