C'è un modo per utilizzare shell_exec senza attendere il completamento del comando?


95

Ho un'attività ad alta intensità di processo che vorrei eseguire in background.

L'utente fa clic su una pagina, viene eseguito lo script PHP e, infine, in base ad alcune condizioni, se necessario, deve eseguire uno script di shell, ad esempio:

shell_exec('php measurePerformance.php 47 844 email@yahoo.com');

Attualmente utilizzo shell_exec , ma questo richiede che lo script attenda un output. C'è un modo per eseguire il comando che desidero senza aspettare che venga completato?


NOTA: il processo deve iniziare immediatamente, quindi un cron non è un'opzione.
ToughPal

2
Solo una breve nota: assicurati che la pagina non sia accessibile a tutti (motori di ricerca / utenti fraudolenti) e se ti trovi in ​​un ambiente condiviso, il tempo di esecuzione di tutti i tuoi script (in particolare php!) È probabilmente limitato. In ogni caso potresti voler dare un'occhiata a set_time_limit / php.ini.
merkuro

Risposte:


150

Che ne dici di aggiungere.

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

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

Nota che questo elimina anche stdio e stderr.


2
No. Nessun effetto collaterale. Se a volte decidi di volere l'output stdio o stderr del tuo processo, considera stackoverflow.com/questions/45953/…
jitter

1
Domanda: Sto solo scartando l'output, giusto? PHP attende ancora che il processo finisca prima di continuare l'esecuzione o si attiva e si dimentica?
Alan Storm

5
Sì scarta. Sì, spara e dimentica
jitter

3
Nota: > /dev/null 2>&1 &come si vede in altre risposte è una forma concisa di > /dev/null 2>/dev/null &dato qui. Questo in pratica sta dicendo "reindirizza STDERR (2) allo stesso posto di STDOUT (& 1)".
rymo

3
Di solito ottengo il PID dello script in esecuzione aggiungendo echo $! >> /tmp/pid.txt alla fine del comando exec ma reindirizzando l'output & l'errore a / dev / null, niente più file pid: qualcuno di voi può ottenere il PID dello script lanciato da exec senza attendere l'output?
hugsbrugs

28

Questo eseguirà un comando e si disconnetterà dal processo in esecuzione. Ovviamente può essere qualsiasi comando tu voglia. Ma per un test, puoi creare un file php con un comando sleep (20).

exec("nohup /usr/bin/php -f sleep.php > /dev/null 2>&1 &");

è meglio questo o shell_exec?
realtebo

ciao, posso eseguire la funzione usando questo shell_exec ("nohup / usr / bin / php -f example.com/notifications/sendnotifications_async > / dev / null 2> & 1 &");
Waseem Bashir

Perché entrambi nohup e il &?
bugmenot123

11

Puoi anche restituire immediatamente il tuo output al client e continuare a elaborare il tuo codice PHP in seguito.

Questo è il metodo che sto usando per le chiamate Ajax di lunga attesa che non avrebbe alcun effetto sul lato client:

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.

Puoi trovare la spiegazione dettagliata qui: http://oytun.co/response-now-process-later


1
Ops ... stavo svegliando una domanda sugli zombi, non ho capito. Ma questa informazione potrebbe essere utile per gli altri.
Oytun

3
Questo non ha nulla a che fare con shell_exec
bugmenot123

8

Su Windows 2003, per chiamare un altro script senza aspettare, ho usato questo:

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

Funziona solo DOPO aver dato i permessi di modifica su cmd.exe- aggiungi Lettura ed Esegui per IUSR_YOURMACHINE(ho anche impostato la scrittura su Nega).


7

Certo, perché windowspuoi usare:

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

Nota:

Se ricevi un COMerrore, aggiungi l'estensione al tuo php.inie riavvia apache:

[COM_DOT_NET]
extension=php_com_dotnet.dll

Non ne ho idea ma ha funzionato per me. Per favore, qualcuno spieghi cos'è wscript.shell e cosa fa.
GeekWithGlasses

puoi spiegare perché questa riga non fornisce alcun output? `$ oExec = $ WshShell-> Esegui ('C: \ Users \ Shreyash \ Desktop \ phantomjs-2.1.1-windows \ bin \ phantomjs.exe -f C: \ xampp \ htdocs \ composer \ test_0.js', 0 , false); `
GeekWithGlasses

Potresti avere un errore su test_0.js, controlla il registro fantasma.
CONvid19

6

Usa il popencomando di PHP , ad esempio:

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

Questo creerà un processo figlio e lo script verrà eseguito in background senza attendere l'output.


4
Attende il termine del processo figlio. Almeno su Win
Max Chernopolsky

Lo sfondo qui si ottiene con l'aiuto del comando "start" di Windows che antepone l'exe che si desidera eseguire, non funzionerà se lo si omette e non mi aspetto che funzioni su un altro sistema operativo ... ma FA funziona per me, grazie! :-)
Antony

1

Se è al di fuori di una pagina web, consiglio di generare un segnale di qualche tipo (lasciando cadere un file in una directory, forse) e di fare in modo che un cron job raccolga il lavoro che deve essere fatto. Altrimenti, è probabile che entreremo nel territorio dell'utilizzo pcntl_fork()e exec()dall'interno di un processo Apache, e questo è solo un brutto mojo.


1
hai detto che è un brutto mojo. puoi elaborare per favore?
Mayank

1

Funzionerà ma dovrai stare attento a non sovraccaricare il tuo server perché creerà un nuovo processo ogni volta che chiami questa funzione che verrà eseguita in background. Se solo una chiamata simultanea allo stesso tempo, questa soluzione alternativa farà il lavoro.

In caso contrario, consiglierei di eseguire una coda di messaggi come ad esempio beanstalkd / gearman / amazon sqs.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.