Tutoriel API de films en PHP
Créez une fonction PHP réutilisable et une petite page de film. La fonction appelle amodb avec cURL, lit Retry-After sur un 429 et met chaque réponse en cache dans un fichier pendant 6 heures. La page affiche l'affiche, la distribution et la note IMDb. Il faut PHP 8.2 ou plus récent avec l'extension curl et environ 20 minutes.
Vous allez construire deux petits fichiers. amodb.php contient une fonction, amodb_get(), qui appelle l'API avec cURL et met les réponses en cache dans des fichiers. movie.php est une page qui montre un film par identifiant avec l'affiche, la distribution et la note IMDb. Il vous faut PHP 8.2 ou plus récent avec l'extension curl et environ 20 minutes.
Étape 1 : obtenir une clé d'API
Achetez une période prépayée sur les tarifs. Il n'y a pas d'offre gratuite, et chaque offre renvoie le jeu de données complet à 20, 40 ou 120 requêtes par minute. Créez une clé dans le tableau de bord de votre compte. Elle fait 32 caractères hexadécimaux en minuscules. Exportez-la avant de lancer PHP :
Le code la lit avec getenv('AMODB_KEY'). Sous PHP-FPM, les workers ne voient pas votre shell : définissez plutôt env[AMODB_KEY] dans la configuration du pool.
export AMODB_KEY="YOUR_API_KEY"Étape 2 : préparer le projet
Créez un dossier et vérifiez que cURL est disponible :
La première commande doit indiquer 8.2 ou plus. La seconde doit afficher curl.
mkdir movie-page && cd movie-page
php -v
php -m | grep -i curlÉtape 3 : envoyer la première requête
Un appel cURL nu demande quatre choses : l'URL, un délai d'expiration, l'en-tête Authorization et une vérification du statut. En PHP 8, le handle se libère tout seul : il n'y a donc pas de curl_close().
<?php
$ch = curl_init('https://api.amodb.dev/3/movie/550?language=en-US');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('AMODB_KEY')],
]);
$body = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;Étape 4 : l'envelopper dans une fonction
Appeler cURL depuis chaque page répète la même configuration. amodb_ construit l'URL avec http_build_query, envoie l'appel et renvoie un tableau décodé. La page de film passe append_, si bien que la distribution et les notes arrivent dans la même requête. Les détails des champs sont sur films, et les tailles d'affiches sur images.
Étape 5 : gérer les erreurs et les limites de débit
La fonction lève AmodbException pour chaque échec, et la page l'intercepte à un seul endroit.
| Statut | Ce que fait la fonction |
|---|---|
| 401 | Lève aussitôt. Une clé mauvaise ou suspendue ne se corrige pas en réessayant. |
| 404 | Lève avec le status_message, pour que la page puisse dire que l'identifiant est inconnu. |
| 429 | Lit l'en-tête Retry-After, attend ce nombre de secondes (de 1 à 30), puis réessaie jusqu'à deux fois. |
| 5xx | Lève avec le code de statut et le message. |
| Erreur cURL | Lève Network error avec le texte de curl_error(). |
L'en-tête arrive via CURLOPT_HEADERFUNCTION, un rappel que cURL exécute pour chaque ligne d'en-tête de la réponse. Voir erreurs pour la liste complète des codes.
Étape 6 : mettre les réponses en cache dans des fichiers
La périphérie garde les détails 6 heures. Un fichier local économise la requête elle-même, et un succès du cache ne coûte rien sur votre limite. Les âges s'additionnent : un fichier de 6 heures peut donc contenir des données qui avaient déjà des heures à la périphérie. Baissez la durée de vie si cela compte. La fonction calcule le hachage sha1 de l'URL finale, cherche un fichier de ce nom et le renvoie si sa date de modification est plus récente que la durée de vie. Sinon elle récupère les données, écrit le corps avec LOCK_EX et renvoie les données.
Étape 7 : le programme complet
Enregistrez la fonction sous amodb.php.
<?php
declare(strict_types=1);
const AMODB_BASE = 'https://api.amodb.dev/3';
final class AmodbException extends RuntimeException
{
}
function amodb_get(string $path, array $query = [], int $ttl = 21600): array
{
$key = getenv('AMODB_KEY');
if ($key === false || $key === '') {
throw new AmodbException('Set the AMODB_KEY environment variable.');
}
$url = AMODB_BASE . $path . ($query ? '?' . http_build_query($query) : '');
$dir = sys_get_temp_dir() . '/amodb-cache';
$file = $dir . '/' . sha1($url) . '.json';
if (is_file($file) && time() - filemtime($file) < $ttl) {
return json_decode((string) file_get_contents($file), true, 512, JSON_THROW_ON_ERROR);
}
for ($attempt = 1; $attempt <= 3; $attempt++) {
$retryAfter = 1;
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key, 'Accept: application/json'],
CURLOPT_HEADERFUNCTION => static function ($handle, string $line) use (&$retryAfter): int {
if (stripos($line, 'retry-after:') === 0) {
$retryAfter = (int) trim(substr($line, 12));
}
return strlen($line);
},
]);
$body = curl_exec($ch);
$status = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$error = curl_error($ch);
if ($body === false) {
throw new AmodbException('Network error: ' . $error);
}
if ($status !== 429 || $attempt === 3) {
break;
}
sleep(max(1, min($retryAfter, 30)));
}
if ($status === 401) {
throw new AmodbException('401: the API key is invalid or suspended.');
}
if ($status !== 200) {
$detail = json_decode((string) $body, true)['status_message'] ?? 'no message';
throw new AmodbException("amodb returned $status: $detail");
}
if (!is_dir($dir)) {
mkdir($dir, 0775, true);
}
file_put_contents($file, $body, LOCK_EX);
return json_decode($body, true, 512, JSON_THROW_ON_ERROR);
}Enregistrez ensuite la page sous movie.php. Chaque valeur passe par htmlspecialchars avant d'arriver dans le HTML.
Démarrez le serveur intégré avec php -S localhost:8000 et ouvrez http:/. L'URL de l'affiche pointe vers l'hôte d'images, qui n'exige aucune clé.
<?php
declare(strict_types=1);
require __DIR__ . '/amodb.php';
function h(?string $text): string
{
return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8');
}
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT) ?: 550;
$movie = null;
$error = null;
try {
$movie = amodb_get("/movie/$id", ['language' => 'en-US', 'append_to_response' => 'credits,ratings']);
} catch (AmodbException $e) {
http_response_code(502);
$error = $e->getMessage();
}
$imdb = $movie['ratings']['imdb'] ?? null;
$cast = $movie ? array_slice(array_column($movie['credits']['cast'], 'name'), 0, 3) : [];
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title><?= h($movie['title'] ?? 'Movie lookup') ?></title>
</head>
<body>
<?php if ($error !== null): ?>
<p>Could not load the movie: <?= h($error) ?></p>
<?php else: ?>
<h1><?= h($movie['title']) ?> (<?= h(substr((string) ($movie['release_date'] ?? ''), 0, 4)) ?>)</h1>
<?php if (!empty($movie['poster_path'])): ?>
<img src="https://img.amodb.dev/t/p/w342<?= h($movie['poster_path']) ?>" alt="Poster of <?= h($movie['title']) ?>" width="342">
<?php endif; ?>
<p><?= h($movie['overview'] ?? '') ?></p>
<p>Cast: <?= h(implode(', ', $cast)) ?></p>
<p>IMDb: <?= $imdb ? h((string) $imdb['value']) : 'not known' ?></p>
<?php endif; ?>
</body>
</html>Pour aller plus loin
- Déplacez le cache du dossier temporaire vers un répertoire que vous contrôlez, et supprimez les fichiers de plus d'un jour avec une tâche cron.
- Ajoutez
language=ru-RUou une autre des 14 langues et mettez chaque langue en cache séparément, ce que fait déjà le hachage de l'URL. - Ajoutez
moodsàappend_to_responseet affichez l'entrée de$movie['moods']['results']ayant leavgle plus élevé. Voir ambiances. - Lisez les limites de débit, ou comparez avec le tutoriel Go.