目次
- サンプル・プログラムの実行例
- サンプル・プログラム
- サンプル・プログラムの流れ
- 準備:pahooGeoCode クラス
- 準備:住所検索サービスの選択
- 「Google Geocoding API」による緯度・経度変換
- 解説:GoogleMaps API Geocoding
- 「YOLPコンテンツジオコーダAPI」による緯度・経度変換
- 解説:YOLPコンテンツジオコーダAPI
- 「HeartRails Geo API」による緯度・経度変換
- 解説:HeartRails Geo API
- 「OSM Nominatim Search API」による緯度・経度変換
- 解説:OSM Nominatim Search API
- 「国土地理院ジオコーディングAPI」による緯度・経度変換
- 解説:国土地理院ジオコーディングAPI
- 解説:検索と結果取得
- 解説:小数を指定した桁数で丸める
- 解説:メインプログラム
- 質疑応答
- 参考サイト
サンプル・プログラムの実行例
サンプル・プログラム
address2geo.php | サンプル・プログラム本体。 |
pahooGeoCode.php | 住所・緯度・経度に関わるクラス pahooGeoCode。 使い方は「PHPで住所・ランドマークから最寄り駅を求める」「PHPで住所・ランドマークから緯度・経度を求める」などを参照。include_path が通ったディレクトリに配置すること。 |
pahooInputData.php | データ入力に関わる関数群。 使い方は「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。 |
バージョン | 更新日 | 内容 |
---|---|---|
5.5.1 | 2024/09/14 | searchPoint3() -- エラー対策追加 |
5.5.0 | 2023/07/11 | 緯度・経度の小数点以下を指定桁数で丸め表示,検索キーの最小・最大長の指定 |
5.4.0 | 2023/07/02 | 国土地理院ジオコーディングAPIを追加 |
5.3 | 2021/09/18 | PHP8対応,リファラチェック改良,https化 |
5.2 | 2020/03/21 | OSM Nominatim Search API追加 |
バージョン | 更新日 | 内容 |
---|---|---|
6.3.3 | 2024/09/14 | $this->NOMINATIM_EMAIL 追加 |
6.3.2 | 2024/02/14 | getStaticMap() -- bug-fix |
6.3.1 | 2023/07/09 | bug-fix |
6.3.0 | 2023/07/02 | getPointsGSI()追加 |
6.2.0 | 2023/07/02 | ip2address()追加 |
バージョン | 更新日 | 内容 |
---|---|---|
1.5.0 | 2024/01/28 | exitIfExceedVersion() 追加 |
1.4.2 | 2024/01/28 | exitIfLessVersion() メッセージ修正 |
1.4.1 | 2023/09/30 | コメントの訂正 |
1.4.0 | 2023/09/09 | $_GET, $_POST参照をfilter_input()関数に置換 |
1.3.0 | 2023/07/11 | roundFloat() 追加 |
サンプル・プログラムの流れ
準備:pahooGeoCode クラス
37: class pahooGeoCode {
38: var $items; //検索結果格納用
39: var $error; //エラー・フラグ
40: var $errmsg; //エラー・メッセージ
41: var $hits; //検索ヒット件数
42: var $webapi; //直前に呼び出したWebAPI URL
43:
44: //Google Cloud Platform APIキー
45: //https://cloud.google.com/maps-platform/
46: //※Google Maps APIを利用しないのなら登録不要
47: var $GOOGLE_API_KEY_1 = '**************************'; //HTTPリファラ用
48: var $GOOGLE_API_KEY_2 = '**************************'; //IP制限用
49:
50: //Yahoo! JAPAN Webサービス アプリケーションID
51: //https://e.developer.yahoo.co.jp/register
52: //※Yahoo! JAPAN Webサービスを利用しないのなら登録不要
53: var $YAHOO_APPLICATION_ID = '*****************************';
54:
55: //OSM Nominatim Search API利用時に知らせるメールアドレス
56: //https://wiki.openstreetmap.org/wiki/JA:Nominatim#.E6.A4.9C.E7.B4.A2
57: var $NOMINATIM_EMAIL = '*****************************';
58:
59: //ジオどすII APIキー【廃止】
60: //http://geodosu.com/user/register
61: var $APIKEY_GEODOS = '*****************';
62:
63: //IP2Location.io APIキー
64: //https://www.ip2location.io/
65: //※IP2Location.ioを利用しないのなら登録不要
66: var $IP2LOCATION_API_KEY = '*****************';
クラスについては「PHPでクラスを使ってテキストの読みやすさを調べる」を参照されたい。
地図や住所検索として Google を利用するのであれば、Google Cloud Platform APIキー が必要で、その入手方法は「Google Cloud Platform - WebAPIの登録方法」を、Yahoo!JAPAN を利用するのであれば、Yahoo! JAPAN Webサービス アプリケーションIDが必要で、その入手方法は「Yahoo!JAPAN デベロッパーネットワーク - WebAPIの登録方法」を、それぞれ参照されたい。
準備:住所検索サービスの選択
58: //住所検索サービスの選択
59: // 0:Google
60: // 1:Yahoo!ジオコーダAPI
61: // 11:HeartRails Geo API
62: // 12:OSM Nominatim Search API
63: // 13:国土地理院ジオコーディングAPI
64: define('GEOSERVICE', 12);
値 | サービス名 | 制 約 |
---|---|---|
0 | 有料(決められた無料枠あり)。全世界の住所、ランドマークの検索可能。 | |
1 | Yahoo!JAPAN | 無料(?)。住所、ランドマーク、海外のどれを検索するか指定。ランドマークや海外地名検索はGoogleに劣る。 |
11 | HeartRails Geo API | 無料。住所、または住所の一部のみ検索可能。 |
12 | OSM Nominatim Search API | 無料。全世界の住所、ランドマークの検索可能。精度はGoogleに劣る。 |
13 | 国土地理院ジオコーディングAPI | 無料。日本国内の住所、ランドマークの検索可能。精度はGoogleに劣る。 |
「Google Geocoding API」による緯度・経度変換
得られる緯度・経度は世界測地系(wgs84)であることに留意されたい。
URL |
---|
https://maps.googleapis.com/maps/api/geocode/xml |
フィールド名 | 要否 | 内 容 |
---|---|---|
key | 必須 | APIキー |
address | 必須 | 住所やランドマーク(UTF-8) |
language | 任意 | 使用言語。ja など |
sensor | 任意 | true または false |
解説:GoogleMaps API Geocoding
189: /**
190: * 指定した検索キーワードからGoogleMaps API Geocoding(V3) のURLを取得する.
191: * @param string $query 検索キーワード(UTF-8)
192: * @return string URL URL
193: */
194: function getURL_GeoCodeAPI_V3($query) {
195: $key = $this->GOOGLE_API_KEY_2;
196: return "https://maps.googleapis.com/maps/api/geocode/xml?key={$key}&language=ja®ion=JP&address=" . urlencode($query);
197: }
199: /**
200: * 指定した検索キーワードの緯度・経度を求める.
201: * クラウドサービスとしてGoogle Geocoding API(V3) を利用する.
202: * 検索結果結果は複数になることがあり,配列$itemsに格納する.
203: * 参考サイト https://www.pahoo.org/e-soul/webtech/php06/php06-08-01.shtm
204: * @param string $query 検索キーワード
205: * @param array $items 情報を格納する配列
206: * @return int ヒットした施設数/(-1):API呼び出し失敗
207: */
208: function getPointsV3_all($query, &$items) {
209: $url = $this->getURL_GeoCodeAPI_V3($query); //リクエストURL
210: $this->webapi = $url;
211: $n = 1;
212:
213: //PEAR::XML_Unserializer
214: if (class_exists('XML_Unserializer')) {
215: $xml = new XML_Unserializer();
216: $xml_data = file_get_contents($url);
217: $xml->unserialize($xml_data);
218: $arr = $xml->getUnserializedData();
219: //レスポンス・チェック
220: if (preg_match('/ok/i', $arr['status']) == 0) return (-1);
221: //位置情報
222: if (isset($arr['result']['geometry'])) {
223: $items[$n]['latitude'] = $arr['result']['geometry']['location']['lat'];
224: $items[$n]['longitude'] = $arr['result']['geometry']['location']['lng'];
225: $items[$n]['address'] = $this->trimAddress($arr['result']['formatted_address']);
226: $n++;
227: } else {
228: foreach ($arr['result'] as $val) {
229: $items[$n]['latitude'] = $val['geometry']['location']['lat'];
230: $items[$n]['longitude'] = $val['geometry']['location']['lng'];
231: $items[$n]['address'] = $this->trimAddress($val['formatted_address']);
232: $n++;
233: }
234: }
235: $xml = NULL;
236:
237: //PHP4用; DOM XML利用
238: } else if ($this->isphp5over() == FALSE) {
239: if (($dom = $this->read_xml($url)) == NULL) return FALSE;
240: $gr = $dom->get_elements_by_tagname('GeocodeResponse');
241: //レスポンス・チェック
242: $res = $gr[0]->get_elements_by_tagname('status');
243: if (preg_match("/ok/i", $res[0]->get_content()) == 0) return 0;
244: //位置情報
245: $res = $gr[0]->get_elements_by_tagname('result');
246: foreach ($res as $val) {
247: $geo = $val->get_elements_by_tagname('geometry');
248: $loc = $geo[0]->get_elements_by_tagname('location');
249: $lat = $loc[0]->get_elements_by_tagname('lat');
250: $items[$n]['latitude'] = (double)$lat[0]->get_content();
251: $lng = $loc[0]->get_elements_by_tagname('lng');
252: $items[$n]['longitude'] = (double)$lng[0]->get_content();
253: $addr = $val->get_elements_by_tagname('formatted_address');
254: $items[$n]['address'] = $this->trimAddress((string)$addr[0]->get_content());
255: $n++;
256: }
257: //PHP5用; SimpleXML利用
258: } else {
259: $this->unknown_certificate();
260: $res = simplexml_load_file($url);
261: //レスポンス・チェック
262: if (preg_match("/ok/i", $res->status) == 0) return 0;
263: foreach ($res->result as $element) {
264: $items[$n]['latitude'] = (double)$element->geometry->location->lat;
265: $items[$n]['longitude'] = (double)$element->geometry->location->lng;
266: $items[$n]['address'] = $this->trimAddress((string)$element->formatted_address);
267: $n++;
268: }
269: }
270: return ($n - 1);
271: }
検索結果が複数ある場合に備え、緯度・経度・人間が読める住所のセットを、連想配列のプロパティ $items に格納しておく。
「YOLPコンテンツジオコーダAPI」による緯度・経度変換
得られる緯度・経度は世界測地系(wgs84)であることに留意されたい。
URL |
---|
https://map.yahooapis.jp/geocode/cont/V1/contentsGeoCoder |
フィールド名 | 要否 | 内 容 |
---|---|---|
appid | 必須 | アプリケーションID |
query | 必須 | 住所やランドマーク |
ei | 任意 | 文字エンコード:UTF-8(デフォルト)/EUC-JP/SJISなど |
category | 任意 | 検索対象カテゴリ:address(デフォルト)/landmark/world |
results | 任意 | 表示件数:最大10(デフォルト) |
output | 任意 | 出力形式:xml(デフォルト)/json |
callback | 任意 | JSONPとして出力する際のコールバック関数名を入力するためのパラメータ。UTF-8でエンコードした文字列を入力する。 |
解説:YOLPコンテンツジオコーダAPI
1254: /**
1255: * 指定した検索キーワードからYOLPコンテンツジオコーダAPIのURLを取得する.
1256: * @param string $query 検索キーワード(UTF-8)
1257: * @param string $category 検索対象カテゴリ
1258: * address = 住所(省略時)
1259: * landmark = ランドマーク
1260: * world = 世界
1261: * @return string URL リクエストURL
1262: */
1263: function getURL_YOLP_GeoCoder($query, $category='address') {
1264: $appid = $this->YAHOO_APPLICATION_ID;
1265: return "https://map.yahooapis.jp/geocode/cont/V1/contentsGeoCoder?appid={$appid}&el=UTF-8&output=xml&category={$category}&query=" . urlencode($query);
1266: }
1268: /**
1269: * 指定した検索キーワードの緯度・経度を求める.
1270: * クラウドサービスとしてYOLPコンテンツジオコーダAPIを利用する.
1271: * $categoryに検索対象カテゴリをセットする(省略時は'address').
1272: * 検索結果結果は複数になることがあり,配列$itemsに格納する.
1273: * 参考サイト https://www.pahoo.org/e-soul/webtech/php06/php06-08-01.shtm
1274: * @param string $query 検索キーワード
1275: * @param array $items 情報を格納する配列
1276: * @param string $category 検索対象カテゴリ
1277: * address = 住所(省略時)
1278: * landmark = ランドマーク
1279: * world = 世界
1280: * @return int ヒットした施設数/(-1):API呼び出し失敗
1281: */
1282: function getPointsYOLP_all($query, &$items, $category='address') {
1283: $url = $this->getURL_YOLP_GeoCoder($query, $category); //リクエストURL
1284: $this->webapi = $url;
1285: $n = 1;
1286:
1287: $this->unknown_certificate();
1288: $res = simplexml_load_file($url);
1289: //レスポンス・チェック
1290: if (!isset($res->ResultInfo)) return (-1);
1291: if (isset($res->ResultInfo->Total) && ((int)$res->ResultInfo->Total <= 0)) return 0; //v.5.73追加
1292:
1293: foreach ($res->Feature as $element) {
1294: if (preg_match('/([\-0-9\.]+)\,([\-0-9\.]+)/i', $element->Geometry->Coordinates, $arr) > 0) {
1295: if (isset($arr[1]) && isset($arr[2])) {
1296: $items[$n]['latitude'] = (double)$arr[2];
1297: $items[$n]['longitude'] = (double)$arr[1];
1298: $items[$n]['address'] = (string)$element->Property->Address;
1299: $n++;
1300: }
1301: }
1302: }
1303:
1304: return ($n - 1);
1305: }
検索結果が複数ある場合に備え、緯度・経度・住所のセットを、連想配列のプロパティ $items に格納しておく。
1307: /**
1308: * YOLPコンテンツジオコーダAPI のカテゴリ選択ラジオボタンの生成
1309: * @param string $name HTML name
1310: * @param string $default デフォルト値(省略可能)
1311: * @return string HTML
1312: */
1313: function makeYOLP_GeoSelectCategory($name, $default='') {
1314: //デフォルト値設定
1315: if (isset($this->YOLP_GeoCategory[$default])) {
1316: foreach ($this->YOLP_GeoCategory as $key=>$item) {
1317: $item[$key]['checked'] = '';
1318: }
1319: $this->YOLP_GeoCategory[$default]['checked'] = 'checked';
1320: }
1321: //選択ラジオボタンの生成
1322: $html = '';
1323: $i = 1;
1324: foreach ($this->YOLP_GeoCategory as $key=>$val) {
1325: $html .= "<input type=\"radio\" name=\"{$name}\" value=\"{$key}\" {$val['checked']} />{$val['title']} ";
1326: $i++;
1327: }
1328: return $html;
1329: }
1339: /**
1340: * checkedされているカテゴリを検索する
1341: * @return string 選択された関数名/FALSE=checkedされている処理がない
1342: */
1343: function getYOLP_GeoSelectCategory() {
1344: foreach ($this->YOLP_GeoCategory as $key=>$val) {
1345: if ($val['checked'] == 'checked') return $key;
1346: }
1347:
1348: return FALSE;
1349: }
1351: /**
1352: * カテゴリをchekedする
1353: * @param string $val カテゴリ値
1354: * @return bool TRUE/FALSE
1355: */
1356: function setYOLP_GeoSelectCategory($val) {
1357: $old = $this->getYOLP_GeoSelectCategory();
1358: if ($val != FALSE) $this->YOLP_GeoCategory[$old]['checked'] = '';
1359: $this->YOLP_GeoCategory[$val]['checked'] = 'checked';
1360:
1361: return TRUE;
1362: }
「HeartRails Geo API」による緯度・経度変換
得られる緯度・経度は世界測地系(wgs84)であることに留意されたい。
URL |
---|
https://geoapi.heartrails.com/api/xml?method=suggest |
フィールド名 | 要否 | 内 容 |
---|---|---|
method | 必須 | メソッド名:suggest(固定) |
keyword | 必須 | 検索キーワード(UTF-8でURLエンコード) |
matching | 必須 | prefix(前方一致)、like(部分一致)、suffix(後方一致)のいずれか |
解説:HeartRails Geo API
1498: /**
1499: * 指定した検索キーワードの緯度・経度を求める.
1500: * クラウドサービスとしてHeartRails Geo APIの住所検索APIを利用する.
1501: * 検索方式は$matchingにセットする(省略時は'like').
1502: * 検索結果結果は複数になることがあり,配列$itemsに格納する.
1503: * 参考サイト https://www.pahoo.org/e-soul/webtech/php06/php06-08-01.shtm
1504: * @param string $query 検索キーワード:住所のみ(UTF-8)
1505: * @param array $items 情報を格納する配列
1506: * @param string $matching 検索方式
1507: * prefix = 前方一致
1508: * like = 部分一致(省略時)
1509: * suffix = 後方一致
1510: * @return int ヒットした地点数/(-1):API呼び出し失敗
1511: */
1512: function getPointsHeartRailsGeo_all($query, &$items, $matching='like') {
1513: //リクエストURL
1514: $url = "https://geoapi.heartrails.com/api/xml?method=suggest&matching={$matching}&keyword=" . urlencode($query);
1515: $this->webapi = $url;
1516: $n = 1;
1517:
1518: $this->unknown_certificate();
1519: $res = simplexml_load_file($url);
1520: //レスポンス・チェック
1521: if (isset($res->error)) {
1522: $this->error = TRUE;
1523: $this->errmsg = (string)$res->error;
1524: $n = 0;
1525: } else if (! isset($res->location)) {
1526: $this->error = TRUE;
1527: $this->errmsg = 'Not found';
1528: $n = 1;
1529: } else {
1530: foreach ($res->location as $element) {
1531: $items[$n]['latitude'] = (double)$element->y;
1532: $items[$n]['longitude'] = (double)$element->x;
1533: $items[$n]['prefecture'] = (string)$element->prefecture;
1534: $items[$n]['city'] = (string)$element->city;
1535: $items[$n]['city_kana'] = (string)$element->{'city-kana'};
1536: $items[$n]['town'] = (string)$element->town;
1537: $items[$n]['town_kana'] = (string)$element->{'town-kana'};
1538: $items[$n]['postal'] = (string)$element->postal;
1539: $items[$n]['address'] = (string)$element->prefecture . (string)$element->city . (string)$element->town;
1540: $n++;
1541: }
1542: }
1543:
1544: return ($n - 1);
1545: }
検索結果が複数ある場合に備え、緯度・経度・住所のセットを、連想配列のプロパティ $items に格納しておく。
「OSM Nominatim Search API」による緯度・経度変換
なお、2024年(令和6年)9月現在、 User-Agent 文字列の一部にメールアドレスを含めることを求めている。"pahooGeoCode.php" の冒頭に定義している変数 $NOMINATIM_EMAIL にご利用のメールアドレスを代入してほしい。
URL |
---|
https://nominatim.openstreetmap.org/search |
フィールド名 | 要否 | 内 容 |
---|---|---|
format | 任意 | 出力形式。html|xml|json|jsonv2。省略時はhtml |
q | 必須 | 住所やランドマーク(UTF-8) |
json_callback | 任意 | json の出力をラップするコールバック関数(JSONP) |
addressdetails | 任意 | 住所の要素への細分化を含むかどうか。0|1。省略時は0 |
解説:OSM Nominatim Search API
1738: /**
1739: * 指定した検索キーワードの緯度・経度を求める.
1740: * クラウドサービスとしてOSM Nominatim Search API住所検索APIを利用する.
1741: * 検索結果結果は複数になることがあり,配列$itemsに格納する.
1742: * 参考サイト https://www.pahoo.org/e-soul/webtech/php06/php06-08-01.shtm
1743: * @param string $query 検索キーワード:住所のみ(UTF-8)
1744: * @param array $items 情報を格納する配列
1745: * @return int ヒットした地点数/(-1):API呼び出し失敗
1746: */
1747: function getPointsNominatim_all($query, &$items) {
1748: //リクエストURL
1749: $url = 'https://nominatim.openstreetmap.org/search?format=json&q=' . urlencode($query);
1750: $this->webapi = $url;
1751: $n = 1;
1752:
1753: //User-Agent偽装
1754: $header = array(
1755: 'Content-Type: application/x-www-form-urlencoded',
1756: 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ' . $this->NOMINATIM_EMAIL,
1757: );
1758: $stream = stream_context_create(array(
1759: 'http' => array(
1760: 'method' => 'GET',
1761: 'header' => implode("\r\n", $header),
1762: 'ignore_errors'=>TRUE
1763: )
1764: ));
1765: $json = file_get_contents($url, FALSE, $stream);
1766:
1767: //レスポンス・チェック
1768: if ($json == FALSE) {
1769: $this->error = TRUE;
1770: $this->errmsg = '';
1771: $n = 0;
1772: } else {
1773: if ($this->isphp7over()) {
1774: $res = @json_decode($json, FALSE, 512, JSON_BIGINT_AS_STRING);
1775: } else {
1776: $res = @json_decode($json, FALSE, 512);
1777: }
1778: //エラー・チェック
1779: if ($res == FALSE) {
1780: $this->error = TRUE;
1781: $this->errmsg = $res;
1782: return (-1);
1783: }
1784: foreach ($res as $element) {
1785: $items[$n]['latitude'] = (double)$element->lat;
1786: $items[$n]['longitude'] = (double)$element->lon;
1787: $items[$n]['address'] = (string)$element->display_name;
1788: $n++;
1789: }
1790: }
1791: if ($n == 1) {
1792: $this->error = TRUE;
1793: $this->errmsg = 'Not found';
1794: }
1795:
1796: return ($n - 1);
1797: }
クラウドサービスの呼び出し時、User-Agent を設定する目的で、 stream_context_create 関数を利用し、 file_get_contents 関数を呼び出している。
json_decode 関数の呼び出しは、BIGINTの扱いが異なるPHP 7以上と未満で場合分けしている。
検索結果が複数ある場合に備え、緯度・経度・人間が読める住所のセットを、連想配列のプロパティ $items に格納しておく。
「国土地理院ジオコーディングAPI」による緯度・経度変換
なお、国土地理院によると、この機能は主に地理院地図からの利用を想定しているものであり、必ずしも常にまた長期的に提供できるとは限らないし、仕様や利用方法が予告なく変更する場合があるとアナウンスしている。
URL |
---|
https://msearch.gsi.go.jp/address-search/AddressSearch |
フィールド名 | 要否 | 内 容 |
---|---|---|
q | 必須 | 住所やランドマーク(UTF-8) |
解説:国土地理院ジオコーディングAPI
1800: /**
1801: * 指定した検索キーワードの緯度・経度を求める.
1802: * クラウドサービスとして国土地理院ジオコーディングAPIを利用する.
1803: * 検索方式は$matchingにセットする(省略時は'like').
1804: * 検索結果結果は複数になることがあり,配列$itemsに格納する.
1805: * 参考サイト https://www.pahoo.org/e-soul/webtech/php06/php06-08-01.shtm
1806: * @param string $query 検索キーワード:住所のみ(UTF-8)
1807: * @param array $items 情報を格納する配列
1808: * @return int ヒットした地点数/(-1):API呼び出し失敗
1809: */
1810: function getPointsGSI($query, &$items) {
1811: //リクエストURL
1812: $url = "https://msearch.gsi.go.jp/address-search/AddressSearch?q=" . urlencode($query);
1813: $this->webapi = $url;
1814: $n = 1;
1815:
1816: $this->unknown_certificate();
1817: $json = file_get_contents($url);
1818: //レスポンス・チェック
1819: if ($json == FALSE) {
1820: $this->error = TRUE;
1821: $this->errmsg = '国土地理院ジオコーディングAPIが応答しません';
1822: $n = 0;
1823: } else {
1824: $arr = json_decode($json);
1825: if (count($arr) == 0) {
1826: $this->error = TRUE;
1827: $this->errmsg = '住所が見つかりません';
1828: $n = 0;
1829: } else {
1830: foreach ($arr as $element) {
1831: $items[$n]['latitude'] = (double)$element->geometry->coordinates[1];
1832: $items[$n]['longitude'] = (double)$element->geometry->coordinates[0];
1833: $items[$n]['address'] = (string)$element->properties->title;
1834: $items[$n]['postal'] = (string)$element->properties->addressCode;
1835: $n++;
1836: }
1837: }
1838: }
1839:
1840: return ($n - 1);
1841: }
解説:検索と結果取得
2208: /**
2209: * 指定した検索キーワードの緯度・経度を求める.
2210: * クラウドサービスとしてGoogle Geocoding API, Yahoo!ジオコーダAPI,
2211: * HeartRails Geo API, OSM Nominatim Search API,
2212: * 国土地理院ジオコーディングAPIを指定できる.
2213: * Yahoo!ジオコーダAPIを利用する場合は,検索対象カテゴリ$categoryをセットする.
2214: * (省略時は 'like')
2215: * 検索結果結果は複数になることがあり,配列$itemsに格納する.
2216: * 参考サイト https://www.pahoo.org/e-soul/webtech/php06/php06-08-01.shtm
2217: *
2218: * @param string $query 検索キーワード(UTF-8)
2219: * @param int $api 0:Google Geocoding API(省略時)
2220: * 1:Yahoo!ジオコーダAPI
2221: * 11:HeartRails Geo API
2222: * 12:OSM Nominatim Search API
2223: * 13:国土地理院ジオコーディングAPI
2224: * @param string $category 検索対象カテゴリ(YOLPのみ必要)
2225: * address = 住所(省略時)
2226: * landmark = ランドマーク
2227: * world = 世界
2228: * @return array(int ヒットした地点数,string WebAPI)
2229: */
2230: function searchPoint3($query, $api=0, $category='address') {
2231: static $pat1 = '/E(\d+\.?\d*)N(\d+\.?\d*)/i';
2232: static $pat2 = '/E(\d+)\.(\d+)\.(\d+)\.(\d+)N(\d+)\.(\d+)\.(\d+)\.(\d+)/i';
2233:
2234: unset($this->items);
2235: $this->items = array();
2236: $this->hits = 0;
2237:
2238: //緯度・経度表記(1)
2239: if (preg_match($pat1, $query) > 0) {
2240: list($this->items[1]['latitude'], $this->items[1]['longitude']) =
2241: $this->parse_geo($query);
2242: $this->items[1]['address'] = '';
2243: $this->hits = 1;
2244:
2245: //緯度・経度表記(2)
2246: } else if (preg_match($pat2, $query) > 0) {
2247: list($this->items[1]['latitude'], $this->items[1]['longitude']) =
2248: $this->parse_geo($query);
2249: $this->items[1]['address'] = '';
2250: $this->hits = 1;
2251:
2252: //Google Geocoding API使用
2253: } else if ($api == 0) {
2254: $n = $this->getPointsV3_all($query, $this->items);
2255: if ($n == (-1)) { //v.5.73修正
2256: $this->error = TRUE;
2257: $this->errmsg = 'Google Geocoding APIにトラブル発生';
2258: $this->hits = 0;
2259: } else if ($n == 0) {
2260: $this->error = TRUE;
2261: $this->errmsg = '指定キーワードでは検索できない';
2262: $this->hits = 0;
2263: } else {
2264: $this->hits = $n;
2265: }
2266:
2267: //Yahoo!ジオコーダAPI使用
2268: } else if ($api == 1) {
2269: $n = $this->getPointsYOLP_all($query, $this->items, $category);
2270: if ($n == (-1)) { //v.5.73修正
2271: $this->error = TRUE;
2272: $this->errmsg = 'Yahoo!ジオコーダAPIにトラブル発生';
2273: $this->hits = 0;
2274: } else if ($n == 0) {
2275: $this->error = TRUE;
2276: $this->errmsg = '指定キーワードでは検索できない';
2277: $this->hits = 0;
2278: } else {
2279: $this->hits = $n;
2280: }
2281:
2282: //HeartRails Geo API使用
2283: } else if ($api == 11) {
2284: $n = $this->getPointsHeartRailsGeo_all($query, $this->items, 'like');
2285: if ($n == (-1)) { //v.5.73修正
2286: $this->hits = 0;
2287: } else if ($n == 0) {
2288: $this->errmsg = '指定キーワードでは検索できない';
2289: $this->hits = 0;
2290: } else {
2291: $this->hits = $n;
2292: }
2293:
2294: //OSM Nominatim Search API使用
2295: } else if ($api == 12) {
2296: $n = $this->getPointsNominatim_all($query, $this->items);
2297: if ($n == (-1)) {
2298: $this->errmsg = 'OSM Nominatim Search APIにトラブル発生';
2299: $this->hits = 0;
2300: } else if ($n == 0) {
2301: $this->errmsg = '指定キーワードでは検索できない';
2302: $this->hits = 0;
2303: } else {
2304: $this->hits = $n;
2305: }
2306:
2307: //国土地理院ジオコーディングAPIs使用
2308: } else if ($api == 13) {
2309: $n = $this->getPointsGSI($query, $this->items);
2310: if ($n > 0) {
2311: $this->hits = $n;
2312: }
2313:
2314: //エラー
2315: } else {
2316: $this->error = TRUE;
2317: $this->errmsg = 'ジオコーダーAPIの指定間違い';
2318: $this->hits = 0;
2319: }
2320:
2321: return array($this->hits, $this->webapi);
2322: }
結果はプロパティ $items に格納する。戻り値としてヒットした件数を返す。
338: /**
339: * 検索結果(緯度・経度)を取得
340: * @param int $id 取得したい地点番号
341: * @return array(緯度,経度,住所):世界測地系
342: */
343: function getPoint($id) {
344: if ($id <= 0 || $id > $this->hits) {
345: $this->error = TRUE;
346: $this->errmsg = '不正な地点番号';
347: $latitude = FALSE;
348: $longitude = FALSE;
349: $address = FALSE;
350: } else {
351: $this->error = FALSE;
352: $this->errmsg = '';
353: $latitude = $this->items[$id]['latitude'];
354: $longitude = $this->items[$id]['longitude'];
355: $address = $this->items[$id]['address'];
356: }
357:
358: return array($latitude, $longitude, $address);
359: }
解説:小数を指定した桁数で丸める
494: /**
495: * 小数を指定した桁数で丸めて文字列として返す。
496: * 与えた小数の有効桁数より指定桁数が多いときには,末尾に0をサプレスする.
497: * @参考URL https://www.pahoo.org/e-soul/webtech/php06/php06-08-01.shtm
498: * @param float $x 丸めたい小数
499: * @param int $dp 小数点以下の桁数(0:整数,負数:丸めない)
500: * @return string 丸めた結果
501: */
502: function roundFloat($x, $dp) {
503: //丸めない
504: if ($dp < 0) {
505: $y = sprintf('%f', $x);
506: //整数に丸める
507: } else if ($dp == 0) {
508: $y = sprintf('%d', $x);
509: //指定した桁数に丸める
510: } else {
511: $ft = '%.' . (int)$dp . 'f';
512: $y = sprintf($ft, $x);
513: }
514: return (string)$y;
515: }
組み込み関数 sprintf を利用し、小数を指定した桁数で丸めて文字列として返す。与えた小数の有効桁数より指定桁数が多いときには、末尾に0をサプレスする。
解説:メインプログラム
66: //初期値
67: define('DEF_QUERY', '東京都千代田区丸の内一丁目'); //検索キー
68: define('DEF_CATEGORY', 'address'); //カテゴリ
69:
70: //表示幅(ピクセル)
71: define('WIDTH', 600);
72:
73: //緯度・経度の小数点以下表示桁数(0:整数に丸める,負数:丸めない)
74: define('DISPLAY_DECIMAL_POINT', 6);
75:
76: //検索キーの最小文字長
77: define('QUERY_MIN_LEN', 3);
78:
79: //検索キーの最大文字長
80: define('QUERY_MAX_LEN', 99);
81:
82: //住所・緯度・経度に関わるクラス:include_pathに配置すること
83: require_once('pahooGeoCode.php');
質疑応答
国土地理院のジオコーディングはお試しになっていたと思いますが、なぜ利用されて居なかったのでしょうか? 精度でしょうか?(ヨッシーXX様,2023年6月30日)【回答】
有用な情報をありがとうございます。試していませんでした。近いうちに試してみて、プログラムから利用できるようにしようと思います。
【質問】
PHPで住所・ランドマークから緯度・経度を求めるにおいて、プログラムを実行するとエラーとなっていました。【回答】
ダウンロードしたものもエラーを吐いて実行できませんでした(私の設定ミスでしたら申し訳ありません。) (2024年8月30日)
デフォルトで使用している OSM Nominatim Search API でメールアドレスを知らせないとAPIエラーが出ることが分かりました。これに合わせてプログラムを改良しました。"pahooGeoCode.php" の冒頭に定義している変数 $NOMINATIM_EMAIL にご利用のメールアドレスを代入してください。
また、大量APIコールで OSM Nominatim Search API に負荷をかけてはいけないので、本ページからサンプル・プログラムの実行を省きました。
これらサービスのうち Google は全世界を対象として最も精度の高い検索が可能だが、有料サービスに移行したため(無料枠あり)、その他の無料利用できるサービスを選択できるようにしている。
ぱふぅ家のホームページで紹介するプログラムの住所検索機能は、すべてこのクラス pahooGeoCode を流用している。
(2024年9月14日)pahooGeoCode->$NOMINATIM_EMAIL追加, searchPoint3()のエラー対策追加