PHPで住所から緯度経度を求める

(1/1)
PHP で Cookie要求サイトにアクセスする」では  fsockopen  関数を使って HTTP通信を行うプログラムを紹介したが、今回はより一般的な HTTP通信関数を作ることで、POST 変数渡しを実現する。
今回の例として、「MapFan」の機能を利用し、日本語の住所から緯度経度を求めるプログラムを作ってみることにする。

なお、MapFan の仕様が変わったため、2017 年(平成 29 年)3 月現在、本プログラムは正常に動作しない

サンプル・プログラム

サンプル・プログラムの解説:HTTP通信

0086: 
0087: /**
0088:  * HTTP通信を行う
0089:  * @param string $url "http://" から始まるURL
0090:  * @param string $method GET,POST,HEAD (省略時はGET)
0091:  * @param string $headers その他の任意のヘッダ (省略時は"")
0092:  * @param array  $post POST変数を格納した連想配列("変数名"=>"値") (省略時はNULL)
0093:  * @param string $cookie Cookie(利用するときは常に$method="POST") (省略時は"")
0094:  * @return string 取得したコンテンツ/FALSE 取得エラー
0095: */
0096: function http($url$method='GET', $header='', $post=NULL$cookie='') {
0097:     if ($cookie != '')  $method = 'POST';
0098:     $URL = parse_url($url);
0099: 
0100:     $URL['query'] = isset($URL['query']) ? $URL['query'] : '';  //クエリ
0101:     $URL['port']  = isset($URL['port'])  ? $URL['port']  : 80;    //ポート番号
0102: 
0103:     //リクエストライン
0104:     $request  = $method . ' ' . $URL['path'] . $URL['query'] . " HTTP/1.1\r\n";
0105: 
0106:     //リクエストヘッダ
0107:     $request .= 'Host: ' . $URL['host'] . "\r\n";
0108:     $request .= 'User-Agent: PHP/' . phpversion() . "\r\n";
0109: 
0110:     //Basic認証用のヘッダ
0111:     if (isset($URL['user']) && isset($URL['pass'])) {
0112:         $request .= 'Authorization: Basic ' . base64_encode($URL['user'] . ':' . $URL['pass']) . "\r\n";
0113:     }
0114: 
0115:     //追加ヘッダ
0116:     $request .= $header;
0117: 
0118:     //POSTの時
0119:     if (strtoupper($method) == 'POST') {
0120:         while (list($name$value) = each($post)) {
0121:             $POST[] = $name . '=' . urlencode($value);
0122:         }
0123:         $postdata = implode('&', $POST);
0124:         $request .= "Content-Type: application/x-www-form-urlencoded\r\n";
0125:         $request .= 'Content-Length: ' . strlen($postdata) . "\r\n";
0126:         if ($cookie != '')  $request .= "Cookie: $cookie\r\n";
0127:         $request .= "\r\n";
0128:         $request .= $postdata;
0129:     } else {
0130:         $request .= "\r\n";
0131:     }
0132: 
0133:     //接続
0134:     $fp = fsockopen($URL['host'], $URL['port']);
0135:     //エラー処理
0136:     if (!$fp)    return FALSE;
0137: 
0138:     //リクエスト送信
0139:     fputs($fp$request);
0140: 
0141:     //応答データ受信
0142:     $response = '';
0143:     while (!feof($fp))   $response .= fgets($fp);
0144: 
0145:     fclose($fp);
0146: 
0147:     return $response;

今回は、汎用的な HTTP通信を行うためのユーザー関数 http を用意した。
この関数は、メソッドとして GET, POST, HEAD を使えるほか、任意のヘッダを渡すことができる。
また、変数を POST 渡しする際は、連想配列を渡すだけで済むようになっている。

サンプル・プログラムの解説:パラメータの準備

0208: 
0209: // メイン・プログラム ======================================================
0210: $address = getParam('address', TRUE, '');
0211: $res = '';
0212: if ($address != '') {
0213:     $post['PARAM'] = mb_convert_encoding($address, 'EUC-JP', INTERNAL_ENCODING);
0214:     $result = http($url$method, '', $post);   //MapFanにアクセス
0215:     echo $result;
0216:     exit(1);
0217:     $res = scraping($result);        //緯度・経度を取り出す
0218:     if ($res == FALSE) {

MapFan に渡す住所は、EUC-JP コードで渡す必要がある。

サンプル・プログラムの解説:スクレイピング

0149: 
0150: /**
0151:  * MapFanのコンテンツから緯度・経度を取り出す
0152:  * @param string $str コンテンツ
0153:  * @return string 緯度・経度/FALSE
0154: */
0155: function scraping($str) {
0156:     if (preg_match("/(Location: http)(.*)/", $str$arr) == 0)   return FALSE;
0157:     $url = 'http' . $arr[2];
0158: 
0159:     $contents = file_get_contents($url);
0160:     if ($contents == '' || $contents == FALSEreturn FALSE;

ユーザー関数 http からの戻り値は、渡した住所に対応する地図を表示する HTML コンテンツである。ここから正規表現を使って必要な文字列を取り出し、緯度・経度に分解する。
このような手順によってウェブサイトから必要なデータを取り出すことを、スクレイピング(ウェブスクレイピング)と呼ぶ。

ちなみに、最近流行っている Ajax は、ユーザー関数 http の部分を JavaScriptの http関数で、戻り値を XML の形にして処理している。戻り値はテキストでも構わない。
(この項おわり)
header