¿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@yahoo.com');

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?


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

Respuestas:


150

¿Qué tal agregar?

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

shell_exec('php measurePerformance.php 47 844 email@yahoo.com > /dev/null 2>/dev/null &');

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


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

¿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


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).


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

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.


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.


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.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.