Establecer el tiempo de espera de Curl en PHP

230

Estoy ejecutando una solicitud curl en una base de datos eXist a través de php. El conjunto de datos es muy grande y, como resultado, la base de datos demora mucho tiempo en devolver una respuesta XML. Para solucionar eso, configuramos una solicitud curl, con lo que se supone que es un largo tiempo de espera.

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

Sin embargo, la solicitud de curl termina consistentemente antes de que se complete la solicitud (<1000 cuando se solicita a través de un navegador). ¿Alguien sabe si esta es la forma correcta de establecer tiempos de espera en rizo?

Moki
fuente

Respuestas:

346

Ver documentación: http://www.php.net/manual/en/function.curl-setopt.php

CURLOPT_CONNECTTIMEOUT- El número de segundos para esperar mientras intenta conectarse. Use 0 para esperar indefinidamente.
CURLOPT_TIMEOUT- El número máximo de segundos para permitir que se ejecuten las funciones de cURL.

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

Tampoco olvides ampliar el tiempo de ejecución del script php self:

set_time_limit(0);// to infinity for example
msangel
fuente
13
No necesita set_time_limit(0);si el script se está ejecutando en la consola.
CONvid19
66
@PedroLobito lo que mencionas es la configuración predeterminada del php en cli, pero es posible que esto haya sido modificado.
cherouvim
44
@cherouvim es obviamente correcto aquí (solo corre php -d max_execution_time=1 -r 'while(true){$r=1*1;}'o algo para observar en acción que el cli no tiene una bandera mágica 'siempre ilimitada'.
Escrito el
@Pedro Lobito no necesitas set_time_limit(0)si no lo estás usando dentro de un bucle.
Viktor Joras
58

Hmm, me parece que CURLOPT_TIMEOUTdefine la cantidad de tiempo que cualquier función cURL puede tardar en ejecutarse. Creo que en realidad debería estar mirando CURLOPT_CONNECTTIMEOUT, ya que eso le dice a cURL la cantidad máxima de tiempo para esperar a que se complete la conexión.

Abedul Chad
fuente
Si bien los documentos en PHP dicen que CURLOPT_TIMEOUTse trata de cuánto tiempo lleva la función, los documentos subyacentes de la biblioteca curl parecen decir que se trata de cuánto tiempo lleva la solicitud, lo cual es una distinción interesante, ¡no estoy seguro de qué manera leer eso!
fideloper
Creo que esta es la mejor interpretación: stackoverflow.com/questions/27776129/…
fideloper
33

Hay una peculiaridad con esto que podría ser relevante para algunas personas ... De los comentarios de los documentos de PHP.

Si desea que cURL agote el tiempo de espera en menos de un segundo, puede usarlo CURLOPT_TIMEOUT_MS, aunque hay un error / "característica" en "sistemas tipo Unix" que hace que libcurl agote el tiempo de espera inmediatamente si el valor es <1000 ms con el error "cURL Error (28): Se alcanzó el tiempo de espera ". La explicación de este comportamiento es:

"Si libcurl está diseñado para usar el solucionador de nombres de sistema estándar, esa parte de la transferencia seguirá utilizando una resolución de segundo completo para tiempos de espera con un tiempo de espera mínimo permitido de un segundo".

Lo que esto significa para los desarrolladores de PHP es "No se puede usar esta función sin probarla primero, porque no se puede saber si libcurl está usando el sistema estándar de resolución de nombres (pero puede estar bastante seguro de que lo es)"

El problema es que en (Li | U) nix, cuando libcurl usa el solucionador de nombre estándar, se genera un SIGALRM durante la resolución de nombre que libcurl cree que es la alarma de tiempo de espera.

La solución es deshabilitar las señales usando CURLOPT_NOSIGNAL. Aquí hay un script de ejemplo que se solicita provocando un retraso de 10 segundos para que pueda probar los tiempos de espera:

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

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

Simon East
fuente
Hola, este código funciona, pero el archivo de origen es de 7 MB y esto me descarga solo 52 KB, ¿qué podría estar mal? URL es algo así como webserver.tld / folder / download / ...
Muflix
@ Simon East, ¿pueden ayudarme? Stackoverflow.com/questions/30861112/…
Nathan Srivi
Cabe señalar que espera un error de tiempo de espera con este script
kmoney12
30

Su código establece el tiempo de espera en 1000 segundos . Por milisegundos, use CURLOPT_TIMEOUT_MS.

Matt Humphreys
fuente
13

Deberá asegurarse de los tiempos de espera entre usted y el archivo. En este caso PHP y Curl.

Para indicarle a Curl que nunca agote el tiempo de espera cuando una transferencia aún está activa, debe configurarlo CURLOPT_TIMEOUTen 0lugar de 1000.

curl_setopt($ch, CURLOPT_TIMEOUT, 0);

En PHP, nuevamente, debe eliminar los límites de tiempo o PHP por sí mismo (después de 30 segundos por defecto) matará el script junto con la solicitud de Curl. Esto solo debería solucionar su problema .
Además, si necesita integridad de datos, puede agregar una capa de seguridad mediante el uso de 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 desconexión del cliente interrumpirá la ejecución del script y posiblemente dañará los datos,
por ejemplo. consulta de base de datos no de transición, compilando un archivo de configuración, etc., mientras que en su caso descargaría un archivo parcial ... y puede que le importe o no.

Respondiendo esta vieja pregunta porque este hilo está en la parte superior de las búsquedas de motores CURL_TIMEOUT.

MarcoP
fuente
8

No puede ejecutar la solicitud desde un navegador, se agota el tiempo de espera para que el servidor que ejecuta la solicitud CURL responda. El navegador probablemente esté agotando el tiempo en 1-2 minutos, el tiempo de espera predeterminado de la red.

Debe ejecutarlo desde la línea de comandos / terminal.

Brent Baisley
fuente
2
+1: el tiempo de espera es probablemente externo al rizo. En realidad, puede evitar el tiempo de espera del navegador asegurándose de generar algo periódicamente; los navegadores generalmente restablecen su tiempo de espera cada vez que reciben más datos. Pero eso es un truco; ejecutar a través de CLI es (¿casi?) siempre preferible.
Frank Farmer, el
3

Si está utilizando PHP como una aplicación fastCGI, asegúrese de verificar la configuración de tiempo de espera de fastCGI. Ver: PHP curl puso error 500

wbinky
fuente