2010-04-06 27 views
162

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

$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 riccio finisce sempre prima che la richiesta è stata completata (< 1000 quando richiesto tramite un browser). Qualcuno sa se questo è il modo corretto per impostare i timeout in curl?

risposta

52

Hmm, mi sembra che CURLOPT_TIMEOUT definisca la quantità di tempo che ogni funzione CURL può eseguire per l'esecuzione. Penso che dovresti effettivamente guardare a CURLOPT_CONNECTTIMEOUT, poiché ciò indica a cURL il tempo massimo di attesa per il completamento della connessione.

+0

Mentre il [docs in PHP] (http://php.net/manual/en/function.curl-setopt.php) dice 'CURLOPT_TIMEOUT' indica il tempo impiegato dalla funzione, i [sottostanti documenti della libreria di arricciatura] (http://curl.haxx.se/libcurl/c/CURLOPT_TIMEOUT.html) sembra dire che si tratta di quanto tempo richiede la richiesta, che è una distinzione interessante - non è sicuro quale sia il modo di leggerlo! – fideloper

+0

Penso che questa sia la migliore interpretazione: http://stackoverflow.com/questions/27776129/php-curl-curlopt-connecttimeout-vs-curlopt-timeout – fideloper

8

Non è possibile eseguire la richiesta da un browser, verrà timeout in attesa che il server che esegue la richiesta CURL risponda. Probabilmente il tempo di attesa del browser è 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 emettere periodicamente qualcosa; i browser generalmente azzerano il loro timeout ogni volta che ricevono più dati. Ma questo è un hack; correre via CLI è (quasi?) sempre preferibile. –

25

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

249

vedere la 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 aspettare indefinitamente.
CURLOPT_TIMEOUT - Il numero massimo di secondi per consentire l'esecuzione di funzioni cURL.

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

inoltre, non dimenticare di allargare tempo di esecuzione di script PHP sé:

set_time_limit(0);// to infinity for example 
+5

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

+0

@PedroLobito quello che citi è la configurazione di default del php su cli, ma è possibile che questo possa essere stato modificato. – cherouvim

+0

Hai controllato i documenti? –

18

C'è una stranezza con questa che potrebbero essere rilevanti per alcune persone ... Dai commenti docs PHP.

Se si desidera cURL per timeout in meno di un secondo, è possibile utilizzare CURLOPT_TIMEOUT_MS, anche se c'è un bug/"funzione" on "sistemi Unix-like" che provoca libcurl timeout immediatamente se il valore è < 1000 ms con l'errore "cURL Error (28): Timeout raggiunto". La spiegazione di questo comportamento è:

"Se libcurl è stato creato per utilizzare il resolver di nome di sistema standard, quella parte del trasferimento utilizzerà comunque la risoluzione full-second per i timeout con un timeout minimo di un secondo."

Ciò significa per gli sviluppatori PHP: "Non è possibile utilizzare questa funzione senza prima verificarla, perché non si può sapere se libcurl sta utilizzando il resolver di nome di sistema standard (ma si può essere abbastanza sicuri che lo sia)"

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

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

<?php 
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

+0

Ciao, questo codice funziona ma il file sorgente è 7MB e questo mi scarica solo 52KB, cosa potrebbe essere sbagliato? L'URL è qualcosa come http: //webserver.tld/folder/download/file.do? Name = file.zip & _lg = en_US – Muflix

+0

@Simon East, per favore aiutami http://stackoverflow.com/questions/30861112/scrap- amazon-all-deals-php-curl –

+0

Va notato che * si aspetta * un errore di timeout con questo script – hellohellosharp

3

Se si utilizza PHP come un'applicazione FastCGI quindi assicuratevi di controllare le impostazioni di timeout fastCGI. Vedi: PHP curl put 500 error

5

È necessario accertarsi di timeout tra l'utente e il file. In questo caso PHP e Curl.

Per dire a Curl di non scadere mai quando un trasferimento è ancora attivo, è necessario impostare CURLOPT_TIMEOUT su 0, anziché su 1000.

curl_setopt($ch, CURLOPT_TIMEOUT, 0); 

In PHP, ancora una volta, è necessario rimuovere limiti di tempo o PHP è di per sé (dopo 30 secondi per impostazione predefinita) ucciderà la sceneggiatura insieme la richiesta di Curl. Questo da solo dovrebbe risolvere il problema.
Inoltre, se hai bisogno di integrità dei dati, si potrebbe aggiungere un ulteriore 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 client interrompere l'esecuzione dello script e dei dati potenzialmente dannosa,
ad es. query di database non transizionale, creazione di un file di configurazione, ecc., mentre nel tuo caso scaricherà un file parziale ... e potresti preoccuparti o meno di questo.

Rispondere a questa vecchia domanda perché questo thread è in cima al motore cerca CURL_TIMEOUT.