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?

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

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.


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


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.


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.


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.


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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.