exec shell assíncrona em PHP

votos
177

Eu tenho um script PHP que precisa chamar um shell script, mas não se importa em tudo sobre a saída. O shell script faz uma série de chamadas SOAP e é lento para completar, então eu não quero abrandar o pedido PHP enquanto aguarda uma resposta. Na verdade, o pedido PHP deve ser capaz de sair sem que encerra o processo shell.

Eu olhei para os vários exec(), shell_exec(), pcntl_fork()funções, etc., mas nenhum deles parecem oferecer exatamente o que eu quero. (Ou, se o fizer, não é claro para mim como.) Alguma sugestão?

Publicado 21/10/2008 em 17:02
fonte usuário
Em outras línguas...                            


13 respostas

votos
193

Se ele "não se preocupa com a saída", não poderia o exec para o script ser chamado com o &de fundo o processo?

EDIT - incorporando o @ AdamTheHut comentou a este post, você pode adicionar este a uma chamada para exec:

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

Isso irá redirecionar ambos stdio(primeiro >) e stderr( 2>) para /dev/nulle executado em segundo plano.

Há outras maneiras de fazer a mesma coisa, mas este é o mais simples de ler.


Uma alternativa para a dupla-redireccionamento acima:

" &> /dev/null &"
Respondeu 21/10/2008 em 17:08
fonte usuário

votos
51

Eu usei a para isso, como ele está realmente começando um processo independente.

<?php
    `echo "the command"|at now`;
?>
Respondeu 21/10/2008 em 23:20
fonte usuário

votos
18

No Linux, você pode fazer o seguinte:

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

Isto irá executar o comando no prompty de comando e, em seguida, basta retornar o PID, que você pode verificar se há> 0 para garantir que ele trabalhou.

Esta questão é semelhante: O PHP tem enfiar?

Respondeu 21/10/2008 em 23:27
fonte usuário

votos
15

Para todos os usuários do Windows: Eu encontrei uma boa maneira de executar um script PHP assíncrona (na verdade, ele funciona com quase tudo).

É baseado em popen () e pclose () comandos. E funciona bem tanto em Windows e Unix.

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

Código original de: http://php.net/manual/en/function.exec.php#86329

Respondeu 25/10/2016 em 15:12
fonte usuário

votos
12

php-execute-a-background-processo tem algumas boas sugestões. Eu acho que o meu é muito bom, mas eu sou preconceituoso :)

Respondeu 21/10/2008 em 23:29
fonte usuário

votos
6

No Linux, você pode começar um processo em um novo segmento independente anexando um e comercial no final do comando

mycommand -someparam somevalue &

No Windows, você pode usar o comando "start" DOS

start mycommand -someparam somevalue
Respondeu 21/10/2008 em 23:46
fonte usuário

votos
5

o caminho certo (!) para fazê-lo é

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

forquilha forquilhas, setsid dizer o atual processo para se tornar um mestre (sem pai), execve dizer o processo de chamada a ser substituído pelo chamado um. de modo que o pai pode sair sem afetar a criança.

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

 // parent's stuff
 exit();
Respondeu 14/11/2008 em 16:31
fonte usuário

votos
4

Eu usei esse ...

/** 
 * 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 &");
}

(onde PHP_PATHestá um const definido como define('PHP_PATH', '/opt/bin/php5')ou semelhante)

Ele passa em argumentos via linha de comando. Para lê-los em PHP, consulte argv .

Respondeu 19/07/2010 em 21:25
fonte usuário

votos
3

A única maneira que eu achei que realmente funcionou para mim foi:

shell_exec('./myscript.php | at now & disown')
Respondeu 08/02/2012 em 19:11
fonte usuário

votos
2

Eu também achei Symfony Processo componente útil para isso.

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

Veja como funciona em sua repo GitHub .

Respondeu 10/10/2017 em 22:45
fonte usuário

votos
1

Use um fifo chamado.

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

Então sempre que você deseja iniciar a tarefa de longa duração, simplesmente escrever uma nova linha (não bloqueante para o arquivo gatilho.

Contanto que sua entrada é menor do que PIPE_BUFe é uma única write()operação, você pode escrever argumentos para o fifo e tê-los aparecer como $REPLYno script.

Respondeu 14/11/2008 em 16:47
fonte usuário

votos
1

Você também pode executar o script PHP como daemon ou cronjob :#!/usr/bin/php -q

Respondeu 07/11/2008 em 08:33
fonte usuário

votos
0

sem fila de uso, você pode usar o proc_open()assim:

    $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);
Respondeu 21/12/2016 em 10:18
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more