Utiliser une API avec cURL

Résumé Support Quiz

Dans ce chapitre, nous allons voir comment interagir avec un service tiers en PHP. L'objectif est de comprendre le principe d'une API HTTP, puis d'utiliser cURL pour appeler une URL, récupérer une réponse et l'exploiter dans notre application.

Une API permet à un système de communiquer avec un autre. Dans le cas d'une API HTTP, on appelle une URL et le serveur renvoie des données, souvent au format JSON. Le rôle de PHP sera alors de faire la requête, de vérifier que tout s'est bien passé, puis de décoder le résultat.

Comprendre le principe d'une API

Une API est une interface de communication. Elle peut prendre plusieurs formes, mais dans beaucoup de cas on travaille avec des requêtes HTTP. On envoie une requête vers une URL, avec parfois des paramètres, et on récupère une réponse contenant les informations demandées.

La documentation de l'API est essentielle, car elle indique :

  • les URL disponibles.
  • les paramètres à envoyer.
  • le format de la réponse.
  • les clés d'API éventuelles.
  • les limites ou conditions d'utilisation.

Dans le cas d'une API qui renvoie du JSON, le résultat brut n'est pas directement pratique à utiliser. On le récupère d'abord sous forme de chaîne, puis on le convertit en tableau associatif avec json_decode().

Pourquoi utiliser cURL ?

Pour appeler une URL en PHP, on pourrait utiliser file_get_contents(), car cette fonction accepte aussi des URL si l'option allow_url_fopen est activée. Mais cette option est souvent désactivée chez certains hébergeurs, et cette approche donne peu de contrôle sur la requête.

cURL est une meilleure solution pour ce type de besoin. Cette extension est prévue pour effectuer des requêtes HTTP et permet de configurer plus finement l'appel : options SSL, timeout, récupération du contenu, lecture du code HTTP, etc.

Avant de l'utiliser, il faut vérifier que l'extension est activée dans PHP. On peut afficher les informations de l'installation avec phpinfo().

<?php phpinfo();

Si cURL n'apparaît pas dans la page d'information, il faudra activer l'extension dans le fichier php.ini.

Activer l'extension cURL

Le fichier de configuration de PHP s'appelle php.ini. Dans une installation locale, on peut parfois partir d'un fichier d'exemple comme php.ini-development, le copier et le renommer en php.ini.

Dans ce fichier, deux points sont importants :

  • vérifier le dossier des extensions avec extension_dir.
  • décommenter l'extension curl.
extension_dir = "ext" extension=curl

Après modification, il faut redémarrer le serveur PHP pour que la configuration soit prise en compte. En rechargeant la page phpinfo(), une section dédiée à cURL doit maintenant apparaître.

Faire une première requête cURL

Une requête cURL suit toujours la même logique : on initialise une session, on configure les options, on exécute la requête, puis on ferme la session.

<?php $curl = curl_init('https://example.com/api'); $data = curl_exec($curl); if ($data === false) { var_dump(curl_error($curl)); } curl_close($curl);

Les fonctions principales sont :

  • curl_init() pour initialiser la session.
  • curl_exec() pour exécuter la requête.
  • curl_error() pour récupérer le message d'erreur en cas d'échec.
  • curl_close() pour fermer la session et libérer les ressources.

Par défaut, curl_exec() affiche directement le résultat si la requête fonctionne. Si on veut récupérer le contenu dans une variable pour le traiter, il faut activer une option.

Récupérer le contenu au lieu de l'afficher

L'option CURLOPT_RETURNTRANSFER permet de demander à cURL de retourner le résultat au lieu de l'afficher directement.

<?php $curl = curl_init('https://example.com/api'); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); $data = curl_exec($curl); if ($data === false) { var_dump(curl_error($curl)); } curl_close($curl);

À partir de là, $data contient le résultat renvoyé par le serveur. On peut ensuite le décoder si le serveur renvoie du JSON.

$data = json_decode($data, true);

Le second paramètre à true permet d'obtenir un tableau associatif plutôt qu'un objet.

Gérer les certificats HTTPS

Lors d'une requête HTTPS, cURL doit vérifier le certificat du serveur. Si aucun certificat racine n'est disponible côté PHP, on peut obtenir une erreur du type :

SSL certificate problem: unable to get local issuer certificate

Une solution que l'on voit souvent consiste à désactiver la vérification SSL avec CURLOPT_SSL_VERIFYPEER à false.

curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);

Cette solution est déconseillée, car elle désactive la vérification HTTPS. Si quelqu'un se place entre votre serveur et l'API, les échanges peuvent être interceptés ou modifiés.

La solution plus propre consiste à fournir à cURL un certificat racine avec CURLOPT_CAINFO.

curl_setopt($curl, CURLOPT_CAINFO, __DIR__ . DIRECTORY_SEPARATOR . 'cert.cer');

Le certificat peut être exporté depuis le navigateur, en choisissant le certificat racine et un format lisible par PHP, comme Base64. Une fois le fichier disponible, cURL peut s'en servir pour vérifier que le serveur qui répond est bien le bon.

Définir plusieurs options

Quand on a plusieurs options à configurer, curl_setopt_array() permet de les regrouper dans un tableau. C'est souvent plus lisible que plusieurs appels successifs à curl_setopt().

<?php $curl = curl_init('https://example.com/api'); curl_setopt_array($curl, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_CAINFO => __DIR__ . DIRECTORY_SEPARATOR . 'cert.cer', CURLOPT_TIMEOUT => 1, ]); $data = curl_exec($curl); curl_close($curl);

L'option CURLOPT_TIMEOUT indique le nombre de secondes maximum à attendre. C'est important lorsqu'on dépend d'un service externe : si le serveur distant est trop lent, on évite de bloquer trop longtemps notre page. Il existe aussi une variante en millisecondes avec CURLOPT_TIMEOUT_MS.

Vérifier le code HTTP

Une requête peut réussir techniquement, même si le serveur répond avec une erreur HTTP. Par exemple, une page peut répondre en 404, mais curl_exec() ne renverra pas forcément false, car le serveur a bien répondu.

Pour vérifier le statut HTTP, on utilise curl_getinfo() avec CURLINFO_HTTP_CODE.

$status = curl_getinfo($curl, CURLINFO_HTTP_CODE); if ($status !== 200) { // Gérer l'erreur. }

On peut donc combiner deux vérifications :

  • est-ce que curl_exec() renvoie false ?
  • est-ce que le code HTTP est bien celui attendu ?
$data = curl_exec($curl); if ($data === false) { var_dump(curl_error($curl)); } elseif (curl_getinfo($curl, CURLINFO_HTTP_CODE) !== 200) { var_dump('Réponse HTTP invalide'); }

Cette étape évite d'essayer de décoder ou d'utiliser une réponse qui ne correspond pas au format attendu.

Exploiter une réponse JSON

Une fois la requête réussie, on peut décoder le JSON et récupérer uniquement les informations utiles. Il est conseillé d'afficher temporairement la structure du tableau ou d'utiliser un navigateur qui formate le JSON pour mieux comprendre les clés disponibles.

$data = json_decode($data, true); var_dump($data);

On peut ensuite accéder aux informations avec les clés du tableau.

$temperature = $data['main']['temp']; $description = $data['weather'][0]['description'];

La structure exacte dépend toujours de l'API utilisée. C'est pour cela qu'il faut lire la documentation et regarder un exemple de réponse.

Créer une classe pour isoler les appels

Une fois que la logique fonctionne, il est préférable de ne pas laisser tout le code cURL au milieu de la page. On peut créer une classe dédiée qui regroupe les appels à l'API et expose des méthodes plus simples à utiliser.

<?php class OpenWeather { private $apiKey; public function __construct(string $apiKey) { $this->apiKey = $apiKey; } public function getToday(string $city): ?array { $data = $this->callAPI('weather?q=' . $city); if ($data === null) { return null; } return [ 'temp' => $data['main']['temp'], 'description' => $data['weather'][0]['description'], 'date' => new DateTime(), ]; } public function getForecast(string $city): ?array { $data = $this->callAPI('forecast/daily?q=' . $city); if ($data === null) { return null; } $results = []; foreach ($data['list'] as $day) { $results[] = [ 'temp' => $day['temp']['day'], 'description' => $day['weather'][0]['description'], 'date' => new DateTime('@' . $day['dt']), ]; } return $results; } private function callAPI(string $endpoint): ?array { $curl = curl_init('https://api.openweathermap.org/data/2.5/' . $endpoint . '&appid=' . $this->apiKey . '&units=metric&lang=fr'); curl_setopt_array($curl, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_CAINFO => __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'cert.cer', CURLOPT_TIMEOUT => 1, ]); $data = curl_exec($curl); if ($data === false || curl_getinfo($curl, CURLINFO_HTTP_CODE) !== 200) { curl_close($curl); return null; } curl_close($curl); return json_decode($data, true); } }

L'intérêt est de séparer la logique technique de l'appel HTTP du reste de l'application. Les méthodes publiques décrivent ce que l'on veut récupérer, tandis que la méthode privée centralise la mécanique cURL commune.

On peut ensuite utiliser la classe de manière plus simple :

$weather = new OpenWeather('api-key'); $today = $weather->getToday('Montpellier,fr'); $forecast = $weather->getForecast('Montpellier,fr');

Cette organisation évite la répétition. Si l'URL de base, les options cURL ou la gestion des erreurs doivent changer, on le fait dans une seule méthode.

À retenir

cURL permet d'appeler une URL depuis PHP avec plus de contrôle que file_get_contents(). Pour une requête propre, on initialise la session, on définit les options utiles, on exécute la requête, on vérifie les erreurs et le code HTTP, puis on ferme la session.

Lorsqu'une API renvoie du JSON, on utilise json_decode() pour transformer la réponse en tableau exploitable. Et dès que plusieurs appels partagent la même logique, il devient intéressant de créer une classe pour centraliser le code et éviter la répétition.

Ressources

Pour aller plus loin, vous pouvez consulter la documentation officielle PHP sur cURL, json_decode et la documentation de l'API OpenWeather.