Impostazione del timeout di Curl in PHP


230

Sto eseguendo una richiesta di arricciatura su un database eXist tramite php. Il set di dati è molto grande e, di conseguenza, il database impiega costantemente molto tempo per restituire una risposta XML. Per risolvere questo, abbiamo impostato una richiesta di arricciatura, con quello che dovrebbe essere un lungo timeout.

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

Tuttavia, la richiesta di arricciatura termina in modo coerente prima che la richiesta sia completata (<1000 quando richiesto tramite un browser). Qualcuno sa se questo è il modo corretto di impostare i timeout in arricciatura?

Risposte:


346

Vedi documentazione: http://www.php.net/manual/en/function.curl-setopt.php

CURLOPT_CONNECTTIMEOUT- Il numero di secondi di attesa durante il tentativo di connessione. Usa 0 per attendere indefinitamente.
CURLOPT_TIMEOUT- Il numero massimo di secondi per consentire l'esecuzione delle funzioni cURL.

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

inoltre, non dimenticare di ingrandire l'esecuzione temporale dello script php self:

set_time_limit(0);// to infinity for example

13
Non è necessario set_time_limit(0);se lo script è in esecuzione sulla console.
CONvocato

6
@PedroLobito quello che dici è la configurazione di default di php su cli, ma è possibile che questo sia stato modificato.
Cherouvim,

4
@cherouvim è ovviamente corretto qui (corri php -d max_execution_time=1 -r 'while(true){$r=1*1;}'o qualcosa da osservare in azione che il cli non ha una bandiera 'sempre illimitata' magica.
Wrikken

@Pedro Lobito non ti serve set_time_limit(0)se non lo usi all'interno di un loop.
Viktor Joras,

58

Hmm, mi sembra che CURLOPT_TIMEOUTdefinisca la quantità di tempo che qualsiasi funzione CURL è autorizzata ad eseguire. Penso che dovresti effettivamente guardare CURLOPT_CONNECTTIMEOUTinvece, dal momento che questo dice a cURL il massimo tempo di attesa per il completamento della connessione.


Mentre i documenti in PHP dicono CURLOPT_TIMEOUTdi quanto tempo impiega la funzione, i documenti della libreria di curl sottostanti sembrano dire quanto tempo impiega la richiesta, il che è una distinzione interessante - non sono sicuro di come leggerlo!
fideloper,

Credo che qui è la migliore interpretazione: stackoverflow.com/questions/27776129/...
fideloper

33

C'è una stranezza con questo che potrebbe essere rilevante per alcune persone ... Dai commenti dei documenti PHP.

Se si desidera timeout di cURL in meno di un secondo, è possibile utilizzare CURLOPT_TIMEOUT_MS, sebbene sia presente un bug / "funzione" su "sistemi di tipo Unix" che causa il timeout di libcurl immediatamente se il valore è <1000 ms con l'errore "cURL Errore (28): Timeout raggiunto ". La spiegazione per questo comportamento è:

"Se libcurl è stato creato per utilizzare il risolutore di nomi di sistema standard, quella parte del trasferimento utilizzerà comunque la risoluzione di un secondo per i timeout con un timeout minimo consentito di un secondo."

Ciò che questo significa per gli sviluppatori PHP è "Non puoi usare questa funzione senza prima provarla, perché non puoi dire se libcurl sta usando il risolutore di nomi di sistema standard (ma puoi essere abbastanza sicuro che lo sia)"

Il problema è che su (Li | U) nix, quando libcurl utilizza il risolutore di nomi standard, durante la risoluzione dei nomi viene generato un SIGALRM che libcurl ritiene sia l'allarme di timeout.

La soluzione è disabilitare i segnali utilizzando CURLOPT_NOSIGNAL. Ecco uno script di esempio che si richiede causando un ritardo di 10 secondi in modo da poter testare i timeout:

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

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


Ciao, questo codice funziona ma il file sorgente è 7 MB e questo mi scarica solo 52 KB, cosa potrebbe esserci di sbagliato? L'URL è qualcosa come webserver.tld / folder / download /…
Muflix


Va notato che ci si aspetta un errore di timeout con questo script
kmoney12

30

Il codice imposta il timeout su 1000 secondi . Per millisecondi, utilizzare CURLOPT_TIMEOUT_MS.


13

Dovrai assicurarti dei timeout tra te e il file. In questo caso PHP e Curl.

A dire Curl mai timeout quando un trasferimento è ancora attivo, è necessario impostare CURLOPT_TIMEOUTa 0, al posto di 1000.

curl_setopt($ch, CURLOPT_TIMEOUT, 0);

In PHP, di nuovo, è necessario rimuovere i limiti di tempo o PHP stesso (dopo 30 secondi di default) ucciderà lo script lungo la richiesta di Curl. Questo da solo dovrebbe risolvere il tuo problema .
Inoltre, se si richiede l'integrità dei dati, è possibile aggiungere un livello di sicurezza utilizzando 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);

Una disconnessione del client interromperà l'esecuzione dello script e potrebbe danneggiare i dati,
ad es. query su database non transitorio, creazione di un file di configurazione, ecc., mentre nel tuo caso scaricherà un file parziale ... e potresti, o no, preoccupartene.

Rispondere a questa vecchia domanda perché questo thread è in cima alle ricerche del motore per CURL_TIMEOUT.


8

Non è possibile eseguire la richiesta da un browser, il timeout attende che il server che esegue la richiesta CURL risponda. Il browser sta probabilmente scadendo in 1-2 minuti, il timeout di rete predefinito.

È necessario eseguirlo dalla riga di comando / terminale.


2
+1: il timeout è probabilmente esterno all'arricciatura. Puoi effettivamente aggirare il timeout del browser assicurandoti di inviare periodicamente qualcosa; i browser in genere ripristinano il timeout ogni volta che ricevono più dati. Ma questo è un trucco; l'esecuzione tramite CLI è (quasi?) sempre preferibile.
Frank Farmer,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.