Partage
  • Partager sur Facebook
  • Partager sur Twitter

Requête cURL et boucle infinie (PHP)

Sujet résolu
    2 mai 2021 à 17:13:47

    Bonjour, 

    J'utilise pour la première fois cURL pour mes requêtes API. Mon objectif est de récupérer les matchs de football des 5 grands championnats à une date définie.

    Pour ce faire, j'ai mis ma requête dans une boucle for qui est censée boucler 5 fois, pour faire une requête par championnat. J'ai ajouté une ligne pour afficher la variable d'itération (afin de vérifier où on en est dans la boucle), et une commande de contrôle pour "break" la boucle si elle se renouvelle à l'infinie (je ne dirais pas que c'est un échec, mais ça n'a pas fonctionné). La deuxième boucle 'for' permet d'afficher tous les matchs du championnat.

    $curl = curl_init();
    
    $date_request='2021-05-07'; //la date de la requête
    $tab_id_league=array(61, 39, 140, 135, 78); //le tableau des ligues
    
    for ($i=0; $i < count($tab_id_league); $i++) //boucle de requête de match
    { 
    	echo '</br>'.$i.' - ';
    
    	if ($i>8) {
    		break; 
    		echo 'emmergency stop';
    	}
    
    	curl_setopt_array($curl, [
    		CURLOPT_URL => "https://api-football-v1.p.rapidapi.com/v3/fixtures?date=".$date_request."&league=".$tab_id_league[$i]."&season=2020",
    		CURLOPT_RETURNTRANSFER => true,
    		CURLOPT_FOLLOWLOCATION => true,
    		CURLOPT_ENCODING => "",
    		CURLOPT_MAXREDIRS => 10,
    		CURLOPT_TIMEOUT => 30,
    		CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    		CURLOPT_CUSTOMREQUEST => "GET",
    		CURLOPT_HTTPHEADER => [..........], //mes identifiants pour accéder à l'API
    	]);
    
    	$response = curl_exec($curl); //LIGNE 40
    $err = curl_error($curl); if ($err) { echo "cURL Error #:" . $err; } else //s'il n'y a pas d'erreur { $tab_json = json_decode($response, true); //on transforme $response en un tableau php. LIGNE 50 $nbr_results=$tab_json['results']; //on récupère le nombre de résultat pour faire la boucle for de lecture des matchs. for ($i=0; $i < $nbr_results; $i++) //affiche tous les matchs du championnat { $id_match_api=$tab_json['response'][$i]['fixture']['id']; $timestamp_api=$tab_json['response'][$i]['fixture']['timestamp']; $date_match=date('Y-m-d',$timestamp_api); $heure_match=date('H:i',$timestamp_api); $ligue=$tab_json['response'][$i]['league']['name']; $locaux=$tab_json['response'][$i]['teams']['home']['name']; $visiteurs=$tab_json['response'][$i]['teams']['away']['name']; echo $ligue.': '.$date_match.' '.$heure_match.' '.$id_match_api.' : '.$locaux.' - '.$visiteurs.'<br/>'; //clean des variables unset($timestamp_api); unset($date_match); unset($heure_match); unset($id_match_api); unset($ligue); unset($locaux); unset($visiteurs); } unset($response); } } curl_close($curl);


    Je précise que j'ai aussi essayé de mettre le 'curl_init' et le 'curl_close' à l'intérieur de la boucle mais j'ai eu le même résultat. Le voici :

    1 fois la ligne "0 - Ligue 1: 2021-05-07 19:00 571824 : Lens - Lille"

    29 fois la ligne "2 - Primera Division: 2021-05-07 19:00 605412 : Real Sociedad - Elche"

    654 fois les lignes "Notice: Undefined index: results in C:\MAMP\htdocs\test_api.php on line 50" (n° de ligne indiqué sur le code)

    Et enfin la ligne : "Fatal error: Maximum execution time of 30 seconds exceeded in C:\MAMP\htdocs\test_api.php on line 40" (n° de ligne indiqué sur le code)

    Donc on commence avec une première boucle qui fonctionne parfaitement. Mais après ça se complique : déjà la boucle 3 arrive avant la 2e (??), la requête fonctionne, le match est affiché, mais la boucle (et la requête) se répète 29 fois (??). La deuxième boucle se répète 654 fois (heureusement la requête, elle, ne se répète pas), et fini par faire mourir le code à cause de la commande 'curl_exec'.

    Mes questions :

    • C'est la première fois que j'ai à faire à ce genre de boucle qui se répète sans que l'itération ne se fasse. Dans quels cas ça peut arriver ? Comment faire pour éviter que ça arrive ?
    • Qu'est ce qu'il se passe avec cette troisième boucle qui apparait avant la deuxième ?
    • Il semble que la deuxième requête ne fonctionne pas (et ça causerait le problème de curl_exec, puis de la ligne 50), avez-vous une idée de ce qui causerait ça ? 
    En vous remerciant pour votre attention, n'hésitez pas à me faire savoir si la forme de mon premier post n'est pas en conformité avec la charte. 


    • Partager sur Facebook
    • Partager sur Twitter
      2 mai 2021 à 21:08:23

      Hello,

      Alors on va y aller par étape pour voir ce qui ne va pas.

      Dans un premier temps pourrais tu corriger les points suivants:

      - Ton IF ligne 8 tu ne l'auras jamais car ton tableau ne contient 5 entrées. Mais tu peux l'enlever car ça n'a pas d'intérêt ici (pas vraiment de risque de boucle infini ici, sauf si tu as fait une erreur ;))

      - Ligne 35 tu fais une "json_decode" mais comme tu reçois des données de l'extérieur, tu devrais tester qu'il n'y a pas eu d'erreur de décodage avec "json_last_error":

      $tab_json = json_decode($response, true);
      if (JSON_ERROR_NONE !== json_last_error()) {
          throw new Exception('Invalid response: '.$response);
      }

      - Tu dois tester aussi que tu as bien la clé "results" dans ton table après ton décode:

      if (!array_key_exists('results', $tab_json)) {
          throw new Exception('Result is not set in server response');
      }

      - Ligne 39 (ta grosse boulette), tu as réutiliser $i comme variable, ce qui fait qu'a chaque boucle, tu changes aussi la valeur de ton $i de ta toute première boucle! Fait moi le plaisir de remplacer par:

      for ($j = 0; $j < $nbr_results; $j++)

      Et bien sur tout le code à l'intérieur de cette boucle FOR pour remplacer $i par $j là où il faut.

      • Partager sur Facebook
      • Partager sur Twitter
      $2b||!$2b
        3 mai 2021 à 0:33:18

        Aie, l'erreur de débutant. Je me suis tellement concentré sur la partie cURL que j'ai manqué l'essentiel.

        Merci pour ta réponse, et déso d'avoir usé de ton temps pour ce genre d'erreur.

        Me conseillerais-tu de mettre mes lignes "$tab_json = json_decode($response, true);" et "$nbr_results=$tab_json['results'];" dans les ELSE des tests que tu m'as proposé ?

        • Partager sur Facebook
        • Partager sur Twitter
          3 mai 2021 à 10:23:16

          Alors tout dépend de comment tu gères ton code. Mais le throw Exception arrête ton script donc pas besoin de faire de else. Par contre si tu veux faire un truc avant ou ne pas émettre de throw, dans ce cas il faut faire en sorte que le reste du script s'exécute seulement si tout va bien. Donc soit dans le else, soit autrement.

          Je suis plus partisan de laisser les gens faire leurs erreurs et d'en tirer les améliorations possible :)

          • Partager sur Facebook
          • Partager sur Twitter
          $2b||!$2b
            7 mai 2021 à 11:50:23

            Hello ! 


            Je me permet de relancer. Mon programme fonctionne ! Mais quand j'entre dans les "if" que @skuti m'a proposé, j'ai le message d'erreur suivant : 

            "Parse error: syntax error, unexpected 'new' (T_NEW)"

            Est-ce qu'il faut définir la classe Exception ? Est-ce autre chose ? 


            Est-il possible de faire une entrée dans une bdd pour sauvegarder le message d'erreur (pour pouvoir les consulter plus tard si je lance le programme via un Crontab) ?


            Encore merci :)

            • Partager sur Facebook
            • Partager sur Twitter
              8 mai 2021 à 19:46:17

              Hello peux tu nous montre ton code actuelle stp ?

              Normalement, la classe Exception fait partie de PHP natif. https://www.php.net/manual/fr/class.exception.php

              Ensuite pour tes messages d'erreur, normalement tu as les logs de ton serveur qui sont là exprès pour ça.

              Je te laisse te renseigné la dessus car tout dépend de comment est fait chaque serveur du coup trop long à essayé de tout t'expliquer.

              • Partager sur Facebook
              • Partager sur Twitter
              $2b||!$2b
                10 mai 2021 à 20:30:36

                Hello, désolé j'ai manqué ta réponse. Voici mon code : 

                $curl = curl_init();
                
                $timestamp=time()+522000; //aujourd'hui+6jours
                $date_request=date("Y-m-d", $timestamp);
                
                $tab_id_league=array(61, 39, 140, 135, 78); //(Ligue 1, PL, esp, série A, Bundesliga, LDC, EL)
                
                for ($i=0; $i < count($tab_id_league); $i++) //boucle de requête de match
                { 
                		curl_setopt_array($curl, [
                			CURLOPT_URL => "https://api-football-v1.p.rapidapi.com/v3/fixtures?date=".$date_request."&league=".$tab_id_league[$i]."&season=2020",
                CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 30, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => "GET", CURLOPT_HTTPHEADER => [...], ]); $response = curl_exec($curl); $err = curl_error($curl); if ($err) { echo "cURL Error #:" . $err; } else
                { $tab_json = json_decode($response, true); //on transforme $response en un tableau php. if (json_last_error() != 'JSON_ERROR_NONE'){     throw new Exception('Invalid response: '.$response); } if (!array_key_exists('results', $tab_json)) { throw new Exception('Result is not set in server response'); } else { $nbr_results=$tab_json['results']; } for ($j=0; $j < $nbr_results; $j++) { $timestamp_api=$tab_json['response'][$j]['fixture']['timestamp']; $date_match=date('Y-m-d',$timestamp_api); $heure_match=date('H:i',$timestamp_api); $pays_match=$tab_json['response'][$j]['league']['country']; $locaux=$tab_json['response'][$j]['teams']['home']['name']; $visiteurs=$tab_json['response'][$j]['teams']['away']['name']; echo $pays_match.': '.$date_match.' '.$heure_match.' '.$id_match_api.' : '.$locaux.' - '.$visiteurs.'<br/>'; $req_insert = $bdd->prepare('INSERT INTO matchs (id_api,date_match,heure_match,pays,locaux,visiteurs) VALUES (?,?,?,?,?,?)'); $req_insert->execute(array($id_match_api,$date_match,$heure_match,$pays_match,$locaux,$visiteurs)); } } } curl_close($curl);

                Depuis mon message j'ai fait quelques tests, en réalité c'est la ligne "if (json_last_error() != 'JSON_ERROR_NONE')" qui pose problème, et donc pas la classe Exception. En effet lorsque que je met "echo 'Salut!';" j'obtiens le même message d'erreur "Parse error: syntax error, unexpected 'echo' ". 

                D'après ce que j'ai compris, la fonction json_last_error() renvoie le statut lié à la ligne du dessus, et si ce statut n'est pas "pas d'erreur" (ie. s'il y a une erreur), alors on stop le processus. Dans les exemples ils utilisent un switch() mais je ne vois pas la différence. 


                Encore merci pour ton aide. Je croise les doigts pour que ce ne soit pas une erreur du niveau de la précédente. 

                -
                Edité par Kassenboule 10 mai 2021 à 20:31:23

                • Partager sur Facebook
                • Partager sur Twitter
                  10 mai 2021 à 21:45:08

                  Hello, pourquoi tu n'as pas copié/collé le bout de code que je t'ai donné. Là tu as converti mon code en quelque chose qui n'a rien a voir !

                  if (json_last_error() != 'JSON_ERROR_NONE'){}

                  "json_last_error()" te renvoi un INT qui correspond au code erreur (comme 404 qui veut dire page not found), tu utilises (très mauvaise habitude d'ailleurs) le != au lien de !== qui te permet de vérifier aussi le type (ici on veut du INT) et ensuite tu as convertis la constante PHP "JSON_ERROR_NONE" et string en ajoutant les guillemets autour du coup au lieu que la constante PHP te retourne 0, tu as une string qui contient "JSON_ERROR_NONE".

                  Le bon code est:

                  if (JSON_ERROR_NONE !== json_last_error()) {
                      throw new Exception('Invalid response: '.$response);
                  }



                  • Partager sur Facebook
                  • Partager sur Twitter
                  $2b||!$2b
                    10 mai 2021 à 23:55:44

                    Il me semble que justement j'avais copié/collé, et j'avais déjà eu le même problème. J'avais donc repris le code dans une forme qui me semblait plus cohérente à ce que j'avais lu sur le manuel php, avec les guillemets comme petite touche perso. 

                    Je n'avais pas cerné la distinction entre "!=" et "!==". Idem pour la constante. 

                    Je réessaye avec le code exact demain, et je reviens voir toi. Encore merci pour l'expertise :)

                    • Partager sur Facebook
                    • Partager sur Twitter
                      11 mai 2021 à 7:54:36

                      C'est des erreurs de débutant donc c'est normal xD

                      Après s'il y a une erreur, remet moi ton nouveau code et on cherchera la problème :)

                      • Partager sur Facebook
                      • Partager sur Twitter
                      $2b||!$2b
                        11 mai 2021 à 16:24:27

                        J'ai édité et testé le programme : l'erreur n'apparait plus. Aurais-je fait une erreur de copier/coller la première fois ? Peut-être :-|

                        Encore merci :)

                        • Partager sur Facebook
                        • Partager sur Twitter

                        Requête cURL et boucle infinie (PHP)

                        × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                        × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                        • Editeur
                        • Markdown