PHP et les API externes

Apprenez à connecter votre application PHP à des services externes : API REST, cURL, OAuth, Webhooks, gestion des erreurs, etc.

Avant de commencer : Qu'est-ce qu'une API ?

Une API (Application Programming Interface) est une interface qui permet à deux applications de communiquer entre elles. Les API REST sont les plus courantes sur le web : elles utilisent le protocole HTTP et échangent des données (souvent en JSON).

Schéma d'une requête API :
Votre code PHPhttps://api.exemple.com/...
Serveur distant → Réponse JSON

Pour chaque API, consultez toujours la documentation officielle : elle précise les endpoints, les paramètres, les méthodes HTTP à utiliser, les formats de réponse, etc.

1. Consommer une API REST en PHP

La plupart des API modernes utilisent le protocole HTTP et échangent des données au format JSON. Pour consommer une API, on utilise généralement file_get_contents ou cURL.

Exemple simple avec file_get_contents

// Appel d'une API publique (ex : OpenWeatherMap)
$url = 'https://api.open-meteo.com/v1/forecast?latitude=48.85&longitude=2.35¤t_weather=true';
$json = file_get_contents($url);
$data = json_decode($json, true);
// Afficher la température actuelle
echo 'Température à Paris : ' . $data['current_weather']['temperature'] . '°C';
Astuce : file_get_contents fonctionne pour les API publiques sans authentification. Pour des API sécurisées ou des requêtes avancées, utilisez cURL.

2. Utiliser cURL en PHP

cURL est une bibliothèque très puissante pour faire des requêtes HTTP (GET, POST, PUT, DELETE) avec gestion des headers, authentification, etc.

Exemple : Requête GET avec cURL

// Initialiser cURL
$ch = curl_init('https://api.open-meteo.com/v1/forecast?latitude=48.85&longitude=2.35¤t_weather=true');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$json = curl_exec($ch);
curl_close($ch);
$data = json_decode($json, true);
echo 'Température à Paris : ' . $data['current_weather']['temperature'] . '°C';

Exemple : Requête POST avec cURL

// Exemple d'envoi de données en POST (ex : API fictive)
$ch = curl_init('https://jsonplaceholder.typicode.com/posts');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'title' => 'body' => 'userId' => 1
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
// Afficher la réponse JSON
echo $response;
À retenir : cURL permet de gérer les headers, l'authentification, les méthodes HTTP, les erreurs, etc. Consultez la doc officielle pour plus d'options.

3. Authentification et tokens OAuth

De nombreuses API nécessitent une authentification via un token (clé API, Bearer token, OAuth2...). Voici un exemple d'appel d'API avec un token Bearer :

// Appel d'une API avec un token Bearer
$token = 'VOTRE_TOKEN_ICI';
$ch = curl_init('https://api.exemple.com/data');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer ' . $token]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
OAuth2 : Pour des API comme Google, GitHub, Stripe, il faut suivre le flow OAuth2 (autorisation, récupération du token, etc.). Utilisez des librairies comme league/oauth2-client pour simplifier l'intégration.

4. Webhooks : recevoir des notifications d'une API

Un webhook est une URL de votre application appelée par un service externe lorsqu'un événement se produit (paiement, push GitHub, etc.).

Exemple de réception d'un webhook Stripe

// Fichier : webhook.php
$payload = file_get_contents('php://input');
$event = json_decode($payload, true);
// Vérifier le type d'événement
if ($event['type'] === 'payment_intent.succeeded') {
    // Traiter le paiement réussi
}
// Répondre à Stripe
http_response_code(200);
Bonnes pratiques :
  • Vérifiez la signature du webhook (voir doc Stripe, GitHub...)
  • Répondez rapidement (200 OK)
  • Logguez les événements reçus

5. Gérer les réponses et les erreurs d'API

Il est essentiel de vérifier le code de réponse HTTP et de gérer les erreurs lors de l'appel à une API.

Exemple : gestion des erreurs avec cURL

// Exemple de gestion d'erreur avec cURL
$ch = curl_init('https://api.exemple.com/data');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($response === false || $httpCode !== 200) {
    $error = curl_error($ch);
    echo "Erreur API : $error (code $httpCode)";
} else {
    echo $response;
}
curl_close($ch);
Attention : Toujours vérifier le code HTTP et le contenu de la réponse pour éviter les bugs et sécuriser votre application.

Exemple complet : Consommer une API météo et afficher le résultat

Voici un exemple complet qui récupère la météo d'une ville et affiche la température et la description du temps :

// Exemple avec l'API OpenWeatherMap (clé API requise)
$apiKey = 'VOTRE_CLE_API';
$city = $url = "https://api.openweathermap.org/data/2.5/weather?q=$city&appid=$apiKey&units=metric&lang=fr";
$json = file_get_contents($url);
$data = json_decode($json, true);
if ($data && isset($data['main'])) {
    $temp = $data['temp'];
    $desc = $data['weather'][0]['description'];
    echo "À $city, il fait $temp°C et le temps est : $desc";
} else {
    echo "Impossible de récupérer la météo.";
}
Conseil : Pour tester, inscrivez-vous sur OpenWeatherMap pour obtenir une clé API gratuite.

Décoder et manipuler une réponse JSON

La plupart des API REST renvoient des données au format JSON. En PHP, on utilise json_decode pour transformer la réponse en tableau ou objet.

// Exemple de réponse JSON
'{"name":"Paris","main":{"temp":22.5},"weather":[{"description":"ciel dégagé"}]}'

// Décodage en tableau associatif
$data = json_decode('{"name":"Paris","main":{"temp":22.5},"weather":[{"description":"ciel dégagé"}]}', true);
echo $data['main']['temp']; // 22.5
echo $data['weather'][0]['description']; // ciel dégagé
À savoir : json_decode($json, true) retourne un tableau associatif, json_decode($json) retourne un objet PHP.

Aller plus loin avec cURL : headers, timeout, erreurs

cURL permet de personnaliser vos requêtes HTTP : ajouter des headers, gérer le timeout, suivre les redirections, etc.

// Exemple avancé avec headers et timeout
$ch = curl_init('https://api.exemple.com/data');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Accept: application/json', 'Authorization: Bearer VOTRE_TOKEN']);
curl_setopt($ch, CURLOPT_TIMEOUT, 5); // 5 secondes max
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode === 200) {
    echo $response;
} else {
    echo "Erreur API : code $httpCode";
}
curl_close($ch);
Conseil : Utilisez toujours un timeout pour éviter que votre script ne reste bloqué si l'API ne répond pas.

Tester une API en local : outils pratiques

Pour tester vos appels API, vous pouvez utiliser des outils comme Postman ou HTTPie. Ils permettent de simuler des requêtes, voir les réponses, tester différents headers, etc.

Astuce : Utilisez php -S localhost:8000 pour lancer un serveur local et tester vos webhooks ou endpoints API.

Utiliser Postman pour tester une API

Postman est un outil graphique gratuit qui permet de tester facilement des requêtes API sans écrire de code. Il est très utilisé par les développeurs pour explorer, documenter et automatiser les tests d'API.

  1. Téléchargez et installez Postman depuis le site officiel.
  2. Créez une nouvelle requête :
    • Cliquez sur New > HTTP Request.
    • Choisissez la méthode (GET, POST, etc.) et saisissez l'URL de l'API (ex : https://jsonplaceholder.typicode.com/posts).
  3. Ajoutez des paramètres ou un corps de requête :
    • Pour une requête GET, ajoutez les paramètres dans l'onglet Params.
    • Pour une requête POST, allez dans l'onglet Body, sélectionnez raw et choisissez JSON puis saisissez votre payload.
  4. Ajoutez des headers si besoin (ex : Authorization, Content-Type: application/json).
  5. Cliquez sur Send pour envoyer la requête et visualiser la réponse (statut HTTP, en-têtes, corps JSON, etc.).
{
  "title": "Test Postman",
  "body": "Ceci est un test via Postman",
  "userId": 1
}
Bonnes pratiques :
  • Utilisez l'onglet History pour rejouer des requêtes.
  • Enregistrez vos requêtes dans des collections pour les retrouver facilement.
  • Exploitez l'onglet Tests pour automatiser la vérification des réponses.
  • Vous pouvez générer du code PHP (ou autre) à partir d'une requête Postman via Code > PHP cURL.
Astuce : Postman permet aussi de simuler des webhooks en lançant un serveur local ou en utilisant webhook.site pour recevoir des notifications d'API.

Exemple pratique : API de covoiturage

Imaginons que nous développons une application de covoiturage et que nous devons intégrer une API pour rechercher des trajets disponibles entre deux villes. Voici comment nous pourrions procéder :

1. Présentation du cas d'usage

Notre API fictive CarShare API permet de :

Fonctionnement général d'une API de covoiturage :
  1. L'utilisateur saisit des critères de recherche (départ, arrivée, date...)
  2. Notre application PHP envoie ces critères à l'API
  3. L'API renvoie une liste de trajets correspondants
  4. Notre application affiche les résultats et permet à l'utilisateur d'interagir avec eux

2. Exemple : Recherche de trajets disponibles

/**
 * Exemple d'intégration d'une API de covoiturage
 * 
 * Cet exemple montre comment :
 * 1. Construire une requête avec plusieurs paramètres
 * 2. Gérer la pagination des résultats
 * 3. Traiter et afficher les données reçues
 */

// Configuration de l'API (à stocker de manière sécurisée en production)
$apiKey = 'votre_cle_api_carshare';
$baseUrl = 'https://api.carshare-exemple.com/v1';

// Paramètres de la recherche (normalement fournis par un formulaire)
$villeDepart = 'Paris';
$villeArrivee = 'Lyon';
$date = '2025-06-25'; // Format YYYY-MM-DD
$nbPassagers = 2;
$prixMax = 30; // Prix maximum en euros
$page = 1;  // Pour la pagination des résultats

// Construction de l'URL avec les paramètres
$url = "$baseUrl/trips/search?" . http_build_query([
    'departure' => $villeDepart,
    'arrival' => $villeArrivee,
    'date' => $date,
    'passengers' => $nbPassagers,
    'max_price' => $prixMax,
    'page' => $page,
    'per_page' => 10
]);

// Initialisation de cURL
$ch = curl_init($url);

// Configuration des options cURL
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . $apiKey,
        'Accept: application/json',
        'User-Agent: MonAppCovoiturage/1.0'
    ],
    CURLOPT_TIMEOUT => 10  // Timeout de 10 secondes
]);

// Exécution de la requête
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

// Fermeture de la connexion cURL
curl_close($ch);

// Traitement de la réponse
if ($httpCode === 200) {
    $data = json_decode($response, true);
    
    // Affichage des résultats
    if (!empty($data['trips'])) {
        echo "<h3>Trajets disponibles de $villeDepart à $villeArrivee le $date</h3>";
        echo "<div class='trips-container'>";
        
        foreach ($data['trips'] as $trajet) {
            echo "<div class='trip-card'>";
            echo "<div class='trip-header'>";
            echo "<div class='trip-route'>{$trajet['departure_city']} → {$trajet['arrival_city']}</div>";
            echo "<div class='trip-price'>{$trajet['price']}€</div>";
            echo "</div>";
            echo "<div class='trip-details'>";
            echo "<div class='trip-time'>Départ: {$trajet['departure_time']} - Arrivée: {$trajet['arrival_time']}</div>";
            echo "<div class='trip-seats'>Places disponibles: {$trajet['available_seats']}</div>";
            echo "<div class='trip-driver'>Conducteur: {$trajet['driver']['name']} (Note: {$trajet['driver']['rating']}/5)</div>";
            echo "</div>";
            echo "<a href='reservation.php?trip_id={$trajet['id']}' class='btn-book'>Réserver</a>";
            echo "</div>";
        }
        
        echo "</div>";
        
        // Affichage de la pagination si nécessaire
        if ($data['total_pages'] > 1) {
            echo "<div class='pagination'>";
            for ($i = 1; $i <= $data[$i++) {
                $activeClass = ($i == $page) ? ' active' : '';
                echo "<a href='?departure=$villeDepart&arrival=$villeArrivee&date=$date&page=$i' class='page-link$activeClass'>$i</a>";
            }
            echo "</div>";
        }
    } else {
        echo "<div class='no-results'>Aucun trajet disponible pour ces critères. Essayez de modifier votre recherche.</div>";
    }
} elseif ($httpCode === 401) {
    echo "<div class='error'>Erreur d'authentification. Vérifiez votre clé API.</div>";
} elseif ($httpCode === 429) {
    echo "<div class='error'>Trop de requêtes. Veuillez réessayer dans quelques instants.</div>";
} else {
    $error = json_decode($response, true);
    $errorMessage = isset($error['message']) ? $error['message'] : "Erreur inconnue (Code: $httpCode)";
    echo "<div class='error'>Erreur API: $errorMessage</div>";
}

3. Structure de la réponse JSON

Voici un exemple de la structure de données que pourrait renvoyer notre API de covoiturage :

{
  "meta": {
    "total_results": 42,
    "total_pages": 5,
    "current_page": 1,
    "results_per_page": 10
  },
  "trips": [
    {
      "id": "trip_12345",
      "departure_city": "Paris",
      "departure_address": "Gare de Lyon",
      "departure_coordinates": {"lat": 48.8448, "lng": 2.3735},
      "departure_time": "2025-06-25T08:30:00+02:00",
      "arrival_city": "Lyon",
      "arrival_address": "Gare Part-Dieu",
      "arrival_coordinates": {"lat": 45.7597, "lng": 4.8592},
      "arrival_time": "2025-06-25T12:15:00+02:00",
      "price": 25.50,
      "distance": 465,
      "duration": 225,
      "available_seats": 3,
      "total_seats": 4,
      "driver": {
        "id": "user_6789",
        "name": "Thomas D.",
        "rating": 4.8,
        "trips_count": 142,
        "verified": true,
        "picture_url": "https://api.carshare-exemple.com/users/6789/picture"
      },
      "vehicle": {
        "make": "Renault",
        "model": "Zoé",
        "color": "Bleu",
        "eco_friendly": true
      },
      "amenities": ["climatisation", "prises USB", "animaux acceptés"]
    },
    // ... autres trajets ...
  ]
}

4. Récupérer les détails d'un trajet spécifique

Une fois qu'un utilisateur sélectionne un trajet, vous pouvez récupérer ses détails complets pour afficher plus d'informations :

// Récupération des détails d'un trajet spécifique
function getTripDetails($tripId, $apiKey, $baseUrl) {
    $url = "$baseUrl/trips/$tripId";
    
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => [
            'Authorization: Bearer ' . $apiKey,
            'Accept: application/json'
        ]
    ]);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($httpCode === 200) {
        return json_decode($response, true);
    } else {
        return null;
    }
}

// Utilisation
if (isset($_GET['trip_id'])) {
    $tripDetails = getTripDetails($_GET['trip_id'], $apiKey, $baseUrl);
    
    if ($tripDetails) {
        // Afficher les détails complets du trajet
        echo "<div class='trip-details-page'>";
        echo "<h2>Trajet de {$tripDetails['departure_city']} à {$tripDetails['arrival_city']}</h2>";
        // Afficher les autres informations du trajet
        echo "</div>";
    } else {
        echo "<div class='error'>Impossible de récupérer les détails du trajet.</div>";
    }
}

5. Effectuer une réservation

Pour réserver une place sur un trajet, on utilise généralement une requête POST avec les informations du passager :

// Fonction pour réserver un trajet
function bookTrip($tripId, $userData, $apiKey, $baseUrl) {
    $url = "$baseUrl/bookings";
    
    // Préparation des données pour la réservation
    $postData = [
        $tripId,
        'passengers' => $userData['passengers'],
        'passenger_name' => $userData['name'],
        'passenger_email' => $userData['email'],
        'passenger_phone' => $userData['phone'],
        'message_to_driver' => $userData['message'] ?? ''
    ];
    
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => json_encode($postData),
        CURLOPT_HTTPHEADER => [
            'Authorization: Bearer ' . $apiKey,
            'Content-Type: application/json',
            'Accept: application/json'
        ]
    ]);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    return [
        $httpCode === 201), // 201 Created pour une réservation réussie
        'data' => json_decode($response, true)
    ];
}

// Gestion du formulaire de réservation
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $tripId = $_POST['trip_id'];
    
    $userData = [
        $_POST['name'],
        'email' => $_POST['email'],
        'phone' => $_POST['phone'],
        'passengers' => (int) $_POST['passengers'],
        'message' => $_POST['message'] ?? ''
    ];
    
    $result = bookTrip($tripId, $userData, $apiKey, $baseUrl);
    
    if ($result['status']) {
        // Réservation réussie
        $bookingId = $result['data']['booking_id'];
        echo "<div class='success'>
                <h3>Réservation confirmée !</h3>
                <p>Votre numéro de réservation : $bookingId</p>
                <p>Un email de confirmation a été envoyé à {$userData['email']}.</p>
                <a href='my-bookings.php' class='btn'>Voir mes réservations</a>
            </div>";
    } else {
        // Erreur de réservation
        $errorMessage = $result['data']['message'] ?? "Impossible de finaliser votre réservation";
        echo "<div class='error'>$errorMessage</div>";
    }
}

6. Bonnes pratiques pour l'intégration d'une API de covoiturage

Recommandations :
  • Mise en cache : Pour réduire le nombre d'appels API et améliorer les performances, mettez en cache les résultats de recherche pour une courte durée (ex : 1-5 minutes).
  • Temps réel : Pour les réservations, assurez-vous toujours d'avoir les données à jour (ne pas utiliser le cache).
  • Gestion des erreurs : Prévoyez tous les cas d'erreur possibles : API indisponible, plus de places disponibles, etc.
  • Expérience utilisateur : Affichez un indicateur de chargement pendant les appels API et proposez des actions alternatives en cas d'échec.
  • Sécurité : Ne stockez jamais la clé API côté client et validez toujours les données envoyées par l'utilisateur.
Astuce : Pour simuler une API de covoiturage en phase de développement, vous pouvez créer un simple fichier JSON contenant des trajets fictifs et le servir via PHP :
// fake-api.php
$trips = [
    /* Vos données de test */
];
header('Content-Type: application/json');
echo json_encode(['trips' => $trips, 'meta' => [...]);

Utilisation avancée : Webhooks pour les notifications en temps réel

Dans le contexte d'une application de covoiturage, les webhooks sont particulièrement utiles pour recevoir des notifications importantes :

// webhook-handler.php - Point d'entrée pour les webhooks envoyés par l'API
// Vérification de la signature du webhook pour la sécurité
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_CARSHARE_SIGNATURE'] ?? '';

if (!verifyWebhookSignature($payload, $signature, $webhookSecret)) {
    http_response_code(403);
    exit('Signature non valide');
}

$event = json_decode($payload, true);

// Traitement selon le type d'événement
switch ($event['type']) {
    case 'trip.cancelled':
        // Envoi d'un email aux passagers pour les prévenir
        notifyPassengersAboutCancellation($event['data']['trip_id']);
        break;
    
    case 'booking.confirmed':
        // Mise à jour du statut de réservation dans votre BDD
        updateBookingStatus($event['data']['booking_id'], 'confirmed');
        break;
    
    case 'message.new':
        // Notification en temps réel (ex: via WebSockets)
        pushNewMessageNotification($event['data']);
        break;
}

// Réponse rapide à l'API
http_response_code(200);
echo json_encode(['status' => 'success']);
Important : Vérifiez toujours la signature d'un webhook pour éviter que des attaquants n'envoient de fausses données à votre application.