72 Stimmen

PHP-Ausführung nach dem Senden der HTTP-Antwort fortsetzen

Wie kann ich PHP 5.2 (das als apache mod_php läuft) dazu bringen, eine vollständige HTTP-Antwort an den Client zu senden und dann noch eine Minute lang weitere Operationen auszuführen?

Die lange Geschichte:

Ich habe ein PHP-Skript, das einige lange Datenbankabfragen ausführen und E-Mails versenden muss, was 45 bis 60 Sekunden dauert. Dieses Skript wird von einer Anwendung aufgerufen, über die ich keine Kontrolle habe. Ich möchte, dass die Anwendung alle vom PHP-Skript empfangenen Fehlermeldungen meldet (meist Fehler bei ungültigen Parametern).

Die Anwendung hat eine Timeout-Verzögerung von weniger als 45 Sekunden (ich kenne den genauen Wert nicht) und registriert daher jede Ausführung des PHP-Skripts als Fehler. Daher muss PHP die vollständige HTTP-Antwort so schnell wie möglich an den Client senden (idealerweise, sobald die Eingabeparameter validiert wurden) und dann die Datenbank- und E-Mail-Verarbeitung ausführen.

Ich verwende mod_php, also pcntl_fork ist nicht verfügbar. Ich könnte dieses Problem umgehen, indem ich die zu verarbeitenden Daten in der Datenbank speichere und den eigentlichen Prozess von cron aber ich suche nach einer kürzeren Lösung.

5 Stimmen

Entschuldigung, aber das sieht nach einem totalen Missbrauch der PHP-Sprache aus.

3 Stimmen

Es handelt sich weniger um einen Missbrauch der PHP-Sprache als um einen Missbrauch eines Webserver-Prozesses. Wenn kein HTTP/Web mehr involviert ist, sollte kein Webserver damit beschäftigt sein.

83 Stimmen

Systemmissbrauch hin oder her, manchmal müssen wir Dinge tun, die wir nicht mögen, weil sie außerhalb unserer Kontrolle liegen. Das macht die Frage nicht ungültig, es macht die Situation nur unglücklich.

5voto

Déjà vu Punkte 27104

Sie können die PHP-Funktion register-shutdown-function die etwas ausführen wird nach das Skript hat seinen Dialog mit dem Browser abgeschlossen.

Siehe auch ignore_user_abort - aber Sie sollten diese Funktion nicht benötigen, wenn Sie die Funktion register_shutdown_function verwenden. Auf derselben Seite, set_time_limit(0) wird verhindern, dass Ihr Skript eine Zeitüberschreitung verursacht.

4voto

Nir O. Punkte 1451

Die Verwendung einer Warteschlange, eines exec- oder cron-Skripts wäre ein Overkill für diese einfache Aufgabe. Es gibt keinen Grund, nicht innerhalb desselben Skripts zu bleiben. Diese Kombination hat bei mir hervorragend funktioniert:

        ignore_user_abort(true);
        $response = "some response"; 
        header("Connection: close");
        header("Content-Length: " . mb_strlen($response));
        echo $response;
        flush(); // releasing the browser from waiting
        // continue the script with the slow processing here...

mehr lesen in: Wie setzt man den Prozess nach der Beantwortung einer Ajax-Anfrage in PHP fort?

4voto

sigalor Punkte 631

Es ist möglich, dafür cURL zu verwenden, mit einem sehr kurzen Timeout. Dies wäre Ihre Hauptdatei:

<?php>
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "http://example.com/processor.php");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_TIMEOUT_MS, 10);      //just some very short timeout
    curl_exec($ch);
    curl_close($ch);
?>

Und das ist Ihre Prozessordatei:

<?php
    ignore_user_abort(true);                       //very important!
    for($x = 0; $x < 10; $x++)                     //do some very time-consuming task
        sleep(10);
?>

Wie Sie sehen können, wird das obere Skript nach einer kurzen Zeit (in diesem Fall 10 Millisekunden) eine Zeitüberschreitung verursachen. Es ist möglich, dass CURLOPT_TIMEOUT_MS funktioniert nicht so, in diesem Fall wäre es äquivalent zu curl_setopt($ch, CURLOPT_TIMEOUT, 1) .

Wenn also auf die Prozessordatei zugegriffen wurde, wird sie ihre Aufgaben erfüllen, unabhängig davon, dass der Benutzer (d. h. die aufrufende Datei) die Verbindung abbricht.

Natürlich können Sie auch GET- oder POST-Parameter zwischen den Seiten übergeben.

3voto

Ignacio Vazquez Punkte 535

Sie können eine http-Anfrage zwischen Server und Server erstellen. (es wird kein Browser benötigt). Das Geheimnis, um eine HTTP-Anfrage im Hintergrund zu erstellen, ist die Einstellung eines sehr kleinen Timeouts, damit die Antwort ignoriert wird.

Dies ist eine funktionierende Funktion, die ich für diesen Zweck verwendet habe:

MAI 31 Asynchrone PHP-Hintergrundanforderung Eine weitere Möglichkeit, eine asynchrone Anfrage in PHP zu erstellen (Simulation des Hintergrundmodus).

 /**
  * Another way to make asyncronous (o como se escriba asincrono!) request with php
  * Con esto se puede simpular un fork en PHP.. nada que envidarle a javita ni C++
  * Esta vez usando fsockopen
  * @author PHPepe
  * @param  unknown_type $url
  * @param  unknown_type $params
  */
 function phpepe_async($url, $params = array()) {
  $post_params = array(); 
     foreach ($params as $key => &$val) {
       if (is_array($val)) $val = implode(',', $val);
         $post_params[] = $key.'='.urlencode($val);
     }
     $post_string = implode('&', $post_params);

     $parts=parse_url($url);

     $fp = fsockopen($parts['host'],
         isset($parts['port'])?$parts['port']:80,
         $errno, $errstr, 30);

     $out = "POST ".$parts['path']." HTTP/1.1\r\n";
     $out.= "Host: ".$parts['host']."\r\n";
     $out.= "Content-Type: application/x-www-form-urlencoded\r\n";
     $out.= "Content-Length: ".strlen($post_string)."\r\n";
     $out.= "Connection: Close\r\n\r\n";
     if (isset($post_string)) $out.= $post_string;

     fwrite($fp, $out);
     fclose($fp);
 }

 // Usage:
 phpepe_async("http://192.168.1.110/pepe/feng_scripts/phprequest/fork2.php");

Weitere Informationen finden Sie unter http://www.phpepe.com/2011/05/php-asynchronous-background-request.html

0voto

Ryan Chouinard Punkte 2046

Bah, ich habe Ihre Anforderungen missverstanden. Sieht so aus, als ob sie tatsächlich sind:

  • Das Skript erhält Eingaben von einer externen Quelle, die Sie nicht kontrollieren
  • Das Skript verarbeitet und validiert die Eingaben und teilt der externen Anwendung mit, ob sie in Ordnung sind oder nicht, und beendet die Sitzung.
  • Das Drehbuch ist der Beginn eines langwierigen Prozesses.

In diesem Fall würde die Verwendung einer externen Warteschlange und/oder eines Cron-Systems funktionieren. Nachdem die Eingabe überprüft wurde, fügen Sie die Auftragsdetails in die Warteschlange ein und beenden Sie den Vorgang. Ein anderes Skript kann dann ausgeführt werden, die Auftragsdaten aus der Warteschlange abholen und den längeren Prozess starten. Alex Howansky hat die richtige Idee.

Entschuldigung, ich gebe zu, dass ich beim ersten Mal ein wenig überflogen habe.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X