2010-03-16 14 views
13

Wir betreiben PHP auf einem Windows-Server (eine Quelle von vielen Problemen in der Tat, aber die Migration ist derzeit keine Option). Es gibt einige Punkte, an denen eine vom Benutzer initiierte Aktion einige Dinge auslösen muss, die eine Weile dauern und bei denen der Benutzer nicht wissen muss, ob sie erfolgreich sind oder fehlschlagen, wie zum Beispiel das Versenden einer E-Mail oder das Sicherstellen von einigen Drittanbieterkonten werden aktualisiert. Wenn ich nur mit pcntl_fork() forkieren könnte, wäre das sehr einfach, aber die PCNTL-Funktionen sind in Windows nicht verfügbar.Forking in PHP unter Windows

Es scheint, die nächste, die ich bekommen kann etwas dieser Art zu tun ist:

exec('php-cgi.exe somescript.php'); 

Dies wäre jedoch weitaus komplizierter sein. Die Aktionen, die ich starten muss, beruhen auf einer Menge von Kontexten, die bereits im laufenden Prozess existieren; um das obige Beispiel zu verwenden, müsste ich die wesentlichen Daten herausfinden und sie dem neuen Skript irgendwie zur Verfügung stellen. Wenn ich mich ablenken könnte, würde es nur darum gehen, dass der Elternprozess früh zurückkehrt und das Kind an ein paar weiteren Dingen arbeiten muss.

Ich habe ein paar Leute gefunden, die über ihre eigene Arbeit sprechen, indem sie verschiedene PCNTL-Funktionen unter Windows kompiliert haben, aber keine scheint etwas verfügbar zu haben (defekte Links, usw.).

Trotz this question praktisch den gleichen Namen wie meine, scheint es das Problem war mehr Ausführungs-Timeout als müssen Gabel. Also, ist meine beste Option, einfach ein wenig umzuformen, um mit dem Aufruf von php-cgi umzugehen, oder gibt es andere Möglichkeiten?

Edit: Es scheint exec() wird nicht funktionieren für diese, zumindest nicht ohne mich etwas anderen Aspekt davon herauszufinden, wie es wartet, bis der Anruf zurückkehrt. Ich dachte mir, ich könnte START verwenden, so ähnlich wie exec('start php-cgi.exe somescript.php');, aber es wartet immer noch, bis das andere Skript beendet ist.

+0

Haben Sie einen Cron-Job dafür in Betracht gezogen? (Einige Optionen stehen zur Verfügung, http://www.google.com/search?q = cron + windows) – user187291

+0

Von dem, was ich sehen kann, sieht es so aus, als würde das genauso gut funktionieren wie psexec, aber ich habe gerade mit psexec gearbeitet, also werde ich wahrscheinlich einfach dabei bleiben. –

Antwort

13

wie etwa installing psexec und verwenden Sie die -d (nicht warten) option

exec('psexec -d php-cgi.exe somescript.php'); 
+0

Ausgezeichnet, ich habe das zur Arbeit. Ich bin verwirrt, warum das Ausführen mit "Start" nicht in der Lage war zu tun, was ich brauchte. Außerdem musste ich psexec mit dem Parameter -accepteula aufrufen, obwohl ich es bereits manuell akzeptiert hatte, indem ich es selbst auf dem Server ausführte. –

+0

Wenn Sie nach einer Möglichkeit suchen, Variablen zu übergeben, dann verwenden Sie diese 'exec (" psexec -d php-cgi.exe somescript.php 'var1' 'var2' 'var3' ");' Dann in der PHP-Skript Sie ' Um die Variablen zu senden, verwenden Sie '$ argv [1]', '$ argv [2]' und '$ argv [3]'. –

3

Get PSExec und führen Sie den Befehl:

exec("psexec -d php-cgi.exe myfile.php"); 
+2

gut diese Antwort hat einen Link, aber der andere nicht – SeanDowney

1

Sie einen Daemon/Hintergrund-Prozess erstellen kann die laufen Code (z. B. E-Mails senden) und die Anfrage würde nur Elemente in die Warteschlange hinzufügen, lassen Sie die Deamon das schwere Heben.

Zum Beispiel kann eine Datei send_emails.bat:

cls 
C:\PHP533\php.exe D:\web\server.php 
exit 

offenen Windows-Taskplaner, und haben die oben send_emails.bat alle 30 Minuten laufen. Stellen Sie sicher, dass jeweils nur eine Instanz ausgeführt wird, oder führen Sie jede Aufgabe in mehreren Schritten aus, oder senden Sie jede E-Mail zweimal. Ich sage 30 Minuten für den Fall, dass etwas vorübergehend kaputtgeht (Speicherprobleme, Datenbank nicht verfügbar, usw.), es wird alle 30 Minuten neu gestartet, anstatt einen nie endenden Prozess zu haben, der einfach stoppt. Das Folgende ist ein Skelett-Dämon ... nicht vollständig oder testet ich gerade tippe ein Exempel:

<?php 
set_time_limit(60*30); // don't run 
$keepgoing = true; 
$timeout = time()+ 60*29; // 29 minutes 

while(time() < $timeout) 
{ 
    // grab emails from database 
    $result = $db->query('select subject, body, to_email FROM email_queue'); 
    if($result->num_rows == 0) 
    { 
     sleep(10); // so we are not taxing the database 
    } 
    else 
    { 
     while($row = $result->fetch_assoc()) 
     { 
     // send email 
     } 
    } 
} 
exit; 
?> 

Schließlich brauchen Sie nur die Anforderung das Element in die Warteschlange in einer Datenbank hinzuzufügen, und lassen Sie den Daemon Griff das schwere Heben.

$db->query('insert into email_queue(to,subject,body) values ('[email protected]','important email','<b>html body!</b>');