Gibt es eine Möglichkeit, shell_exec zu verwenden, ohne auf den Abschluss des Befehls zu warten?


95

Ich habe eine prozessintensive Aufgabe, die ich im Hintergrund ausführen möchte.

Der Benutzer klickt auf eine Seite, das PHP-Skript wird ausgeführt und schließlich muss unter bestimmten Bedingungen, falls erforderlich, ein Shell-Skript ausgeführt werden, z.

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

Derzeit verwende ich shell_exec , aber dazu muss das Skript auf eine Ausgabe warten. Gibt es eine Möglichkeit, den gewünschten Befehl auszuführen, ohne darauf zu warten, dass er ausgeführt wird?


HINWEIS: Der Prozess muss sofort gestartet werden, damit ein Cron keine Option ist.
ToughPal

2
Nur eine kurze Anmerkung: Stellen Sie sicher, dass die Seite nicht für alle zugänglich ist (Suchmaschinen / betrügerische Benutzer). Wenn Sie sich in einer gemeinsam genutzten Umgebung befinden, ist die Ausführungszeit aller Ihrer Skripte (insbesondere PHP!) Wahrscheinlich begrenzt. In jedem Fall möchten Sie vielleicht einen Blick auf set_time_limit / php.ini werfen.
Merkuro

Antworten:


149

Wie wäre es mit Hinzufügen.

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

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

Beachten Sie, dass dadurch auch stdio und stderr entfernt werden.


2
Nein, keine Nebenwirkungen. Wenn Sie sich irgendwann für die stdio oder stderr Ausgabe Ihres Prozesses entscheiden, sollten Sie stackoverflow.com/questions/45953/…
jitter

1
Frage: Das ist nur das Verwerfen der Ausgabe, oder? Wartet PHP noch auf den Abschluss des Prozesses, bevor die Ausführung fortgesetzt wird, oder wird es ausgelöst und vergessen?
Alan Storm

5
Ja, wirft weg. Ja Feuer und vergessen
Jitter

3
Hinweis: > /dev/null 2>&1 &Wie in anderen Antworten zu sehen ist, wird hier eine knappe Form > /dev/null 2>/dev/null &angegeben. Dies bedeutet im Grunde "STDERR (2) an dieselbe Stelle wie STDOUT (& 1) umleiten".
Rymo

3
Normalerweise erhalte ich die PID für das Ausführen eines Skripts, indem ich echo $ hinzufüge! >> /tmp/pid.txt am Ende des Befehls exec, aber durch Umleiten von output & error nach / dev / null, keine PID-Datei mehr: Kann einer von Ihnen die PID des von exec gestarteten Skripts erhalten, ohne auf die Ausgabe zu warten?
Umarmungen

28

Dadurch wird ein Befehl ausgeführt und die Verbindung zum laufenden Prozess getrennt. Natürlich kann es ein beliebiger Befehl sein. Für einen Test können Sie jedoch eine PHP-Datei mit dem Befehl sleep (20) erstellen.

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

ist es besser dies oder shell_exec?
Realtebo

Hallo, kann ich die Funktion mit dieser shell_exec ausführen ("nohup / usr / bin / php -f example.com/notifications/sendnotifications_async > / dev / null 2> & 1 &");
Waseem Bashir

Warum beides nohup und das &?
Bugmenot123

11

Sie können Ihre Ausgabe auch sofort an den Client zurückgeben und anschließend Ihren PHP-Code weiter verarbeiten.

Dies ist die Methode, die ich für lang wartende Ajax-Aufrufe verwende, die auf der Clientseite keine Auswirkungen haben würden:

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.

Die ausführliche Erklärung finden Sie hier: http://oytun.co/response-now-process-later


1
Ops ... Ich habe hier eine Zombie-Frage geweckt, ich habe es nicht bemerkt. Diese Informationen könnten jedoch für andere von Vorteil sein.
Oytun

2
Dies hat nichts mit shell_exec zu tun
bugmenot123

8

Unter Windows 2003 habe ich Folgendes verwendet, um ein anderes Skript aufzurufen, ohne zu warten:

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

Dies funktioniert nur, nachdem cmd.exeSie Änderungsberechtigungen für - Hinzufügen von Lesen und Ausführen für IUSR_YOURMACHINE(ich habe auch Schreiben auf Verweigern gesetzt) hinzugefügt haben .


7

Sicher, denn windowsSie können verwenden:

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

Hinweis:

Wenn Sie eine COMFehlermeldung erhalten, fügen Sie die Erweiterung zu Ihrer hinzu php.iniund starten Sie neu apache:

[COM_DOT_NET]
extension=php_com_dotnet.dll

Ich habe keine Ahnung, aber es hat bei mir funktioniert. Bitte erklären Sie jemandem, was wscript.shell ist und was es tut.
GeekWithGlasses

Können Sie bitte erklären, warum diese Zeile keine Ausgabe liefert? $ oExec = $ WshShell-> Run ('C: \ Benutzer \ Shreyash \ Desktop \ phantomjs-2.1.1-windows \ bin \ phantomjs.exe -f C: \ xampp \ htdocs \ composer \ test_0.js', 0 , false); `
GeekWithGlasses

Möglicherweise ist bei test_0.js ein Fehler aufgetreten. Überprüfen Sie das Phantomprotokoll.
CONvid19

6

Verwenden Sie den popenBefehl von PHP , z.

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

Dadurch wird ein untergeordneter Prozess erstellt und das Skript wird im Hintergrund ausgeführt, ohne auf die Ausgabe zu warten.


4
Es wartet auf das Ende des untergeordneten Prozesses. Zumindest auf Win
Max Chernopolsky

Der Hintergrund hier wird mit Hilfe des Windows-Befehls "start" erreicht, der der Exe vorangestellt ist, die Sie ausführen möchten. Es funktioniert nicht, wenn Sie es weglassen, und ich würde nicht erwarten, dass es auf einem anderen Betriebssystem funktioniert ... aber es funktioniert funktioniert für mich, danke! :-)
Antony

1

Wenn es sich nicht um eine Webseite handelt, empfehle ich, ein Signal zu generieren (z. B. eine Datei in einem Verzeichnis abzulegen) und die Arbeit, die erledigt werden muss, von einem Cron-Job übernehmen zu lassen. Andernfalls werden wir wahrscheinlich in das Gebiet der Verwendung pcntl_fork()und exec()von innerhalb eines Apache-Prozesses gelangen, und das ist nur schlechtes Mojo.


1
Du hast gesagt, es ist ein schlechtes Mojo. Kannst du das bitte näher erläutern?
Mayank

1

Das wird funktionieren, aber Sie müssen darauf achten, Ihren Server nicht zu überlasten, da jedes Mal, wenn Sie diese Funktion aufrufen, ein neuer Prozess erstellt wird, der im Hintergrund ausgeführt wird. Wenn nur ein Anruf gleichzeitig ausgeführt wird, erledigt diese Problemumgehung die Aufgabe.

Wenn nicht, würde ich empfehlen, eine Nachrichtenwarteschlange wie beispielsweise beanstalkd / gearman / amazon sqs auszuführen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.