PHPで「ぐるなび」を使って喫茶店を探す

(1/1)
ぐるなび Web サービス:レストラン検索API」は、ぐるなびに掲載されている飲食店の基本情報(住所など)や緯度経度、設備情報、クーポン URL、画像 URL などを取得することができる WebAPI サービスだ。
Google や Yahoo!JAPAN の地図サービスをマッシュアップすることで、住所やランドマークから最寄りの喫茶店を求める PHP プログラムを作ってみることにする。

(2019 年 5 月 27 日)地理院地図、OpenStreetMap も利用できるようにした。緯度・経度から住所を検索する逆ジオコーディングサービスの選択肢を増やした。
(2019 年 3 月 16 日)Yahoo! JavaScript マップも利用できるようにした。

サンプル・プログラムの実行例

PHPで「ぐるなび」を使って喫茶店を探す
Google マップ表示

サンプル・プログラムのダウンロード

圧縮ファイルの内容
searchCafe.phpサンプル・プログラム本体
pahooGeoCode.php住所・緯度・経度に関わるクラス pahooGeoCode。
使い方は「PHPで住所・ランドマークから最寄り駅を求める」「PHPで住所・ランドマークから緯度・経度を求める」などを参照。include_path が通ったディレクトリに配置すること。

サンプル・プログラムの流れ

PHPで「ぐるなび」を使って喫茶店を探す
プログラムの流れは「PHP で最寄り駅を求める」の時と同じで、緯度・経度から施設情報を求める部分を、「ぐるなび Web サービス:レストラン検索API」に差し替えただけである。

準備:pahooGeoCode クラス

0035: class pahooGeoCode {
0036:     var $items;      //検索結果格納用
0037:     var $error;      //エラーフラグ
0038:     var $hits;       //検索ヒット件数
0039:     var $webapi; //直前に呼び出したWebAPI URL
0040: 
0041:     //Google Cloud Platform APIキー
0042:     //https://cloud.google.com/maps-platform/
0043:     //※Google Maps APIを利用しないのなら登録不要
0044:     var $GOOGLE_API_KEY_1 = '**************************';   //HTTPリファラ用
0045:     var $GOOGLE_API_KEY_2 = '**************************';   //IP制限用
0046: 
0047:     //Yahoo! JAPAN Webサービス アプリケーションID
0048:     //https://e.developer.yahoo.co.jp/register
0049:     //※Yahoo! JAPAN Webサービスを利用しないのなら登録不要
0050:     var $YAHOO_APPLICATION_ID = '*****************************';

地図サービスを利用するために、クラスファイル "pahooGeoCode.php" を使用する。組み込み関数  require_once  を使って読めるディレクトリに配置する。ディレクトリは、設定ファイル php.ini に記述されているオプション設定 include_path に設定しておく。
クラスについては「PHP でクラスを使ってテキストの読みやすさを調べる」を参照されたい。

地図として Google マップを利用するのであれば、Google Cloud Platform API キー が必要で、その入手方法は「Google Cloud Platform - WebAPI の登録方法」を、YOLP マップを利用するのであれば、Yahoo! JAPAN Web サービス アプリケーション IDが必要で、その入手方法は「Google Cloud Platform - WebAPI の登録方法」を、それぞれ参照されたい。

準備:地図サービス(WebAPI)の選択

0032: //地図描画サービスの選択
0033: //    0:Google
0034: //    1:Yahoo!JAPAN
0035: //    2:地理院地図・OSM
0036: define('MAPSERVICE', 0);
0037: 
0038: //住所検索サービスの選択
0039: //    0:Google
0040: //    1:Yahoo!JAPAN
0041: //   11:HeartRails Geo API
0042: define('GEOSERVICE', 0);
0043: 
0044: //逆ジオコーディングサービスの選択
0045: //    0:Google
0046: //    1:Yahoo!JAPAN
0047: //   11:HeartRails Geo API
0048: //   21:簡易ジオコーディングサービス
0049: define('REVGEOSERVICE', 21);

表示する地図は、Google マップ、[Yahoo!マップ]blue]、地理院地図・オープンストリートマップ(OSM)から選べる。あらかじめ、定数 MAPSERVIC に値を設定すること。
住所検索サービスは、GoogleYahoo!JAPANHeartRails Geo APIから選べる。あらかじめ、定数 GEOSERVICE に値を設定すること。
逆ジオコーディングサービスは、GoogleYahoo!JAPANHeartRails Geo API簡易ジオコーディングサービスから選べる。あらかじめ、定数 REVGEOSERVICE に値を設定すること。
PHPで住所・ランドマークから最寄り駅を求める
Yahoo!マップ表示

準備:ぐるなびWebサービス

0051: //ぐるなびWebサービス アクセスキー:https://api.gnavi.co.jp/api/ で発行
0052: define('GNAVI_ACCESSKEY', '*********************************');

ぐるなび Web サービス」を利用するために、アクセスキーが必要で、入手方法は「ぐるなび Web サービス - WebAPI の登録方法」を参照されたい。

「ぐるなびWebサービス:レストラン検索API」による店舗探索

ぐるなび Web サービス:レストラン検索API」は、入力パラメータ(IN)は GET 渡しで、出力結果(OUT)は JSON で戻すという形である。今回使う入力パラメータと出力結果のデータ構造の一部を以下に記す。
WebAPI
URL
https://api.gnavi.co.jp/RestSearchAPI/v3/

入力パラメータ
フィールド名 要否 内  容
keyid 必須 ぐるなびより提供されたアクセスキー
input_coordinates_mode 任意 入力パラメータに含まれる緯度/経度の測地系を指定
1:日本測地系
2:世界測地系(デフォルト)
latitude 任意 検索地点の緯度(小数表記)
longitude 任意 検索地点の経度(小数表記)
coordinates_mode 任意 レスポンスに含まれる緯度/経度の測地系を指定
1:日本測地系
2:世界測地系(デフォルト)
range 任意 緯度/経度からの検索範囲(半径)
1:300m、2:500m(デフォルト)、3:1000m、4:2000m、5:3000m
freeword 任意 検索ワードをUTF-8でURLエンコードすること「,」区切りで複数ワードが検索可能(10個まで)
出力パラメータ (JSON)
フィールド名 内  容
@attributes api_versionAPIのバージョン
total_hit_count該当件数
hit_per_page表示件数
page_offset表示ページ
total_hit_count表示ページ
rest[] id店舗ID
update_date情報更新日時
name店舗名
name_kana店舗名称(カタカナ)
latitude緯度(小数表記)
longitude経度(小数表記)
categoryフリーワードカテゴリー
urlPCサイトURL
url_mobile携帯サイトURL
address住所
tel電話番号
opentime営業時間
holiday休業日

解説:ぐるなびWebサービス

0222: /**
0223:  * 数値に対応するアルファベットを返す
0224:  * @param int $i 値
0225:  * @return string アルファベット
0226: */
0227: function num2alpha($i) {
0228:     return chr(64 + $i);
0229: }

0231: /**
0232:  * ぐるなびWebサービスのURLを取得する
0233:  * @param double $latitude  緯度(世界測地系)
0234:  * @param double $longitude 経度(世界測地系)
0235:  * @param double $distance  範囲(メートル)
0236:  * @param string $freeword  フリーワード検索(カンマ区切り)
0237:  * @return string URL レストラン検索APIのURL
0238: */
0239: function getURL_RestSearchAPI($latitude$longitude$distance$freeword) {
0240:     $range_tbl = array(1=>300, 2=>500, 3=>1000, 4=>2000, 5=>3000);
0241: 
0242:     $keyid = GNAVI_ACCESSKEY;
0243:     $range = count($range_tbl);
0244:     foreach ($range_tbl as $key=>$val) {
0245:         if ($distance <= $val) {
0246:             $range = $key;
0247:             break;
0248:         }
0249:     }
0250:     $freeword = urlencode($freeword);
0251: 
0252:     $url = "https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid={$keyid}&input_coordinates_mode=2&coordinates_mode=2&latitude={$latitude}&longitude={$longitude}&range={$range}&freeword={$freeword}";
0253: 
0254:     return $url;
0255: }

0257: /**
0258:  * レストラン検索APIを利用して指定座標の近くにある喫茶店を検索
0259:  * @param double $latitude  緯度(世界測地系)
0260:  * @param double $longitude 経度(世界測地系)
0261:  * @param double $distance  範囲(メートル)
0262:  * @param array $items 情報を格納する配列
0263:  * @return array(ヒットした施設数, メッセージ, APIのURL)
0264: */
0265: function searchCafe($latitude$longitude$distance, &$items) {
0266:     $url = getURL_RestSearchAPI($latitude$longitude$distance, '喫茶店');
0267:     $data = @file_get_contents($url);
0268:     $json = json_decode($data);
0269: 
0270:     //レスポンス・チェック
0271:     if (($data == FALSE|| ($json == NULL)) {
0272:         if (isset($json->error->message)) {
0273:             $msg = (string)$json->error->message;
0274:         } else {
0275:             $msg = '検索範囲に店舗が無いか,ぐるなびWebサービスのエラーです';
0276:         }
0277:         return array(FALSE$msg$url);
0278:     }
0279: 
0280:     //応答解釈
0281:     $n = 1;
0282:     foreach ($json->rest as $element) {
0283:         $items[$n]['id']        = num2alpha($n);
0284:         $items[$n]['title']     = (string)$element->name;
0285:         $items[$n]['url']       = (string)$element->url;
0286:         $items[$n]['category']  = (string)$element->category;
0287:         $items[$n]['phone']     = (string)$element->tel;
0288:         $items[$n]['opentime']  = preg_replace("/\n/ui", '<br />', (string)$element->opentime);
0289:         $items[$n]['holiday']   = preg_replace("/\n/ui", '<br />', (string)$element->holiday);
0290:         $items[$n]['latitude']  = (double)$element->latitude;
0291:         $items[$n]['longitude'] = (double)$element->longitude;
0292:         $address = (string)$element->address;
0293:         $address = preg_replace('/〒[0-9\-]+ /ui', '', $address);
0294:         $address = preg_replace("/\n/ui", '<br />', $address);
0295:         $items[$n]['address'] = $address;
0296: $items[$n]['description'] =<<< EOT
0297: <span class="small"><a href="{$items[$n]['url']}" target="_blank">{$items[$n]['title']}</a><br />電話:{$items[$n]['phone']}<br />住所:{$items[$n]['address']}<br />営業時間:{$items[$n]['opentime']}<br />定休日:{$items[$n]['holiday']}</span>
0298: EOT;
0299:         $n++;
0300:     }
0301: 
0302:     return array($n, '', $url);
0303: }

ぐるなび Web サービス:レストラン検索API」を呼び出し、店舗情報を配列 $items に格納するのが、ユーザー関数 searchCafe である。WebAPI の応答を  json_decode  を使って解釈し、配列 $items に格納する。

マップに描画する際に必要になるので、要素 description には、店舗名、電話番号、住所、営業時間、定休日とリンク先 URL をハイパーリンクする。

参考サイト

(この項おわり)
header