Einstellen des Curl-Timeouts in PHP

230

Ich führe eine Curl-Anfrage in einer eXist-Datenbank über PHP aus. Das Dataset ist sehr groß, und daher benötigt die Datenbank durchweg viel Zeit, um eine XML-Antwort zurückzugeben. Um dies zu beheben, haben wir eine Curl-Anfrage mit einer angeblich langen Zeitüberschreitung eingerichtet.

$ch = curl_init();
$headers["Content-Length"] = strlen($postString);
$headers["User-Agent"] = "Curl/1.0";

curl_setopt($ch, CURLOPT_URL, $requestUrl);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, 'admin:');
curl_setopt($ch,CURLOPT_TIMEOUT,1000);
$response = curl_exec($ch);
curl_close($ch);

Die Curl-Anforderung endet jedoch konsistent, bevor die Anforderung abgeschlossen ist (<1000, wenn sie über einen Browser angefordert wird). Weiß jemand, ob dies der richtige Weg ist, um Timeouts in Curl zu setzen?

Moki
quelle

Antworten:

346

Siehe Dokumentation: http://www.php.net/manual/en/function.curl-setopt.php

CURLOPT_CONNECTTIMEOUT- Die Anzahl der Sekunden, die beim Versuch, eine Verbindung herzustellen, gewartet werden muss. Verwenden Sie 0, um unbegrenzt zu warten.
CURLOPT_TIMEOUT- Die maximale Anzahl von Sekunden, um die Ausführung von cURL-Funktionen zu ermöglichen.

curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0); 
curl_setopt($ch, CURLOPT_TIMEOUT, 400); //timeout in seconds

Vergessen Sie auch nicht, die Zeitausführung des PHP-Skripts selbst zu verlängern:

set_time_limit(0);// to infinity for example
msangel
quelle
13
Sie brauchen nicht, set_time_limit(0);wenn das Skript auf der Konsole ausgeführt wird.
CONvid19
6
@PedroLobito Was Sie erwähnen, ist die Standardkonfiguration des PHP auf CLI, aber es ist möglich, dass dies geändert wurde.
Cherouvim
4
@cherouvim ist hier offensichtlich richtig (einfach laufen php -d max_execution_time=1 -r 'while(true){$r=1*1;}'oder etwas in Aktion beobachten, dass der Cli keine magische "immer unbegrenzte" Flagge hat.
Wrikken
@ Pedro Lobito brauchen set_time_limit(0)Sie nicht, wenn Sie es nicht in einer Schleife verwenden.
Viktor Joras
58

Hmm, es sieht für mich so aus, als würde es CURLOPT_TIMEOUTdie Zeit definieren, die eine cURL-Funktion für die Ausführung benötigt. Ich denke, Sie sollten sich CURLOPT_CONNECTTIMEOUTstattdessen umsehen, da dies cURL die maximale Zeit angibt, die gewartet werden muss, bis die Verbindung hergestellt ist.

Chad Birch
quelle
Während die docs in PHP sagt , CURLOPT_TIMEOUTist , wie lange die Funktion übernimmt, die zugrunde liegende curl Bibliothek docs zu sagen scheinen darüber ist , wie lange dauert die Anforderung, die eine interessante Unterscheidung ist - nicht sicher , dass die Art und Weise zu lesen!
Fideloper
Ich denke, hier ist die beste Interpretation: stackoverflow.com/questions/27776129/…
fideloper
33

Es gibt eine Eigenart, die für einige Leute relevant sein könnte ... Aus den Kommentaren der PHP-Dokumente.

Wenn Sie möchten, dass cURL in weniger als einer Sekunde eine Zeitüberschreitung aufweist, können Sie diese verwenden CURLOPT_TIMEOUT_MS, obwohl es auf "Unix-ähnlichen Systemen" einen Fehler / eine "Funktion" gibt, die dazu führt, dass libcurl sofort eine Zeitüberschreitung aufweist, wenn der Wert <1000 ms mit dem Fehler "cURL" ist Fehler (28): Timeout wurde erreicht ". Die Erklärung für dieses Verhalten lautet:

"Wenn libcurl für die Verwendung des Standard-Systemnamen-Resolvers erstellt wurde, verwendet dieser Teil der Übertragung weiterhin eine Auflösung von einer vollen Sekunde für Zeitüberschreitungen mit einer zulässigen Mindestzeitüberschreitung von einer Sekunde."

Für PHP-Entwickler bedeutet dies: "Sie können diese Funktion nicht verwenden, ohne sie vorher zu testen, da Sie nicht feststellen können, ob libcurl den Standard-Systemnamen-Resolver verwendet (aber Sie können ziemlich sicher sein, dass dies der Fall ist)."

Das Problem ist, dass unter (Li | U) nix, wenn libcurl den Standard-Namensauflöser verwendet, während der Namensauflösung ein SIGALRM ausgelöst wird, das libcurl für den Timeout-Alarm hält.

Die Lösung besteht darin, Signale mit CURLOPT_NOSIGNAL zu deaktivieren. Hier ist ein Beispielskript, das sich selbst anfordert und eine Verzögerung von 10 Sekunden verursacht, damit Sie Zeitüberschreitungen testen können:

if (!isset($_GET['foo'])) {
    // Client
    $ch = curl_init('http://localhost/test/test_timeout.php?foo=bar');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_NOSIGNAL, 1);
    curl_setopt($ch, CURLOPT_TIMEOUT_MS, 200);
    $data = curl_exec($ch);
    $curl_errno = curl_errno($ch);
    $curl_error = curl_error($ch);
    curl_close($ch);

    if ($curl_errno > 0) {
        echo "cURL Error ($curl_errno): $curl_error\n";
    } else {
        echo "Data received: $data\n";
    }
} else {
    // Server
    sleep(10);
    echo "Done.";
}

Von http://www.php.net/manual/en/function.curl-setopt.php#104597

Simon East
quelle
Hallo, dieser Code funktioniert aber die Quelldatei ist 7MB und dieser Download hat mir nur 52KB, was könnte falsch sein? URL ist so etwas wie
webserver.tld
@ Simon East können Sie mir bitte helfen stackoverflow.com/questions/30861112/…
Nathan Srivi
Es sollte beachtet werden, dass Sie einen Timeout-Fehler mit diesem Skript erwarten
kmoney12
30

Ihr Code legt das Zeitlimit auf 1000 Sekunden fest . Verwenden Sie für Millisekunden CURLOPT_TIMEOUT_MS.

Matt Humphreys
quelle
12

Sie müssen sicherstellen, dass zwischen Ihnen und der Datei Zeitüberschreitungen bestehen. In diesem Fall PHP und Curl.

Zu sagen , Curl nie Timeout , wenn eine Übertragung noch aktiv ist, die Sie einstellen müssen , CURLOPT_TIMEOUTum 0, statt 1000.

curl_setopt($ch, CURLOPT_TIMEOUT, 0);

In PHP müssen Sie wiederum Zeitlimits entfernen, oder PHP selbst (standardmäßig nach 30 Sekunden) beendet das Skript gemäß Curls Anfrage. Dies allein sollte Ihr Problem beheben .
Wenn Sie Datenintegrität benötigen, können Sie außerdem eine Sicherheitsebene hinzufügen, indem Sie Folgendes verwenden ignore_user_abort:

# The maximum execution time, in seconds. If set to zero, no time limit is imposed.
set_time_limit(0);

# Make sure to keep alive the script when a client disconnect.
ignore_user_abort(true);

Eine Client-Trennung unterbricht die Ausführung des Skripts und beschädigt möglicherweise Daten,
z. Nicht-Übergangs-Datenbankabfrage, Erstellen einer Konfigurationsdatei usw., während in Ihrem Fall eine Teildatei heruntergeladen wird ... und Sie könnten sich darum kümmern oder nicht.

Beantwortung dieser alten Frage, da dieser Thread bei der Suche nach Suchmaschinen ganz oben steht CURL_TIMEOUT.

MarcoP
quelle
8

Sie können die Anforderung nicht über einen Browser ausführen. Es wird eine Zeitüberschreitung auftreten, bis der Server, auf dem die CURL-Anforderung ausgeführt wird, reagiert. Der Browser läuft wahrscheinlich in 1-2 Minuten ab, dem Standard-Netzwerk-Timeout.

Sie müssen es über die Befehlszeile / das Terminal ausführen.

Brent Baisley
quelle
2
+1 - Das Timeout liegt wahrscheinlich außerhalb des Curls. Sie können das Browser-Timeout tatsächlich umgehen, indem Sie sicherstellen, dass regelmäßig etwas ausgegeben wird. Browser setzen ihre Zeitüberschreitung im Allgemeinen jedes Mal zurück, wenn sie mehr Daten erhalten. Aber das ist ein Hack; Laufen über CLI ist (fast?) immer vorzuziehen.
Frank Farmer
3

Wenn Sie PHP als fastCGI-Anwendung verwenden, überprüfen Sie unbedingt die Einstellungen für das fastCGI-Zeitlimit. Siehe: PHP Curl Put 500 Fehler

wbinky
quelle