מדריך API לסרטים ב-PHP
בנו פונקציית PHP אחת לשימוש חוזר ועמוד סרט קטן. הפונקציה קוראת ל-amodb עם cURL, קוראת את Retry-After ב-429 ושומרת כל תגובה בקובץ ל-6 שעות. העמוד מציג פוסטר, שחקנים וציון IMDb, וכל ערך עובר htmlspecialchars לפני ההצגה. נדרשים PHP 8.2 ומעלה עם תוסף curl וכ-20 דקות.
בונים שני קבצים קטנים. amodb.php מחזיק פונקציה אחת, amodb_get(), שקוראת ל-API עם cURL ושומרת תגובות בקבצים. movie.php הוא עמוד שמציג סרט לפי מזהה עם פוסטר, שחקנים וציון IMDb. צריך PHP 8.2 ומעלה עם התוסף curl וכ-20 דקות.
שלב 1: קבלת מפתח API
קנו תקופה בתשלום מראש בעמוד תמחור. אין מסלול חינמי, וכל מסלול מחזיר את מערך הנתונים המלא ב-20, 40 או 120 בקשות לדקה. צרו מפתח בלוח הבקרה של החשבון. הוא 32 תווים הקסדצימליים באותיות קטנות. ייצאו אותו לפני שמפעילים את PHP:
הקוד קורא אותו עם getenv('AMODB_KEY'). ב-PHP-FPM תהליכי העבודה לא רואים את ה-shell שלכם, ולכן הגדירו במקום זה env[AMODB_KEY] בהגדרות ה-pool.
export AMODB_KEY="YOUR_API_KEY"שלב 2: הכנת הפרויקט
צרו תיקייה ובדקו ש-cURL זמין:
הפקודה הראשונה אמורה לדווח על 8.2 ומעלה. השנייה חייבת להדפיס curl.
mkdir movie-page && cd movie-page
php -v
php -m | grep -i curlשלב 3: שליחת הבקשה הראשונה
קריאת cURL חשופה צריכה ארבעה דברים: הכתובת, פסק זמן, הכותרת Authorization ובדיקת סטטוס. ב-PHP 8 הידית משתחררת מעצמה, ולכן אין 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;שלב 4: עטיפה בפונקציה
קריאה ל-cURL מכל עמוד חוזרת על אותה הגדרה. amodb_ בונה את הכתובת עם http_build_query, שולחת את הקריאה ומחזירה מערך מפוענח. עמוד הסרט מעביר append_, ולכן שחקנים וציונים מגיעים באותה בקשה. פרטי השדות בעמוד סרטים, וגדלי הפוסטרים בעמוד תמונות.
שלב 5: טיפול בשגיאות ובמגבלות קצב
הפונקציה זורקת AmodbException בכל כשל, והעמוד תופס אותה במקום אחד.
| סטטוס | מה הפונקציה עושה |
|---|---|
| 401 | זורקת מיד. מפתח שגוי או מושעה אי אפשר לתקן בניסיון חוזר. |
| 404 | זורקת עם status_message, כדי שהעמוד יוכל לומר שהמזהה לא מוכר. |
| 429 | קוראת את הכותרת Retry-After, ישנה כמספר השניות הזה (1 עד 30) ומנסה שוב עד פעמיים. |
| 5xx | זורקת עם קוד הסטטוס וההודעה. |
| שגיאת cURL | זורקת Network error עם הטקסט מ-curl_error(). |
הכותרת מגיעה דרך CURLOPT_HEADERFUNCTION, פונקציית קריאה חוזרת ש-cURL מריץ לכל שורת כותרת בתגובה. את רשימת הקודים המלאה ראו בעמוד שגיאות.
שלב 6: שמירת תגובות בקבצים
הקצה שומר פרטים 6 שעות. קובץ מקומי חוסך את הבקשה עצמה, ופגיעה במטמון לא עולה דבר מהמגבלה שלכם. הגילאים מצטברים, ולכן קובץ בן 6 שעות יכול להחזיק נתונים שכבר היו בני שעות בקצה. הנמיכו את ה-TTL אם זה חשוב. הפונקציה מגבבת את הכתובת הסופית עם sha1, מחפשת קובץ בשם הזה ומחזירה אותו כשזמן השינוי שלו חדש מה-TTL. אחרת היא שולפת, כותבת את הגוף עם LOCK_EX ומחזירה את הנתונים.
שלב 7: התוכנית המלאה
שמרו את הפונקציה כ-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);
}אחר כך שמרו את העמוד כ-movie.php. כל ערך עובר דרך htmlspecialchars לפני שהוא מגיע ל-HTML.
הפעילו את השרת המובנה עם php -S localhost:8000 ופתחו את http:/. כתובת הפוסטר מצביעה על מארח התמונות, שלא דורש מפתח.
<?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>הצעדים הבאים
- העבירו את המטמון מתיקיית הזמניים לתיקייה שבשליטתכם, ומחקו קבצים ישנים מיום באמצעות משימת cron.
- הוסיפו
language=ru-RUאו אחת מ-14 השפות האחרות ושמרו כל שפה במטמון בנפרד, מה שגיבוב הכתובת כבר עושה. - הוסיפו
moodsל-append_to_responseוהדפיסו את הפריט של$movie['moods']['results']עם ה-avgהגבוה ביותר. ראו מדדי מצב רוח. - קראו על מגבלות קצב, או השוו עם המדריך ב-Go.