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

230

J'exécute une requête curl sur une base de données eXist via php. L'ensemble de données est très volumineux et, par conséquent, la base de données prend constamment beaucoup de temps pour renvoyer une réponse XML. Pour résoudre ce problème, nous avons mis en place une demande curl, avec ce qui est censé être un long délai.

$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 demande curl se termine systématiquement avant la fin de la demande (<1000 lorsqu'elle est demandée via un navigateur). Quelqu'un sait-il si c'est la bonne façon de définir des délais d'attente en boucle?

Moki
la source

Réponses:

346

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 pour permettre aux fonctions cURL de s'exécuter.

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

n'oubliez pas non plus d'agrandir l'exécution du script php:

set_time_limit(0);// to infinity for example
msangel
la source
13
Vous n'avez pas besoin set_time_limit(0);si le script s'exécute sur la console.
CONvid19
6
@PedroLobito ce que vous mentionnez est la configuration par défaut du php sur cli, mais il est possible qu'elle ait été modifiée.
cherouvim
4
@cherouvim est évidemment correct ici (il suffit de courir php -d max_execution_time=1 -r 'while(true){$r=1*1;}'ou d'observer en action que le cli n'a pas de drapeau magique "toujours illimité".
Wrikken
@Pedro Lobito dont vous n'avez pas besoin set_time_limit(0)si vous ne l'utilisez pas dans une boucle.
Viktor Joras
58

Hmm, il me semble que CURLOPT_TIMEOUTdéfinit le temps que toute fonction cURL est autorisée à exécuter. Je pense que vous devriez plutôt regarder à la CURLOPT_CONNECTTIMEOUTplace, car cela indique à cURL le temps maximal d'attente pour la connexion.

Chad Birch
la source
Alors que les documents en PHP disent CURLOPT_TIMEOUTsur le temps que prend la fonction, les documents de la bibliothèque curl sous - jacente semblent dire que c'est sur le temps que prend la demande, ce qui est une distinction intéressante - je ne sais pas dans quel sens lire cela!
fideloper
Je pense que voici la meilleure interprétation: stackoverflow.com/questions/27776129/…
fideloper
33

Il y a une bizarrerie avec cela qui pourrait être pertinente pour certaines personnes ... D'après les commentaires des documents PHP.

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

"Si libcurl est conçu pour utiliser le résolveur de nom de système standard, cette partie du transfert utilisera toujours une résolution d'une seconde complète pour les délais d'expiration avec un délai minimal autorisé d'une seconde."

Ce que cela signifie pour les développeurs PHP est "Vous ne pouvez pas utiliser cette fonction sans la tester d'abord, car vous ne pouvez pas dire si libcurl utilise le résolveur de nom de système standard (mais vous pouvez en être sûr)"

Le problème est que sur (Li | U) nix, lorsque libcurl utilise le résolveur de nom standard, un SIGALRM est levé pendant la résolution de nom qui, selon libcurl, est l'alarme de timeout.

La solution consiste à désactiver les signaux à l'aide de CURLOPT_NOSIGNAL. Voici un exemple de script qui se demande lui-même entraînant un délai de 10 secondes afin que vous puissiez tester les délais d'attente:

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

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

Simon East
la source
Bonjour, ce code fonctionne mais le fichier source est de 7 Mo et celui-ci ne me télécharge que 52 Ko, quel est le problème? URL est quelque chose comme webserver.tld / dossier / téléchargement /…
Muflix
@Simon East pouvez-vous m'aider s'il vous plaît stackoverflow.com/questions/30861112/…
Nathan Srivi
Il convient de noter que vous vous attendez à une erreur de temporisation avec ce script
kmoney12
30

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

Matt Humphreys
la source
13

Vous devrez vous assurer des délais d'attente entre vous et le fichier. Dans ce cas, PHP et Curl.

Pour indiquer à Curl de ne jamais expirer lorsqu'un transfert est toujours actif, vous devez définir CURLOPT_TIMEOUTsur 0, au lieu de 1000.

curl_setopt($ch, CURLOPT_TIMEOUT, 0);

En PHP, encore une fois, vous devez supprimer les limites de temps ou PHP lui-même (après 30 secondes par défaut) tuera le script le long de la demande de Curl. Cela seul devrait résoudre votre problème .
De plus, si vous avez besoin de l'intégrité des données, vous pouvez ajouter une couche de sécurité en utilisant 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);

Une déconnexion du client va interrompre l'exécution du script et éventuellement endommager les données,
par exemple. requête de base de données non transitionnelle, création d'un fichier de configuration, etc., alors que dans votre cas, il téléchargerait un fichier partiel ... et vous pourriez, ou non, vous en soucier.

Répondre à cette ancienne question, car ce fil est en haut des recherches de moteurs CURL_TIMEOUT.

MarcoP
la source
8

Vous ne pouvez pas exécuter la demande à partir d'un navigateur, il attendra que le serveur exécutant la demande CURL réponde. Le navigateur expire probablement dans 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 / du terminal.

Brent Baisley
la source
2
+1 - le délai est probablement externe à curl. Vous pouvez réellement contourner le délai d'expiration du navigateur en vous assurant de produire quelque chose périodiquement; les navigateurs réinitialisent généralement leur délai d'expiration à chaque fois qu'ils reçoivent plus de données. Mais c'est un hack; courir via CLI est (presque?) toujours préférable.
Frank Farmer
3

Si vous utilisez PHP comme application fastCGI, assurez-vous de vérifier les paramètres de délai d'attente fastCGI. Voir: PHP curl put 500 error

wbinky
la source