特定チャンネルの動画を視聴数順で取得し、ランキング表示する実装方法を解説します。今回は「直近3ヶ月以内に投稿された動画」に絞ったランキング取得を例にします。
事前準備
- Google Cloud Console でプロジェクトを作成
- YouTube Data API v3 を有効化
- 認証情報から APIキー を発行
- 対象チャンネルの チャンネルID を確認(チャンネルページのURL末尾など)
⚠️ APIキーは必ず環境変数や設定ファイルで管理し、ソースコードに直書きしないようにしましょう。
基本実装
<?php// =============================// 設定// =============================$DEVELOPER_KEY = getenv('YOUTUBE_API_KEY'); // 環境変数から取得を推奨$CHANNEL_ID = 'UCxxxxxxxxxxxxxxxxxxxxxxx'; // 対象チャンネルID$MAX_RESULTS = 5; // 取得件数(最大50)$MONTHS_AGO = 3; // 何ヶ月前まで遡るか// 期間の起点日時をISO 8601形式で生成$PERIOD = date('Y-m-d', strtotime("-{$MONTHS_AGO} month")) . 'T00:00:00Z';// =============================// APIリクエスト// =============================$params = [ 'type' => 'video', 'part' => 'snippet', 'maxResults' => $MAX_RESULTS, 'regionCode' => 'JP', 'channelId' => $CHANNEL_ID, 'order' => 'viewCount', // 視聴数順(他: date / rating / relevance) 'publishedAfter'=> $PERIOD, 'key' => $DEVELOPER_KEY,];$url = 'https://www.googleapis.com/youtube/v3/search?' . http_build_query($params);$result = file_get_contents($url);if ($result === false) { die('APIリクエストに失敗しました。');}$result = json_decode($result, true);if (isset($result['error'])) { die('APIエラー: ' . $result['error']['message']);}// =============================// データ整形// =============================$rankingList = [];foreach ($result['items'] as $item) { $rankingList[] = [ 'videoId' => $item['id']['videoId'], 'title' => $item['snippet']['title'], 'description' => $item['snippet']['description'], 'thumbnail_medium' => $item['snippet']['thumbnails']['medium']['url'], 'publishedAt' => $item['snippet']['publishedAt'], 'channelTitle' => $item['snippet']['channelTitle'], ];}PHP
http_build_query()を使うと、配列から安全にURLクエリ文字列を生成できます(特殊文字の自動エスケープつき)。
HTML出力
// =============================// 出力// =============================?><ol class="ranking-list"><?php foreach ($rankingList as $rank => $video): ?> <li class="ranking-item"> <span class="rank-number"><?= $rank + 1 ?></span> <a href="https://www.youtube.com/watch?v=<?= htmlspecialchars($video['videoId']) ?>" target="_blank"> <img src="<?= htmlspecialchars($video['thumbnail_medium']) ?>" alt="<?= htmlspecialchars($video['title']) ?>"> <div class="video-info"> <h3><?= htmlspecialchars($video['title']) ?></h3> <p class="published"><?= date('Y年m月d日', strtotime($video['publishedAt'])) ?></p> <p class="description"><?= htmlspecialchars(mb_substr($video['description'], 0, 80)) ?>...</p> </div> </a> </li><?php endforeach; ?></ol>PHP
htmlspecialchars()で出力時のXSS対策を忘れずに。
視聴数も取得したい場合(videos.list の併用)
search.list のレスポンスには実際の視聴数が含まれません。視聴数を表示したい場合は、取得したビデオIDを使って videos.list を追加で呼び出す必要があります。
// videoIdをカンマ区切りで結合$videoIds = implode(',', array_column($rankingList, 'videoId'));$statsParams = [ 'part' => 'statistics', 'id' => $videoIds, 'key' => $DEVELOPER_KEY,];$statsUrl = 'https://www.googleapis.com/youtube/v3/videos?' . http_build_query($statsParams);$statsResult = json_decode(file_get_contents($statsUrl), true);// rankingListに視聴数をマージ$statsMap = [];foreach ($statsResult['items'] as $item) { $statsMap[$item['id']] = $item['statistics']['viewCount'];}foreach ($rankingList as &$video) { $video['viewCount'] = $statsMap[$video['videoId']] ?? 0;}unset($video);PHPこれで $video['viewCount'] に視聴数が入ります。
応用:キャッシュで API クォータを節約する
YouTube Data API v3 には**1日あたりのクォータ制限(デフォルト10,000ユニット)**があります。毎回APIを叩くのではなく、結果をファイルやDBにキャッシュしておくのがベストプラクティスです。
$cacheFile = __DIR__ . '/cache/youtube_ranking.json';$cacheExpiry = 3600; // 1時間キャッシュif (file_exists($cacheFile) && (time() - filemtime($cacheFile) < $cacheExpiry)) { // キャッシュから読み込み $rankingList = json_decode(file_get_contents($cacheFile), true);} else { // APIから取得(上記コード) // ... // キャッシュに保存 file_put_contents($cacheFile, json_encode($rankingList));}PHPよくあるエラーと対処法
| エラー内容 | 原因 | 対処 |
|---|---|---|
keyInvalid | APIキーが誤っている | Cloud ConsoleでAPIキーを確認 |
quotaExceeded | 1日のクォータ超過 | キャッシュ導入、または翌日まで待つ |
forbidden | APIが有効化されていない | YouTube Data API v3 を有効化 |
| 結果が0件 | チャンネルIDの誤り・対象期間に動画なし | チャンネルIDを再確認 |
まとめ
order=viewCount+publishedAfterで期間絞り込みランキングが取得できる- 実際の視聴数表示は
videos.listとの2段階取得が必要 - APIキーは環境変数管理 & 結果はキャッシュでクォータを節約
- 出力時は必ず
htmlspecialchars()でXSS対策を行う