PHPで住所から緯度・経度を求める(Windowsアプリ版)

(1/1)
PHP でマッシュアップ」で様々なプログラムを紹介しているが、PHP は Web アプリを作るのに便利な言語である。
そこで今回は、「PHP で Google等を利用して住所から緯度・経度を求める」で紹介した「Google Geocoding API V3」「ジオどす II」を利用し、住所や駅名から緯度・経度を求める Windows アプリケーションを作ってみることにする。

サンプル・プログラム

PHPで住所から緯度・経度を求める(Windowsアプリ版)

解説:準備

0023: // GeoCodeクラス =============================================================
0024: class pahooGeoCode {
0025:     var $items;      //検索結果格納用
0026:     var $error;      //エラーフラグ
0027:     var $hits;           //検索ヒット件数
0028:     var $webapi;     //直前に呼び出したWebAPI URL
0029: 

PHP で Google等を利用して住所から緯度・経度を求める」で紹介したクラス pahooGeoCode を利用する。

WebAPI「ジオどす II」では API キーが必要になる。これは http://geodosu.com/user/register から無料で入手することができる。この API キーの値は定数 APIKEY_GEODOS にあらかじめ設定しておく。
また、今回は使用しないが、Yahoo! JAPAN Web サービスを利用する場合は、アプリケーション ID を https://account.edit.yahoo.co.jp/registration から無償取得し、定数 YAHOO_APPLICATION_ID に設定しておく。

解説:XMLパーシング

0107:  * @param string $xml XMLファイル名
0108:  * @return object DOMオブジェクト/NULL 失敗
0109: */
0110: function read_xml($xml) {
0111:     if ($this->isphp5over()) return NULL;
0112:     if (($fp = fopen($xml, 'r')) == FALSE)  return NULL;
0113: 
0114:     //いったん変数に読み込む
0115:     $str = fgets($fp);
0116:     $str = preg_replace('/UTF-8/', 'utf-8', $str);
0117: 
0118:     while (! feof($fp)) {
0119:         $str = $str . fgets($fp);
0120:     }
0121:     fclose($fp);
0122: 
0123:     //DOMを返す
0124:     $dom = domxml_open_mem($str);
0125:     if ($dom == NULL) {
0126:         echo "\n>Error while parsing the document - " . $xml . "\n";
0127:         exit(1);
0128:     }
0129: 
0130:     return $dom;
0131: }
0132: 
0133: /**
0134:  * GoogleMaps API Geocoding(V3) のURLを取得する
0135:  * @param string $query 検索キーワード(UTF-8)
0136:  * @return string URL URL
0137: */
0138: function getURL_GeoCodeAPI_V3($query) {
0139:     $key = $this->GOOGLE_API_KEY;
0140:     return "https://maps.googleapis.com/maps/api/geocode/xml?key={$key}&language=ja&region=JP&address=" . urlencode($query);
0141: }
0142: 
0143: /**
0144:  * Google Geocoding API(V3) を用いて住所・駅名の緯度・経度を求める
0145:  * @param string $query 検索キーワード
0146:  * @param array  $items 情報を格納する配列
0147:  * @return int ヒットした施設数
0148: */
0149: function getPointsV3_all($query, &$items) {
0150:     $url = $this->getURL_GeoCodeAPI_V3($query);   //リクエストURL
0151:     $this->webapi = $url;
0152:     $n = 1;
0153: 
0154: //PEAR::XML_Unserializer
0155:     if (class_exists('XML_Unserializer')) {
0156:         $xml = new XML_Unserializer();
0157:         $xml_data = file_get_contents($url);
0158:         $xml->unserialize($xml_data);
0159:         $arr = $xml->getUnserializedData();
0160:         //レスポンス・チェック
0161:         if (preg_match('/ok/i', $arr['status']) == 0)   return 0;
0162:         //位置情報
0163:         if (isset($arr['result']['geometry'])) {
0164:             $items[$n]['latitude']  = $arr['result']['geometry']['location']['lat'];
0165:             $items[$n]['longitude'] = $arr['result']['geometry']['location']['lng'];
0166:             $items[$n]['address']   = $arr['result']['formatted_address'];
0167:             $n++;
0168:         } else {
0169:             foreach ($arr['result'] as $val) {
0170:                 $items[$n]['latitude']  = $val['geometry']['location']['lat'];
0171:                 $items[$n]['longitude'] = $val['geometry']['location']['lng'];
0172:                 $items[$n]['address']   = $val['formatted_address'];
0173:                 $n++;
0174:             }
0175:         }
0176:         $xml = NULL;
0177: 
0178: //PHP4用; DOM XML利用
0179:     } else if ($this->isphp5over() == FALSE) {
0180:         if (($dom = $this->read_xml($url)) == NULL)  return FALSE;
0181:         $gr = $dom->get_elements_by_tagname('GeocodeResponse');
0182:         //レスポンス・チェック
0183:         $res  = $gr[0]->get_elements_by_tagname('status');
0184:         if (preg_match("/ok/i", $res[0]->get_content()) == 0)  return 0;

PHP で Google等を利用して住所から緯度・経度を求める」で紹介したクラス pahooGeoCode は、そのままのプログラムでは bamcompile でコンパイルできない。
というのは、PHP4 ではクラス DOMElement を使って XML パーシングしているのだが、これが "\Windows\System32\" に配置した "iconv.dll" をロードするためである。 bamcompile は、PHP エクテンション以外の DLL は配置できないのだ。
また、PHP4 には XML をパーシングするための関数  xml_parse  があるのだが、これが使いにくい。

そこで、PEAR にある XML_Unserializer を利用することにした。PEAP::XML_Unserializer は、XML ファイルの内容を連想配列に展開してくれる。

PEAR のインストール方法は公式サイト「PEAR パッケージマネージャの取得とインストール」を参照していただくとして、ここで必要なのは、"PEAR.php", "Parser", "Unserializer" の 3 つだけである。
これを下記のように配置する。
address2geowin
│  address2geowin.bcp
└─address2geowin
     │  address2geowin.phpw
     │  address2geowin.rc
     │  address2geowin.ico
     │  PEAR.phpw
     │  Unserializer.php
     │  Parser.php
     │  php_mbstring.dll
     │  php_winbinder.dll
     ├─include
     │     wb_generic.inc.php
     │     wb_resources.inc.php
     │     wb_windows.inc.php
     │     winbinder.php
     └─icon
         address2geowin.ico
まず、 class_exists  を使って、クラス XML_Unserializer が存在していればオブジェクトを生成する。

メソッド getURL_GeoCodeAPI_V3 は「PHP で Google等を利用して住所から緯度・経度を求める」で紹介したものと同じで、API の結果となる XML の URL を取得する。
関数  file_get_contents  で XML ファイルを読み込み、メソッド unserialize を使ってアンシリアライズする。アンシリアライズした結果を配列 $arr に代入するのに、メソッド getUnserializedData を利用する。
あとは、API が返す XML 構造にしたがって配列 $arr を解釈していけばいい。

注意すべき点は、result が複数ある場合には $arr['result'][0]['geometry']$arr['result'][1]['geometry']$arr['result'][2]['geometry']‥‥のように代入されるが、result が 1 つしかない場合には $arr['result']['geometry'] となる点だ。
ここでは if 文で条件分岐して、どちらの場合も読み込めるようにしてある。

サンプル・プログラムの解説: 緯度・経度を表示

0104: /**
0105:  * 緯度・経度を表示
0106:  * @param  int       $window ウィンドウID
0107:  * @return string    なし
0108: */
0109: function put_geometry($window) {
0110:     $pgc = new pahooGeoCode();
0111: 
0112:     $items = array();
0113:     $query = wb_get_text(wb_get_control($windowIDC_ADDRESS_EDIT));
0114:     $query = sjis2internal($query);
0115:     list($n$url) = $pgc->searchPoint2($query);
0116:     if (! $pgc->iserror()) {
0117:         for ($i = 1; $i <= $n$i++) {
0118:             list($items[$i]['latitude'], $items[$i]['longitude'], $items[$i]['address']) = $pgc->getPoint($i);
0119:         }
0120:         $msg = $items[1]['address'];
0121:         $lat = lat2dgree($items[1]['latitude']);
0122:         $lng = lng2dgree($items[1]['longitude']);
0123:     } else {
0124:         $msg = '**検索失敗**';
0125:         $lat = '';
0126:         $lng = '';
0127:     }
0128:     wb_set_text(wb_get_control($windowIDC_MSG_LABEL), internal2sjis($msg));
0129:     wb_set_text(wb_get_control($windowIDC_LAT_EDIT),  $lat); 
0130:     wb_set_text(wb_get_control($windowIDC_LNG_EDIT),  $lng); 
0131:     unset($items);
0132: 
0133:     $pgc = NULL;
0134: }

「生成」ボタンを押下したときの動作については、ネットに接続していなかったり、API がエラーを返した場合を考慮し、エラーメッセージを変数 $msg に格納し、ラベルとして表示するようにしている。

コンパイル

コンパイルは「PHP で bamcompile を使って EXE プログラムを生成」で紹介したのと同じ手順で、bamcompile.exe を使ってプロジェクトファイル "address2geowin.bcp" をコンパイルする。
コマンドラインから "bamcompile address2geowin.bcp" を実行する。コンパイルが完了すると、"address2geowin.exe" が生成されている。
"address2geowin.exe" は、DLL 不要で、単独で動作する EXE プログラムである。

参考サイト

(この項おわり)
header