Existe uma maneira de usar shell_exec sem esperar a conclusão do comando?

95

Tenho uma tarefa intensiva de processo que gostaria de executar em segundo plano.

O usuário clica em uma página, o script PHP é executado e, finalmente, com base em algumas condições, se necessário, ele deve executar um script de shell, por exemplo:

shell_exec('php measurePerformance.php 47 844 [email protected]');

Atualmente eu uso shell_exec , mas isso requer que o script espere por uma saída. Existe alguma maneira de executar o comando que desejo sem esperar que ele seja concluído?

ToughPal
fonte
NOTA: O processo deve começar imediatamente, portanto, um cron não é uma opção.
ToughPal de
2
Apenas uma nota rápida: certifique-se de que a página não será acessível a todos (motores de busca / usuários fraudulentos) e se você estiver em um ambiente compartilhado, o tempo de execução de todos os seus scripts (em particular php!) Provavelmente é limitado. Em qualquer caso, você pode querer dar uma olhada em set_time_limit / php.ini.
merkuro
Possível duplicata do php executar um processo em segundo plano
Sean the Bean

Respostas:

150

Que tal adicionar.

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

shell_exec('php measurePerformance.php 47 844 [email protected] > /dev/null 2>/dev/null &');

Observe que isso também elimina o stdio e o stderr.

tremor
fonte
2
Não. Sem efeitos colaterais. Se em algum momento você decidir que deseja a saída stdio ou stderr de seu processo, considere stackoverflow.com/questions/45953/…
jitter
1
Pergunta: Isso é apenas descartar a saída, certo? O PHP ainda espera que o processo termine antes de continuar a execução ou ele dispara e esquece?
Alan Storm
5
Sim, descarta. Sim, dispare e esqueça
tremulação de
3
Nota: > /dev/null 2>&1 &como visto em outras respostas, é uma forma concisa > /dev/null 2>/dev/null &fornecida aqui. Isso basicamente significa "redirecionar STDERR (2) para o mesmo lugar que STDOUT (& 1)".
rymo
3
Eu normalmente obtenho o PID da execução do script adicionando echo $! >> /tmp/pid.txt no final do comando exec, mas redirecionando a saída e o erro para / dev / null, chega de arquivo pid: algum de vocês pode obter o PID do script lançado pelo exec enquanto não espera pela saída?
hugsbrugs
28

Isso executará um comando e se desconectará do processo em execução. Claro, pode ser qualquer comando que você quiser. Mas, para um teste, você pode criar um arquivo php com um comando sleep (20).

exec("nohup /usr/bin/php -f sleep.php > /dev/null 2>&1 &");
Brent Baisley
fonte
é melhor isso ou shell_exec?
realtebo
oi, posso executar a função usando este shell_exec ("nohup / usr / bin / php -f example.com/notifications/sendnotifications_async > / dev / null 2> & 1 &");
Waseem Bashir
Por que ambos nohup e o &?
bugmenot123
11

Você também pode devolver sua saída ao cliente instantaneamente e continuar processando seu código PHP depois.

Este é o método que estou usando para chamadas Ajax de longa espera que não teriam nenhum efeito no lado do cliente:

ob_end_clean();
ignore_user_abort();
ob_start();
header("Connection: close");
echo json_encode($out);
header("Content-Length: " . ob_get_length());
ob_end_flush();
flush();
// execute your command here. client will not wait for response, it already has one above.

Você pode encontrar a explicação detalhada aqui: http://oytun.co/response-now-process-later

Oytun
fonte
1
Ops ... Eu estava levantando uma pergunta sobre zumbis aqui, eu não percebi. Mas essa informação pode ser benéfica para outras pessoas.
Oytun
3
Isso não tem nada a ver com shell_exec
bugmenot123
8

No Windows 2003, para chamar outro script sem esperar, usei este:

$commandString = "start /b c:\\php\\php.EXE C:\\Inetpub\\wwwroot\\mysite.com\\phpforktest.php --passmsg=$testmsg"; 
pclose(popen($commandString, 'r'));

Isso só funciona APÓS conceder permissões de alteração em cmd.exe- adicionar Ler e Executar para IUSR_YOURMACHINE(também defini gravação como Negar).

Jason Plank
fonte
7

Claro, para windowsvocê pode usar:

$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->Run("C:/path/to/php-win.exe -f C:/path/to/script.php", 0, false);

Nota:

Se você receber um COMerro, adicione a extensão ao seu php.inie reinicie apache:

[COM_DOT_NET]
extension=php_com_dotnet.dll
CONvid19
fonte
Eu não tenho ideia, mas funcionou para mim. Por favor, alguém explique o que é wscript.shell e o que ele faz.
GeekWithGlasses
você pode explicar por que esta linha não está dando nenhuma saída? `$ oExec = $ WshShell-> Run ('C: \ Users \ Shreyash \ Desktop \ phantomjs-2.1.1-windows \ bin \ phantomjs.exe -f C: \ xampp \ htdocs \ composer \ test_0.js', 0 , false); `
GeekWithGlasses
Você pode ter um erro em test_0.js, verifique o log fantasma.
CONvid19
6

Use o popencomando do PHP , por exemplo:

pclose(popen("start c:\wamp\bin\php.exe c:\wamp\www\script.php","r"));

Isso criará um processo filho e o script será executado em segundo plano sem esperar pela saída.

Jason Plank
fonte
4
Ele espera que o processo filho termine. Pelo menos na vitória
Max Chernopolsky
O plano de fundo aqui é obtido com a ajuda do comando "iniciar" do Windows que prefixa o exe que você deseja executar, ele não funcionará se você omiti-lo e eu não esperaria que funcionasse em outro sistema operacional ... mas FUNCIONA funciona para mim, obrigado! :-)
Antony
1

Se estiver fora de uma página da web, recomendo gerar um sinal de algum tipo (soltar um arquivo em um diretório, talvez) e fazer com que um cron job pegue o trabalho que precisa ser feito. Do contrário, provavelmente entraremos no território de usar pcntl_fork()e exec()de dentro de um processo Apache, e isso é apenas um mojo ruim.

caos
fonte
1
você disse que é um mojo ruim. você pode elaborar?
Mayank
1

Isso funcionará, mas você terá que ter cuidado para não sobrecarregar seu servidor, pois ele criará um novo processo toda vez que você chamar esta função, que será executada em segundo plano. Se houver apenas uma chamada simultânea ao mesmo tempo, essa solução alternativa fará o trabalho.

Se não, eu aconselharia a executar uma fila de mensagens como, por exemplo, beanstalkd / gearman / amazon sqs.

Alfred
fonte