Ustawianie limitu czasu Curl w PHP

230

Uruchamiam żądanie curl w bazie danych eXist przez php. Zestaw danych jest bardzo duży, w wyniku czego baza danych konsekwentnie zajmuje dużo czasu, aby zwrócić odpowiedź XML. Aby to naprawić, skonfigurowaliśmy żądanie zwijania, którego czas oczekiwania powinien być długi.

$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);

Jednak żądanie zwijania konsekwentnie kończy się przed zakończeniem żądania (<1000, gdy jest wymagane przez przeglądarkę). Czy ktoś wie, czy jest to właściwy sposób na ustawienie limitów czasu w zwijaniu?

Moki
źródło

Odpowiedzi:

346

Zobacz dokumentację: http://www.php.net/manual/en/function.curl-setopt.php

CURLOPT_CONNECTTIMEOUT- Liczba sekund oczekiwania podczas próby połączenia. Użyj 0, aby czekać w nieskończoność.
CURLOPT_TIMEOUT- Maksymalna liczba sekund, aby umożliwić wykonanie funkcji cURL.

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

również nie zapomnij powiększyć czasu wykonywania skryptu PHP:

set_time_limit(0);// to infinity for example
msangel
źródło
13
Nie potrzebujesz, set_time_limit(0);jeśli skrypt działa na konsoli.
CONvid19,
6
@PedroLobito to, o czym wspominasz, to domyślna konfiguracja php na cli, ale możliwe, że mogła zostać zmodyfikowana.
cherouvim
4
@cherouvim ma tutaj oczywiście rację (po prostu biegnij php -d max_execution_time=1 -r 'while(true){$r=1*1;}'lub obserwuj w akcji, że cli nie ma magicznej flagi „zawsze nieograniczona”.
Wrikken,
@Pedro Lobito nie potrzebujesz, set_time_limit(0)jeśli nie używasz go w pętli.
Viktor Joras,
58

Hmm, wydaje mi się, że CURLOPT_TIMEOUTokreśla czas, jaki może zająć wykonanie dowolnej funkcji cURL. Myślę, że CURLOPT_CONNECTTIMEOUTzamiast tego powinieneś na to patrzeć , ponieważ oznacza to, że cURL określa maksymalny czas oczekiwania na zakończenie połączenia.

Chad Birch
źródło
Podczas gdy dokumenty w PHP mówią CURLOPT_TIMEOUTo tym, jak długo trwa ta funkcja, bazowe dokumenty biblioteki curl wydają się mówić, jak długo trwa to żądanie, co jest ciekawym rozróżnieniem - nie jestem pewien, w jaki sposób to przeczytać!
fideloper
Myślę, że tutaj jest najlepsza interpretacja: stackoverflow.com/questions/27776129/...
fideloper
33

Jest to dziwactwo, które może być istotne dla niektórych osób ... Z komentarzy doktorów PHP.

Jeśli chcesz, aby cURL przekroczył limit czasu w czasie krótszym niż jedna sekunda, możesz go użyć CURLOPT_TIMEOUT_MS, chociaż istnieje błąd / „funkcja” w „systemach uniksowych”, które powodują natychmiastowe przekroczenie limitu czasu libcurl, jeśli wartość wynosi <1000 ms z błędem „cURL Błąd (28): Osiągnięto limit czasu ”. Wyjaśnienie tego zachowania jest następujące:

„Jeśli libcurl jest zbudowany na standardowym systemie rozpoznawania nazw systemu, w tej części przesyłania nadal będzie używana pełna sekundowa rozdzielczość dla limitów czasu z minimalnym dopuszczalnym limitem czasu wynoszącym jedną sekundę.”

Dla programistów PHP oznacza to: „Nie możesz użyć tej funkcji bez uprzedniego przetestowania, ponieważ nie możesz stwierdzić, czy libcurl używa standardowego systemu rozpoznawania nazw systemów (ale możesz być całkiem pewien, że tak jest)”

Problem polega na tym, że w (Li | U) nix, gdy libcurl używa standardowego rozpoznawania nazw, podczas rozpoznawania nazw powstaje SIGALRM, który zdaniem libcurl jest alarmem przekroczenia limitu czasu.

Rozwiązaniem jest wyłączenie sygnałów za pomocą CURLOPT_NOSIGNAL. Oto przykładowy skrypt, który sam się żąda, powodując 10-sekundowe opóźnienie, abyś mógł przetestować limity czasu:

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.";
}

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

Simon East
źródło
Witaj, ten kod działa, ale plik źródłowy ma 7 MB i ten plik do pobrania ma tylko 52 KB, co może być nie tak? Adres URL jest podobny do webserver.tld / folder / download /…
Muflix
@ Simon East, czy możesz mi pomóc stackoverflow.com/questions/30861112/...
Nathan Srivi
Należy zauważyć, że spodziewasz się
przekroczenia
30

Twój kod ustawia limit czasu na 1000 sekund . Dla milisekund użyj CURLOPT_TIMEOUT_MS.

Matt Humphreys
źródło
13

Musisz upewnić się co do limitów czasu między tobą a plikiem. W tym przypadku PHP i Curl.

Aby powiedzieć Curlowi, aby nigdy nie przekraczał limitu czasu, gdy transfer jest nadal aktywny, musisz ustawić CURLOPT_TIMEOUTna 0zamiast 1000.

curl_setopt($ch, CURLOPT_TIMEOUT, 0);

W PHP ponownie musisz usunąć limity czasowe, w przeciwnym razie PHP (domyślnie po 30 sekundach) zabije skrypt zgodnie z żądaniem Curl. To samo powinno rozwiązać problem .
Ponadto, jeśli potrzebujesz integralności danych, możesz dodać warstwę bezpieczeństwa, używając 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);

Rozłączenie klienta przerwie wykonywanie skryptu i może spowodować uszkodzenie danych,
np. nieprzejściowe zapytanie do bazy danych, budowanie pliku konfiguracyjnego itd., podczas gdy w twoim przypadku pobierałby plik częściowy ... i możesz się tym przejmować lub nie.

Odpowiadając na to stare pytanie, ponieważ ten wątek znajduje się na górze wyszukiwanych haseł CURL_TIMEOUT.

MarcoP
źródło
8

Nie można uruchomić żądania z przeglądarki, upłynie limit czasu oczekiwania na odpowiedź serwera z uruchomionym żądaniem CURL. Limit czasu przeglądarki prawdopodobnie upłynie za 1-2 minuty, co jest domyślnym limitem czasu sieci.

Musisz uruchomić go z wiersza poleceń / terminala.

Brent Baisley
źródło
2
+1 - przekroczenie limitu czasu jest prawdopodobnie zewnętrzne. Możesz faktycznie obejść limit czasu przeglądarki, upewniając się, że co jakiś czas wysyłasz coś; przeglądarki zazwyczaj resetują limit czasu za każdym razem, gdy otrzymują więcej danych. Ale to hack; uruchamianie przez CLI jest (prawie?) zawsze preferowane.
Frank Farmer,