【PHP】URL から OGP を取得する方法

Contents
はじめに
当サイトでは、外部サイトのサイト名、記事タイトル、サムネイルなどを OGP から取得しています。当サイトが海外旅ブログまとめサイトの為そういった処理を実装しているのですが、人によっては外部サイトのブログカードの出力などで OGP を使いたい方もいらっしゃる方もいるかと思い、こちらの記事にまとめました。
OGP とは
OGP とは Open Graph Protocol の略で、Line や X、Facebook などの SNS でシェアされたときに、ページタイトルやサムネイルなどを適切に伝えるための HTML タグ情報です。
例えば当サイトのトップページの場合、HTML の head に以下のような meta タグを出力をするように設定しています。これらの情報をもとに、SNS でシェアされたときの表示が決まります。
<meta property="og:url" content="https://pancake-trail.site" />
<meta property="og:type" content="website" />
<meta property="og:title" content="パントレ " />
<meta property="og:description" content="海外旅行のための情報サイト( 旅ブログ/YouTube のまとめサイト)" />
<meta property="og:site_name" content="パントレ " />
<meta property="og:image" content="https://pancake-trail.site/wp-content/uploads/2024/04/DSC_2418_00001-1-scaled-e1713623139631.jpg" />
<meta name="twitter:card" content="summary_large_image">
<meta property="twitter:description" content="海外旅行のための情報サイト( 旅ブログ/YouTube のまとめサイト)">
<meta property="twitter:title" content="パントレ ">
<meta property="twitter:url" content="https://pancake-trail.site">
<meta name="twitter:image" content="https://pancake-trail.site/wp-content/uploads/2024/04/DSC_2418_00001-1-scaled-e1713623139631.jpg">
<meta name="twitter:domain" content="パントレ ">
<meta name="twitter:creator" content="@pantredeveloper">
<meta name="twitter:site" content="@pantredeveloper">
外部サイトのブログカードなどを作る場合など、どうしてもサムネイルやサイト名、記事タイトルが欲しくなってくることがあります。HTML の <title> タグの中身を読むとか、<h1> タグの中身を読むとか色々方法は考えられますが、OGP が設定してあるサイトなら、OGP を引っ張ってくるのが一番手っ取り早いです。以下 OGP の取得方法について説明します。
OGP の取得方法
正攻法だと、file_get_contents() で所望の URL の HTML 全てを取得して、preg_match() で og:~ を検索する方法になるかと思います。ただし、URL が長かったり、URL にパラメータがついていたりと、特殊なケースの処理を考える必要があります。
そこで、OpenGraph.php を使う方法をここでは紹介します。2010 年に作られた古の PHP になるのですが、特に問題なく動作するので良しとします。こちらからダウンロードしてください。
以下のような PHP で、オブジェクトとして OGP をとってくることができます。
require_once 'OpenGraph.php';
$graph = OpenGraph::fetch($post_url);
ただし OGP を引っ張ってくるサイトによっては、文字コードの違いにより文字化けを起こしてしまうため、以下のような処理を入れます。いまのところこれで不具合は起こっていません。
if($graph){
$detects = ['ASCII','EUC-JP','SJIS', 'JIS', 'CP51932','UTF-16', 'ISO-8859-1'];
$post_title = esc_attr($graph->title);
$post_thumbnail = esc_url($graph->image);
$site_name = esc_attr($graph->site_name);
$title_check = utf8_decode($post_title);
if(mb_detect_encoding($title_check) == 'UTF-8'){
$post_title = $title_check;
}
if(mb_detect_encoding($post_title) != 'UTF-8'){
$post_title = mb_convert_encoding($post_title, 'UTF-8', mb_detect_encoding($post_title, $detects, true));
}
$thumbnail_check = utf8_decode($post_thumbnail);
if(mb_detect_encoding($thumbnail_check) == 'UTF-8'){
$post_thumbnail = $thumbnail_check;
}
if(mb_detect_encoding($post_thumbnail) != 'UTF-8'){
$post_thumbnail = mb_convert_encoding($post_thumbnail, 'UTF-8', mb_detect_encoding($post_thumbnail, $detects, true));
}
$site_name_check = utf8_decode($site_name);
if(mb_detect_encoding($site_name_check) == 'UTF-8'){
$site_name = $site_name_check;
}
if(mb_detect_encoding($site_name) != 'UTF-8'){
$site_name = mb_convert_encoding($site_name, 'UTF-8', mb_detect_encoding($site_name, $detects, true));
}
}
上記の投稿タイトル、サムネイル URL、サイト名があれば、外部サイトのブログカードを出力できると思います。ただし、OGP の取得にはサイト全てを読み込む必要があり、秒単位で時間がかかります。複数ブログカードを設置した際に都度 OGP を読み込むと、ページ全体の読み込みが 10 秒を超えることもあるので、別途データベースにテーブルを作るなどして、OGP をキャッシュしておくことをおすすめします。
特に、サムネイル画像の直リンクは相手サーバーの負荷にもなるので、自分のサーバーに画像をキャッシュしておいたほうが良いです。これは、file_get_contents() と file_put_contents() で、画像の取得と保存を行うことで実現できます。
$ogp_image = file_get_contents($post_thumbnail);
file_put_contents('画像の保存用パス', $ogp_image);
OGP 画像は重い場合が多いので、リサイズ・圧縮には以下の記事を参照してください。
OGP は更新されることもあるので、サーバーの Cron (定時実行処理) 等を用いて、キャッシュしたデータのデータベースを更新していきましょう。
実行速度うんぬんより、問題は OGP 設定してないサイトにぶつかった場合なんですけどね…
少し宣伝
当サイトは WordPress 自作テーマを用いた海外旅ブログまとめサイトとなっています。トップページに地図がありますが、地名を押すと画像が開き、画像を押すと関連記事一覧(クリック数順)が開きます。記事数が多い国ほど赤く、地名もその国で記事が多い都市の文字が大きくなるようにしています。ぜひ覗いてみてください。
当サイトで海外旅ブログを執筆することも可能です(もちろん無料です)! また既にブログをお持ちの方も、当サイトからリンクを貼ることができるようになっています。パントレ開発部までお気軽にお問い合わせください。
このページが皆様のプログラミングの一助となりますことをお祈りいたします
パントレ開発部