¿Hay alguna forma de usar shell_exec sin esperar a que se complete el comando?

95

Tengo una tarea de proceso intensivo que me gustaría ejecutar en segundo plano.

El usuario hace clic en una página, se ejecuta el script PHP y, finalmente, según algunas condiciones, si es necesario, debe ejecutar un script de shell, por ejemplo:

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

Actualmente uso shell_exec , pero esto requiere que el script espere una salida. ¿Hay alguna forma de ejecutar el comando que quiero sin esperar a que se complete?

ToughPal
fuente
NOTA: El proceso debe comenzar de inmediato, por lo que un cron no es una opción.
ToughPal
2
Solo una nota rápida: asegúrese de que la página no sea accesible para todos (motores de búsqueda / usuarios fraudulentos) y si está en un entorno compartido, el tiempo de ejecución de todos sus scripts (¡en particular php!) Probablemente sea limitado. En cualquier caso, es posible que desee echar un vistazo a set_time_limit / php.ini.
merkuro
Posible duplicado de php ejecutar un proceso en segundo plano
Sean the Bean

Respuestas:

150

¿Qué tal agregar?

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

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

Tenga en cuenta que esto también elimina stdio y stderr.

estar nervioso
fuente
2
No. Sin efectos secundarios. Si en algún momento decide que desea la salida stdio o stderr de su proceso, considere stackoverflow.com/questions/45953/…
jitter
1
Pregunta: Eso es simplemente descartar la salida, ¿verdad? ¿PHP todavía espera a que finalice el proceso antes de continuar con la ejecución, o se activa y se olvida?
Alan Storm
5
Sí se descarta. Sí, dispara y olvida
jitter
3
Nota: > /dev/null 2>&1 &como se ve en otras respuestas, es una forma concisa de > /dev/null 2>/dev/null &dada aquí. Esto básicamente dice "redirigir STDERR (2) al mismo lugar que STDOUT (& 1)".
Rymo
3
Por lo general, obtengo el PID del script en ejecución agregando echo $! >> /tmp/pid.txt al final del comando exec pero redirigiendo la salida y el error a / dev / null, no más archivo pid: ¿alguno de ustedes puede obtener el PID del script lanzado por el ejecutivo mientras no espera la salida?
Hugsbrugs
28

Esto ejecutará un comando y se desconectará del proceso en ejecución. Por supuesto, puede ser cualquier comando que desee. Pero para una prueba, puede crear un archivo php con un comando sleep (20).

exec("nohup /usr/bin/php -f sleep.php > /dev/null 2>&1 &");
Brent Baisley
fuente
¿es mejor esto o shell_exec?
realtebo
hola, ¿puedo ejecutar la función usando este shell_exec ("nohup / usr / bin / php -f example.com/notifications/sendnotifications_async > / dev / null 2> & 1 &");
Waseem Bashir
¿Por qué ambos nohup y el &?
bugmenot123
11

También puede devolver su salida al cliente instantáneamente y continuar procesando su código PHP después.

Este es el método que estoy usando para llamadas Ajax de larga espera que no tendrían ningún efecto en el lado del 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.

Puede encontrar la explicación detallada aquí: http://oytun.co/response-now-process-later

Oytun
fuente
1
Ops ... Estaba despertando una pregunta zombi aquí, no me había dado cuenta. Pero esta información podría ser beneficiosa para otros.
Oytun
3
Esto no tiene nada que ver con shell_exec
bugmenot123
8

En Windows 2003, para llamar a otro script sin esperar, utilicé esto:

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

Esto solo funciona DESPUÉS de otorgar permisos de cambio en cmd.exe: agregue Leer y Ejecutar para IUSR_YOURMACHINE(también configuré la escritura en Denegar).

Jason Plank
fuente
7

Seguro, porque windowspuedes usar:

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

Nota:

Si recibe un COMerror, agregue la extensión a su php.iniy reinicie apache:

[COM_DOT_NET]
extension=php_com_dotnet.dll
CONvid19
fuente
No tengo idea, pero funcionó para mí. Por favor, alguien explique qué es wscript.shell y para qué sirve.
GeekWithGlasses
¿Puede explicar por qué esta línea no da ningún resultado? `$ oExec = $ WshShell-> Ejecutar ('C: \ Users \ Shreyash \ Desktop \ phantomjs-2.1.1-windows \ bin \ phantomjs.exe -f C: \ xampp \ htdocs \ composer \ test_0.js', 0 , falso); `
GeekWithGlasses
Es posible que tenga un error en test_0.js, verifique el registro fantasma.
CONvid19
6

Utilice el popencomando de PHP , por ejemplo:

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

Esto creará un proceso hijo y el script se ejecutará en segundo plano sin esperar la salida.

Jason Plank
fuente
4
Espera a que finalice el proceso hijo. Al menos en Win
Max Chernopolsky
El fondo aquí se logra con la ayuda del comando de "inicio" de Windows que antepone el exe que desea ejecutar, no funcionará si lo omite, y no esperaría que funcione en otro sistema operativo ... pero SÍ funciona para mi, gracias! :-)
Antony
1

Si está fuera de una página web, recomiendo generar una señal de algún tipo (colocar un archivo en un directorio, tal vez) y hacer que un trabajo cron recoja el trabajo que debe hacerse. De lo contrario, es probable que entremos en el territorio del uso pcntl_fork()y exec()desde el interior de un proceso de Apache, y eso es simplemente un mal mojo.

caos
fuente
1
dijiste que es un mal mojo. ¿Puedes por favor explicarme?
Mayank
1

Eso funcionará, pero tendrá que tener cuidado de no sobrecargar su servidor porque creará un nuevo proceso cada vez que llame a esta función que se ejecutará en segundo plano. Si solo hay una llamada simultánea al mismo tiempo, esta solución hará el trabajo.

Si no es así, aconsejaría ejecutar una cola de mensajes como, por ejemplo, beanstalkd / gearman / amazon sqs.

Alfredo
fuente