J'ai un script PHP qui doit appeler un script Shell mais ne se soucie pas du tout de la sortie. Le script Shell effectue un certain nombre d'appels SOAP et est lent à terminer. Par conséquent, je ne souhaite pas ralentir la demande PHP en attendant une réponse. En fait, la requête PHP devrait pouvoir se fermer sans mettre fin au processus Shell.
J'ai examiné les différentes fonctions exec()
, Shell_exec()
, pcntl_fork()
, etc., mais aucune ne semble offrir exactement ce que je veux. (Ou, s'ils le font, je ne vois pas comment.) Des suggestions?
S'il "ne se soucie pas de la sortie", l'exécutif du script ne peut-il pas être appelé avec le &
afin d'arrière-plan du processus?
EDIT - incorporant ce que @ AdamTheHut a commenté dans cet article, vous pouvez ajouter cela à un appel à exec
:
" > /dev/null 2>/dev/null &"
Cela redirigera stdio
(premier >
) et stderr
(2>
) vers /dev/null
et s'exécutera en arrière-plan.
Il y a d'autres façons de faire la même chose, mais c'est la plus simple à lire.
Une alternative à la double redirection ci-dessus:
" &> /dev/null &"
J'ai utilisé at pour cela, car il s'agit vraiment d'un processus indépendant.
<?php
`echo "the command"|at now`;
?>
Sur Linux, vous pouvez effectuer les opérations suivantes:
$cmd = 'Nohup Nice -n 10 php -f php/file.php > log/file.log & printf "%u" $!';
$pid = Shell_exec($cmd);
Cela exécutera la commande à l'invite de commande, puis renverra simplement le PID, que vous pouvez vérifier pour> 0 pour vous assurer qu'il a fonctionné.
Cette question est similaire: PHP a-t-il des threads?
Pour tous les utilisateurs Windows: j'ai trouvé un bon moyen d'exécuter un script PHP asynchrone (en réalité, il fonctionne avec presque tout).
Il est basé sur les commandes popen () et pclose (). Et fonctionne bien à la fois sur 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
php-execute-a-background-process a de bonnes suggestions. Je pense que le mien est très bon, mais je suis partial :)
Sous Linux, vous pouvez démarrer un processus dans un nouveau thread indépendant en ajoutant une esperluette à la fin de la commande.
mycommand -someparam somevalue &
Sous Windows, vous pouvez utiliser la commande DOS "démarrer"
start mycommand -someparam somevalue
la bonne façon de le faire est de
fork forks, setsid indique au processus en cours de devenir un processus maître (pas de parent), execve indique au processus appelant d'être remplacé par le processus appelé. afin que le parent puisse quitter sans affecter 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();
J'ai utilisé ça ...
/**
* 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 .
J'ai aussi trouvé Composant de processus Symfony 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
Voyez comment cela fonctionne dans son GitHub repo .
La seule façon qui a vraiment fonctionné pour moi était:
Shell_exec('./myscript.php | at now & disown')
Vous pouvez également exécuter le script PHP en tant que daemon ou cronjob : #!/usr/bin/php -q
Utilisez un fifo nommé.
#!/bin/sh
mkfifo trigger
while true; do
read < trigger
long_running_task
done
Ensuite, chaque fois que vous souhaitez démarrer une tâche longue, écrivez simplement une nouvelle ligne (non bloquante dans le fichier de déclencheur).
Tant que votre entrée est inférieure à PIPE_BUF
et qu'il s'agit d'une seule opération write()
, vous pouvez écrire des arguments dans le fifo et les afficher sous la forme $REPLY
dans le script.
sans utiliser la file d'attente, vous pouvez utiliser la 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);