目次
- サンプル・プログラムの実行例
- サンプル・プログラム
- サンプル・プログラムの流れ
- 準備:PHP の https対応
- 準備:pahooGeoCode クラス
- 準備:pahooInputData 関数群
- 準備:逆ジオコーディングサービスの選択
- 準備:各種定数
- 「Google Geocoding API」による住所変換
- 解説:GoogleMaps API Geocoding
- 「Yahoo!リバースジオコーダAPI」による住所変換
- 解説:Yahoo!リバースジオコーダAPI
- 「HeartRails Geo API」による住所変換
- 解説:HeartRails Geo API
- 「簡易逆ジオコーディングサービス」による住所変換
- 解説:簡易逆ジオコーディングサービス
- 解説:検索と結果取得
- 参考サイト
サンプル・プログラムの実行例
サンプル・プログラム
| reverseGeocoding.php | サンプル・プログラム本体。 |
| pahooGeoCode.php | 住所・緯度・経度に関わるクラス pahooGeoCode。 使い方は「PHPで住所・ランドマークから最寄り駅を求める」「PHPで住所・ランドマークから緯度・経度を求める」などを参照。include_path が通ったディレクトリに配置すること。 |
| pahooInputData.php | データ入力に関わる関数群。 使い方は「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。 |
| バージョン | 更新日 | 内容 |
|---|---|---|
| 1.0.0 | 2026/02/07 | 初版 |
| バージョン | 更新日 | 内容 |
|---|---|---|
| 6.9.1 | 2025/11/25 | PHP8.5対応:double→float |
| 6.9.0 | 2025/09/21 | jsPolygon, jsPolygon_Gmap, jsPolygon_Leaflet, loadGeoJSON, getPrefBorderList を追加 |
| 6.8.0 | 2025/08/10 | アクセスキーなどを ".pahooEnd" に分離 |
| 6.7.1 | 2025/07/26 | jsLine_Gmap() - bug-fix |
| 6.7.0 | 2025/07/20 | drawJSmap,drawGMap -- 引数 $markerLevel 追加 |
| バージョン | 更新日 | 内容 |
|---|---|---|
| 2.0.1 | 2025/08/11 | getParam() bug-fix |
| 2.0.0 | 2025/08/11 | pahooLoadEnv() 追加 |
| 1.9.0 | 2025/07/26 | getParam() 引数に$trim追加 |
| 1.8.1 | 2025/03/15 | validRegexPattern() debug |
| 1.8.0 | 2024/11/12 | validRegexPattern() 追加 |
サンプル・プログラムの流れ
準備:PHP の https対応
Windowsでは、"php.ini" の下記の行を有効化する。
extension=php_openssl.dllLinuxでは --with-openssl=/usr オプションを付けて再ビルドする。→OpenSSLインストール手順
これで準備は完了だ。
準備:pahooGeoCode クラス
pahooGeoCode.php
41: class pahooGeoCode {
42: public $items; // 検索結果格納用
43: public $error; // エラー・フラグ
44: public $errmsg; // エラー・メッセージ
45: public $hits; // 検索ヒット件数
46: public $webapi; // 直前に呼び出したWebAPI URL
47:
48: // 都道府県境界線データ
49: // SimpleMaps.com is a product of Pareto Software, LLC. © 2010-2025
50: // https://simplemaps.com/gis/country/jp
51: // ※各自の環境に合わせて設定すること
52: public $GeoJsonJP = __DIR__ . '/jp.json';
53:
54: // -- 以下のデータは .env ファイルに記述可能
55: // Google Cloud Platform APIキー
56: // https://cloud.google.com/maps-platform/
57: // ※Google Maps APIを利用しないのなら登録不要
58: public $GOOGLE_API_KEY_1 = ''; // HTTPリファラ用
59: public $GOOGLE_API_KEY_2 = ''; // IP制限用
60: public $GOOGLE_MAP_ID = ''; // GoogleMaps ID
61:
62: // Yahoo! JAPAN Webサービス アプリケーションID
63: // https://e.developer.yahoo.co.jp/register
64: // ※Yahoo! JAPAN Webサービスを利用しないのなら登録不要
65: public $YAHOO_APPLICATION_ID = '';
66:
67: // OSM Nominatim Search API利用時に知らせるメールアドレス
68: // https://wiki.openstreetmap.org/wiki/JA:Nominatim#.E6.A4.9C.E7.B4.A2
69: // ※OSM Nominatim Search APIを利用しないのなら登録不要
70: public $NOMINATIM_EMAIL = '';
71:
72: // IP2Location.io APIキー
73: // https://www.ip2location.io/
74: // ※IP2Location.ioを利用しないのなら登録不要
75: public $IP2LOCATION_API_KEY = '';
地図や住所検索として Google を利用するのであれば Google Cloud Platform APIキー とマップID が必要で、その入手方法は「Google Cloud Platform - WebAPIの登録方法」を、Yahoo!JAPAN を利用するのであれば Yahoo! JAPAN Webサービス アプリケーションIDが必要で、その入手方法は「Yahoo!JAPAN デベロッパーネットワーク - WebAPIの登録方法」を、IP2Location.ioを利用するのであれば「PHPでIPアドレスやホスト名から住所を求める」を、それぞれ参照されたい。
PHPのクラスについては「PHPでクラスを使ってテキストの読みやすさを調べる」を参照されたい。
準備:pahooInputData 関数群
また、各種クラウドサービスに登録したときに取得するアカウント情報、アプリケーションパスワードなどを登録した .pahooEnv ファイルから読み込む関数 pahooLoadEnv を備えている。こちらについては、「各種クラウド連携サービス(WebAPI)の登録方法」をご覧いただきたい。
準備:逆ジオコーディングサービスの選択
reverseGeocoding.php
64: // 逆ジオコーディングサービスの選択
65: // 0:Google
66: // 1:Yahoo!JAPAN
67: // 11:HeartRails Geo API
68: // 21:簡易ジオコーディングサービス
69: define('REVGEOSERVICE', 11);
GoogleMaps API、YahooデベロッパーネットワークAPI、HeartRails Geo API、簡易ジオコーディングサービスAPI といったクラウドサービスに逆ジオコーディングAPIが用意されおり、あらかじめ定数 REVGEOSERVICE に値を設定することで、いずれかのサービスを利用する。
| 値 | サービス名 | 制 約 |
|---|---|---|
| 0 | 有料(決められた無料枠あり)。 | |
| 1 | Yahoo!JAPAN | 無料(?)。郵便番号が取得できない。 |
| 11 | HeartRails Geo API | 無料。市街地ではビル名が戻ることがある。 |
| 21 | 簡易ジオコーディングサービス | 無料。郵便番号が取得できない。 |
準備:各種定数
reverseGeocoding.php
57: // 各種定数(START) ===========================================================
58:
59: // 地図描画サービスの選択
60: // 0:Google
61: // 2:地理院地図・OSM
62: define('MAPSERVICE', 2);
63:
64: // 逆ジオコーディングサービスの選択
65: // 0:Google
66: // 1:Yahoo!JAPAN
67: // 11:HeartRails Geo API
68: // 21:簡易ジオコーディングサービス
69: define('REVGEOSERVICE', 11);
70:
71: // マップの表示サイズ(単位:ピクセル)
72: define('MAP_WIDTH', 600);
73: define('MAP_HEIGHT', 400);
74:
75: // マップID
76: define('MAPID', 'map_id');
77:
78: // 初期値
79: define('DEF_LATITUDE', 35.67); // 緯度
80: define('DEF_LONGITUDE', 139.78); // 経度
81: define('DEF_TYPE', 'roadmap'); // マップタイプ
82: define('DEF_ZOOM', 8); // ズーム
83: define('DEF_CATEGORY', 'address'); // カテゴリ
84:
85: // マップ中心マーカーのURL;表示しなくなければNULLにする
86: define('CENTER_MARKER', 'https://www.google.com/mapfiles/arrow.png');
87:
88: // 各種定数(END) ===============================================================
「Google Geocoding API」による住所変換
得られる緯度・経度は世界測地系(wgs84)であることに留意されたい。
| URL |
|---|
| https://maps.googleapis.com/maps/api/geocode/xml |
| フィールド名 | 要否 | 内 容 |
|---|---|---|
| key | 必須 | APIキー |
| latlng | 必須 | 検索対象の緯度,経度(世界測地系,10進数の度表記) |
| language | 任意 | 使用言語。ja など |
| sensor | 任意 | true または false |
解説:GoogleMaps API Geocoding
得られる要素が複数あるが、type=street_address であるものが住所表記であるので、これを選別して配列に格納してゆく。
pahooGeoCode.php
390: /**
391: * Google Geocoding API を用いて緯度・経度から住所を求める
392: * @param float $latitude 緯度(世界測地系,10進数の度表記)
393: * @param float $longitude 経度(世界測地系,10進数の度表記)
394: * @return array ['address'] フォーマット済み住所
395: * ['$$$$'] 都道府県など(サービスによって添字が変わる)
396: * FALSE=エラー
397: */
398: function getGoogleAddress($latitude, $longitude) {
399: $key = $this->GOOGLE_API_KEY_2;
400: $url = "https://maps.googleapis.com/maps/api/geocode/xml?key={$key}&latlng={$latitude},{$longitude}&language=ja®ion=JP";
401: $this->webapi = $url;
402:
403: $res = array();
404: $this->unknown_certificate();
405: $xml = simplexml_load_file($url);
406: // レスポンス・チェック
407: if (preg_match("/ok/i", $xml->status) == 0) return FALSE;
408: foreach ($xml->result as $element) {
409: if ($element->type == 'street_address') {
410: $res['address'] = $this->trimAddress((string)$element->formatted_address);
411: // 有効な住所部品を格納
412: foreach ($element->address_component as $elem2) {
413: $str = '';
414: $flag = FALSE;
415: foreach ($elem2->type as $val) {
416: $type = (string)$val;
417: if (preg_match('/_level_[0-9]+/i', $type) > 0) {
418: $str = $type;
419: } else if ($type == 'postal_code') {
420: $flag = TRUE;
421: $str = $type;
422: } else if ($type == 'political') {
423: $flag = TRUE;
424: } else if ($str == '') {
425: $str = $type;
426: }
427: }
428: if ($flag && ($str != '')) {
429: $res[$str] = (string)$elem2->long_name;
430: }
431: }
432: break;
433: }
434: }
435:
436: return $res;
437: }
「Yahoo!リバースジオコーダAPI」による住所変換
得られる緯度・経度は世界測地系(wgs84)であることに留意されたい。
| URL |
|---|
| https://map.yahooapis.jp/geoapi/V1/reverseGeoCoder |
| フィールド名 | 要否 | 内 容 |
|---|---|---|
| appid | 必須 | アプリケーションID |
| lat | 必須 | 検索対象の緯度(世界測地系,10進数の度表記) |
| lng | 必須 | 検索対象の経度(世界測地系,10進数の度表記) |
| datum | 任意 | 測地系 wgs:世界測地系(デフォルト) tky:日本測地系 |
| output | 任意 | 出力形式:xml(デフォルト)/json |
| callback | 任意 | JSONPとして出力する際のコールバック関数名を入力するためのパラメータ。UTF-8でエンコードした文字列を入力する。 |
解説:Yahoo!リバースジオコーダAPI
pahooGeoCode.php
1527: /**
1528: * Yahoo!リバースジオコーダAPIを用いて緯度・経度から住所を求める
1529: * @param float $latitude 緯度(世界測地系,10進数の度表記)
1530: * @param float $longitude 経度(世界測地系,10進数の度表記)
1531: * @return array ['address'] フォーマット済み住所
1532: * ['city'] 市区町村
1533: * ['oaza'] 大字
1534: * ['aza'] 字
1535: * ['detail1'] 街区
1536: * FALSE=エラー
1537: */
1538: function getYOLP_Address($latitude, $longitude) {
1539: $appid = $this->YAHOO_APPLICATION_ID;
1540: $url = "https://map.yahooapis.jp/geoapi/V1/reverseGeoCoder?appid={$appid}&lat={$latitude}&lon={$longitude}&datum=wgs&output=xml";
1541: $this->webapi = $url;
1542:
1543: $res = array();
1544: $this->unknown_certificate();
1545: $xml = simplexml_load_file($url);
1546: // レスポンス・チェック
1547: if (isset($xml->Error)) {
1548: $this->error = TRUE;
1549: $this->errmsg = 'Yahoo!リバースジオコーダAPI - ' . $xml->Message;
1550: $res = FALSE;
1551: } else {
1552: $res['address'] = (string)$xml->Feature->Property->Address;
1553: foreach ($xml->Feature->Property->AddressElement as $val) {
1554: $res[(string)$val->Level] = (string)$val->Name;
1555: }
1556: }
1557:
1558: return $res;
1559: }
「HeartRails Geo API」による住所変換
得られる緯度・経度は世界測地系(wgs84)であることに留意されたい。
| URL |
|---|
| https://geoapi.heartrails.com/api/xml?method=searchByGeoLocation |
| フィールド名 | 要否 | 内 容 |
|---|---|---|
| method | 必須 | メソッド名:searchByGeolocation(固定) |
| y | 必須 | 検索対象の緯度(世界測地系,10進数の度表記) |
| x | 必須 | 検索対象の経度(世界測地系,10進数の度表記) |
解説:HeartRails Geo API
pahooGeoCode.php
1611: /**
1612: * HeartRails Geo API - 緯度経度による住所検索APIを用いて
1613: * 緯度・経度から住所を求める
1614: * @param float $latitude 緯度(世界測地系,10進数の度表記)
1615: * @param float $longitude 経度(世界測地系,10進数の度表記)
1616: * @return array ['address'] フォーマット済み住所
1617: * ['prefecture'] 都道府県名
1618: * ['city'] 市区町村名
1619: * ['town'] 町域名
1620: * ['postal'] 郵便番号
1621: * FALSE=エラー
1622: */
1623: function getHeartRailsGeo_Address($latitude, $longitude) {
1624: // リクエストURL
1625: $url = "https://geoapi.heartrails.com/api/xml?method=searchByGeoLocation&y={$latitude}&x={$longitude}";
1626: $this->webapi = $url;
1627:
1628: $res = array();
1629: $this->unknown_certificate();
1630: $xml = simplexml_load_file($url);
1631: // レスポンス・チェック
1632: if (isset($xml->error)) {
1633: $this->error = TRUE;
1634: $this->errmsg = 'HeartRails Geo API - ' . (string)$xml->error;
1635: $res = FALSE;
1636: } else if (! isset($xml->location)) {
1637: $this->error = TRUE;
1638: $this->errmsg = 'HeartRails Geo APIにトラブル発生';
1639: $res = FALSE;
1640: } else {
1641: foreach ($xml->location as $element) {
1642: $res['prefecture'] = (string)$element->prefecture;
1643: $res['city'] = (string)$element->city;
1644: $res['city_kana'] = (string)$element->{'city-kana'};
1645: $res['town'] = (string)$element->town;
1646: $res['town_kana'] = (string)$element->{'town-kana'};
1647: $res['postal'] = (string)$element->postal;
1648: $res['address'] = $res['prefecture'] . $res['city'] . $res['town'];
1649: break;
1650: }
1651: }
1652:
1653: return $res;
1654: }
「簡易逆ジオコーディングサービス」による住所変換
今回使う入力パラメータと出力結果のデータ構造を以下に示す。バージョン2の出力を利用する。
なお、入力する緯度・経度は世界測地系(wgs84)であることに留意されたい。
出典: 農研機構 (https://aginfo.cgk.affrc.go.jp/)
| URL |
|---|
| https://aginfo.cgk.affrc.go.jp/ws/rgeocode.php |
| フィールド名 | 要否 | 内 容 |
|---|---|---|
| key | 任意 | 出力文書のバージョン。現在は 1 または 2 のみ有効。省略時はバージョン 1。 |
| lat | 必須 | 検索対象点の緯度(世界測地系,10進数の度表記) |
| lon | 必須 | 検索対象点の経度(世界測地系,10進数の度表記) |
| jsonp / php / ponp | 任意 | JSONP, PHPシリアライズ, PONP の各文書種別を指定する。いずれの指定も無い場合はXML文書を応答文書とする。 |
解説:簡易逆ジオコーディングサービス
pahooGeoCode.php
549: /**
550: * 簡易逆ジオコーディングサービスのWebAPI URLを取得する
551: * @param float $latitude 緯度(世界測地系,10進数の度表記)
552: * @param float $longitude 経度(世界測地系,10進数の度表記)
553: * @return string URL URL
554: */
555: function getURLrgeocode($latitude, $longitude) {
556: return "https://aginfo.cgk.affrc.go.jp/ws/rgeocode.php?v=2&lat={$latitude}&lon={$longitude}";
557: }
pahooGeoCode.php
559: /**
560: * 簡易逆ジオコーディングサービスを用いて緯度・経度から住所を求める
561: * @param float $latitude 緯度(世界測地系,10進数の度表記)
562: * @param float $longitude 経度(世界測地系,10進数の度表記)
563: * @return array (都道府県名,市町村名,町丁目,番地)/FALSE=エラー
564: */
565: function getAddress($latitude, $longitude) {
566: // APIコール
567: $url = $this->getURLrgeocode($latitude, $longitude);
568: $this->webapi = $url;
569:
570: // PHP4用; DOM XML利用
571: if ($this->isphp5over() == FALSE) {
572: if (($dom = read_xml($url)) == NULL) return FALSE;
573: $rgeocode = $dom->get_elements_by_tagname('rgeocode');
574: // 住所取得
575: if (($result = $rgeocode[0]->get_elements_by_tagname('result')) == NULL) return FALSE;
576: if (($pref = $result[0]->get_elements_by_tagname('prefecture')) == NULL) return FALSE;
577: if (($pref2 = $pref[0]->get_elements_by_tagname('pname')) == NULL) return FALSE;
578: $prefecture = $pref2[0]->get_content();
579: $muni = $result[0]->get_elements_by_tagname('municipality');
580: $municipality = '';
581: if ($muni != NULL) {
582: $muni2 = $muni[0]->get_elements_by_tagname('mname');
583: if ($muni2 != NULL) $municipality = $muni2[0]->get_content();
584: }
585: $section = '';
586: $homenumber = '';
587: $loc = $result[0]->get_elements_by_tagname('local');
588: if ($loc != NULL) {
589: $loc2 = $loc[0]->get_elements_by_tagname('section');
590: if ($loc2 != NULL) $section = $loc2[0]->get_content();
591: $loc2 = $loc[0]->get_elements_by_tagname('homenumber');
592: if ($loc2 != NULL) $homenumber = $loc2[0]->get_content();
593: }
594:
595: // PHP5用; SimpleXML利用
596: } else {
597: $this->unknown_certificate();
598: $rgeocode = simplexml_load_file($url);
599: // レスポンス・チェック
600: if (! isset($rgeocode->result)) {
601: $this->error = TRUE;
602: $this->errmsg = '簡易ジオコーディングサービス' . (isset($rgeocode->error) ? (' ' . $rgeocode->error) : 'にトラブル発生');
603: return FALSE;
604: }
605: // 住所取得
606: $prefecture = $rgeocode->result->prefecture->pname;
607: $municipality = $rgeocode->result->municipality->mname;
608: $section = $rgeocode->result->local->section;
609: $homenumber = $rgeocode->result->local->homenumber;
610: }
611:
612: return array($prefecture, $municipality, $section, $homenumber);
613: }
解説:検索と結果取得
pahooGeoCode.php
2465: /**
2466: * 指定した緯度・経度から住所を求める(逆ジオコーダ).
2467: *
2468: * @param float $latitude 緯度(世界測地系,10進数の度表記)
2469: * @param float $longitude 経度(世界測地系,10進数の度表記)
2470: * @param int $api 0:Google Geocoding API
2471: * 1:Yahoo!リバースジオコーダAPI
2472: * 11:HeartRails Geo API
2473: * 21:簡易ジオコーディングサービス(省略時)
2474: * @return array ['address'] フォーマット済み住所
2475: * ['postalcode'] 郵便番号(一部サービスのみ)
2476: * ['prefecture'] 都道府県名
2477: * ['city'] 市町村名
2478: * ['local'] 市町村名以下
2479: * FALSE=エラー
2480: */
2481: function getAddress3($latitude, $longitude, $api=21) {
2482: $this->hits = 1;
2483: $ret = array();
2484: switch ($api) {
2485: // Google Geocoding API
2486: case 0:
2487: $res = $this->getGoogleAddress($latitude, $longitude);
2488: if ($res == FALSE) {
2489: $ret = FALSE;
2490: $this->error = TRUE;
2491: $this->errmsg = 'Google Geocoding API にトラブル発生';
2492: $this->hits = 0;
2493: } else {
2494: $ret['address' ] = $res['address'];
2495: $ret['postalcode'] = preg_replace('/\-/', '', $res['postal_code']);
2496: $ret['prefecture'] = $res['administrative_area_level_1'];
2497: $ret['city'] = $res['locality'];
2498: $pat = '/' . $ret['prefecture'] . $ret['city'] . '(.+)$/ui';
2499: $ret['local'] = (preg_match($pat, $ret['address'], $arr) > 0) ?
2500: $arr[1] : '';
2501: }
2502: break;
2503: // Yahoo!リバースジオコーダAPI
2504: case 1:
2505: $res = $this->getYOLP_Address($latitude, $longitude);
2506: if ($res == FALSE) {
2507: $ret = FALSE;
2508: $this->hits = 0;
2509: } else {
2510: $ret['address' ] = isset($res['address']) ? $res['address'] : '';
2511: $ret['postalcode'] = '';
2512: $ret['prefecture'] = isset($res['prefecture']) ? $res['prefecture'] : '';
2513: $ret['city'] = isset($res['city']) ? $res['city'] : '';
2514: $pat = '/' . $ret['prefecture'] . $ret['city'] . '(.+)$/ui';
2515: $ret['local'] = (preg_match($pat, $ret['address'], $arr) > 0) ?
2516: $arr[1] : '';
2517: }
2518: break;
2519: // HeartRails Geo API
2520: case 11:
2521: $res = $this->getHeartRailsGeo_Address($latitude, $longitude);
2522: if ($res == FALSE) {
2523: $ret = FALSE;
2524: $this->hits = 0;
2525: } else {
2526: $ret['address' ] = isset($res['address']) ? $res['address'] : '';
2527: $ret['postalcode'] = isset($res['postal']) ? $res['postal'] : '';
2528: $ret['prefecture'] = isset($res['prefecture']) ? $res['prefecture'] : '';
2529: $ret['city'] = isset($res['city']) ? $res['city'] : '';
2530: $pat = '/' . $ret['prefecture'] . $ret['city'] . '(.+)$/ui';
2531: $ret['local'] = (preg_match($pat, $ret['address'], $arr) > 0) ?
2532: $arr[1] : '';
2533: }
2534: break;
2535: // 簡易逆ジオコーディングサービス
2536: case 21:
2537: $arr = $this->getAddress($latitude, $longitude);
2538: if ($arr == FALSE) {
2539: $ret = FALSE;
2540: $this->hits = 0;
2541: } else {
2542: $ret['address'] = $arr[0] . $arr[1] . $arr[2] . $arr[3];
2543: $ret['postalcode'] = '';
2544: $ret['prefecture'] = $arr[0];
2545: $ret['city'] = $arr[1];
2546: $ret['local'] = $arr[2] . $arr[3];
2547: }
2548: break;
2549: // エラー
2550: default:
2551: $ret = FALSE;
2552: $this->error = TRUE;
2553: $this->errmsg = '逆ジオコーダーAPIの指定ミス';
2554: $this->hits = 0;
2555: break;
2556: }
2557:
2558: return $ret;
2559: }
結果はAPIによらずに等しく使えるように、下記の要素をもつ配列として戻す。エラー時には FALSE を返す。
| 添 字 | 内 容 |
|---|---|
| address | フォーマット済み住所 |
| postalcode | 郵便番号(一部サービスのみ) |
| prefecture | 都道府県名 |
| city | 市町村名 |
| local | 市町村名以下 |
