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 protected]');

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?

ToughPal
quelle
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
Mögliches Duplikat von PHP führen einen Hintergrundprozess aus
Sean the Bean

Antworten:

149

Wie wäre es mit Hinzufügen.

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

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

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

Jitter
quelle
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 &");
Brent Baisley
quelle
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

Oytun
quelle
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 .

Jason Plank
quelle
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
CONvid19
quelle
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.

Jason Plank
quelle
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.

Chaos
quelle
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.

Alfred
quelle