Tutorial API filme PHP
Construiești o funcție PHP reutilizabilă și o pagină de film mică. Funcția apelează amodb cu cURL, citește Retry-After la un 429 și ține fiecare răspuns în cache într-un fișier timp de 6 ore. Pagina arată posterul, distribuția și scorul IMDb. Cere PHP 8.2 sau mai nou cu extensia curl și durează cam 20 de minute.
Vei construi două fișiere mici. amodb.php conține o singură funcție, amodb_get(), care apelează API-ul cu cURL și ține răspunsurile în cache în fișiere. movie.php este o pagină care arată un film după ID, cu poster, distribuție și scorul IMDb. Ai nevoie de PHP 8.2 sau mai nou cu extensia curl și de cam 20 de minute.
Pasul 1: obține o cheie API
Cumpără o perioadă plătită în avans la prețuri. Nu există nivel gratuit, iar fiecare plan întoarce setul complet de date la 20, 40 sau 120 de cereri pe minut. Creează o cheie în panoul contului tău. Are 32 de caractere hexazecimale minuscule. Exportă-o înainte să pornești PHP:
Codul o citește cu getenv('AMODB_KEY'). Sub PHP-FPM, worker-ii nu văd shell-ul tău, deci setează în schimb env[AMODB_KEY] în configurația pool-ului.
export AMODB_KEY="YOUR_API_KEY"Pasul 2: pregătește proiectul
Fă un folder și verifică dacă cURL este disponibil:
Prima comandă ar trebui să raporteze 8.2 sau mai mult. A doua trebuie să afișeze curl.
mkdir movie-page && cd movie-page
php -v
php -m | grep -i curlPasul 3: trimite prima cerere
Un apel cURL simplu are nevoie de patru lucruri: URL-ul, un timeout, antetul Authorization și o verificare a stării. În PHP 8 handle-ul se eliberează singur, deci nu există 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;Pasul 4: învelește-l într-o funcție
Apelarea cURL din fiecare pagină repetă aceeași configurare. amodb_ construiește URL-ul cu http_build_query, trimite apelul și întoarce un array decodat. Pagina de film transmite append_, deci distribuția și scorurile sosesc în aceeași cerere. Detaliile câmpurilor sunt la filme, iar dimensiunile posterelor la imagini.
Pasul 5: tratează erorile și limitele de cereri
Funcția aruncă AmodbException la fiecare eșec, iar pagina o prinde într-un singur loc.
| Stare | Ce face funcția |
|---|---|
| 401 | Aruncă imediat. O cheie greșită sau suspendată nu se repară prin reîncercare. |
| 404 | Aruncă cu status_message, ca pagina să poată spune că ID-ul este necunoscut. |
| 429 | Citește antetul Retry-After, doarme atâtea secunde (de la 1 la 30), apoi reîncearcă de până la două ori. |
| 5xx | Aruncă cu codul de stare și mesajul. |
| Eroare cURL | Aruncă Network error cu textul din curl_error(). |
Antetul sosește prin CURLOPT_HEADERFUNCTION, un callback pe care cURL îl rulează pentru fiecare linie de antet din răspuns. Vezi erori pentru lista completă de coduri.
Pasul 6: păstrează răspunsurile în fișiere
Marginea ține detaliile 6 ore. Un fișier local economisește cererea în sine, iar o lovitură de cache nu costă nimic din limita ta. Vârstele se adună, deci un fișier vechi de 6 ore poate conține date care erau deja vechi de ore la margine. Scade TTL dacă asta contează. Funcția face hash sha1 pe URL-ul final, caută un fișier cu acel nume și îl întoarce când timpul lui de modificare este mai nou decât TTL. Altfel preia, scrie corpul cu LOCK_EX și întoarce datele.
Pasul 7: programul complet
Salvează funcția ca 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);
}Apoi salvează pagina ca movie.php. Fiecare valoare trece prin htmlspecialchars înainte să ajungă în HTML.
Pornește serverul încorporat cu php -S localhost:8000 și deschide http:/. URL-ul posterului indică gazda de imagini, care nu cere cheie.
<?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>Pașii următori
- Mută cache-ul din folderul temporar într-un director pe care îl controlezi și șterge fișierele mai vechi de o zi cu un job cron.
- Adaugă
language=ru-RUsau alta dintre cele 14 limbi și pune în cache fiecare limbă separat, lucru pe care hash-ul URL-ului îl face deja. - Adaugă
moodslaappend_to_responseși afișează intrarea din$movie['moods']['results']cu cel mai mareavg. Vezi atmosfere. - Citește despre limite de cereri sau compară cu tutorialul Go.