251 votes

Définition du délai d'attente de Curl en PHP

Je lance une requête curl sur une base de données eXist à travers php. L'ensemble de données est très volumineux, et en conséquence, la base de données prend systématiquement beaucoup de temps pour renvoyer une réponse XML. Pour résoudre ce problème, nous avons configuré une requête curl, avec ce qui est censé être un long délai d'attente.

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

Cependant, la requête curl se termine systématiquement avant que la requête ne soit terminée (<1000 lorsqu'elle est demandée via un navigateur). Est-ce que quelqu'un sait si c'est la bonne façon de définir les délais d'attente dans curl ?

381voto

msangel Points 1716

Voir la documentation : http://www.php.net/manual/en/function.curl-setopt.php

CURLOPT_CONNECTTIMEOUT - Le nombre de secondes à attendre lors de la tentative de connexion. Utilisez 0 pour attendre indéfiniment.
CURLOPT_TIMEOUT - Le nombre maximum de secondes à autoriser pour l'exécution des fonctions cURL.

curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0); 
curl_setopt($ch, CURLOPT_TIMEOUT, 400); //timeout en secondes

n'oubliez pas non plus d'augmenter le temps d'exécution du script PHP lui-même :

set_time_limit(0);// à l'infini par exemple

16 votes

Vous n'avez pas besoin de set_time_limit(0); si le script s'exécute sur la console.

6 votes

@PedroLobito ce que tu mentionnes est la configuration par défaut du php en mode cli, mais il est possible que cela ait été modifié.

4 votes

@cherouvim a clairement raison ici (il suffit d'exécuter php -d max_execution_time=1 -r 'while(true){$r=1*1;}' ou quelque chose du genre pour observer en action que le cli n'a pas une "magie 'toujours illimitée'".

58voto

Chad Birch Points 39087

Hmm, il me semble que CURLOPT_TIMEOUT définit le temps maximum que n'importe quelle fonction cURL est autorisée à prendre pour s'exécuter. Je pense que vous devriez en fait regarder plutôt CURLOPT_CONNECTTIMEOUT car cela indique à cURL le temps maximal à attendre pour que la connexion se termine.

0 votes

Tandis que les docs en PHP disent que CURLOPT_TIMEOUT concerne la durée de la fonction, les docs sous-jacentes de la bibliothèque curl semblent dire qu'il s'agit de la durée de la requête, ce qui est une distinction intéressante - je ne suis pas sûr de comment interpréter cela !

0 votes

Je pense que voici la meilleure interprétation : stackoverflow.com/questions/27776129/…

41voto

Simon Points 4467

Il y a une bizarrerie avec cela qui pourrait être pertinent pour certaines personnes... Des commentaires de la documentation de PHP.

Si vous voulez que cURL expire en moins d'une seconde, vous pouvez utiliser CURLOPT_TIMEOUT_MS, bien qu'il y ait un bug/"fonctionnalité" sur les "systèmes de type Unix" qui provoque libcurl a expiré immédiatement si la valeur est < 1000 ms avec l'erreur "Erreur cURL (28): Le délai imparti a été atteint". L'explication de ce comportement est :

"Si libcurl est construit pour utiliser le résolveur de noms de système standard, cette partie du transfert utilisera toujours une résolution de la durée d'une seconde entière pour les délais d'expiration avec un délai d'expiration minimal d'une seconde."

Ce que cela signifie pour les développeurs PHP est "Vous ne pouvez pas utiliser cette fonction sans la tester au préalable, car vous ne pouvez pas dire si libcurl utilise le résolveur de noms du système standard (mais vous pouvez être assez sûr que c'est le cas)".

Le problème est que sur (Li|U)nix, lorsque libcurl utilise le résolveur de noms standard, un SIGALRM est généré pendant la résolution du nom que libcurl pense être l'alarme de délai d'expiration.

La solution consiste à désactiver les signaux en utilisant CURLOPT_NOSIGNAL. Voici un exemple de script qui demande lui-même un retard de 10 secondes afin que vous puissiez tester les délais d'expiration :

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 "Erreur cURL ($curl_errno): $curl_error\n";
    } else {
        echo "Données reçues: $data\n";
    }
} else {
    // Serveur
    sleep(10);
    echo "Terminé.";
}

À partir de http://www.php.net/manual/en/function.curl-setopt.php#104597

0 votes

Bonjour, ce code fonctionne mais le fichier source est de 7 Mo et cela ne me télécharge que 52 Ko, qu'est-ce qui pourrait ne pas aller ? L'URL ressemble à webserver.tld/folder/download/…

0 votes

@Simon East peux-tu s'il te plaît m'aider stackoverflow.com/questions/30861112/…

0 votes

Il convient de noter que vous attendez une erreur de délai avec ce script

31voto

Matt Humphreys Points 89

Votre code définit le délai d'attente à 1000 secondes. Pour les millisecondes, utilisez CURLOPT_TIMEOUT_MS.

8voto

Brent Baisley Points 10223

Vous ne pouvez pas exécuter la requête à partir d'un navigateur, elle expirera en attendant que le serveur exécutant la requête CURL réponde. Le navigateur atteint probablement la limite de temps en 1-2 minutes, le délai d'attente par défaut du réseau.

Vous devez l'exécuter à partir de la ligne de commande/terminal.

2 votes

+1 - le délai est probablement externe à curl. Vous pouvez effectivement contourner le délai du navigateur en vous assurant de produire périodiquement une sortie ; les navigateurs réinitialisent généralement leur délai à chaque fois qu'ils reçoivent plus de données. Mais c'est un hack ; exécuter via CLI est (presque ?) toujours préférable.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X