PHPで携帯電話の位置情報を調べる

(1/1)
最近の携帯電話にはGPSレシーバが搭載されている。これを使って、現在位置を表示するプログラムをつくる。
あわせて、日本測地系(tokyo)と世界測地系(wgs84)について考える。

各社携帯電話のGET変数の内容

DoCoMo、au、SoftBank, Willcom各社のGPS対応携帯電話は、特定のタグをクリックすると、GPS衛星から情報を取得し、それをサーバに送信する。送信データはGET変数の形でサーバに渡される。各社の使用は下記の通りだ。
DoCoMoの場合
<a href="GPSを処理するスクリプトのURL" lcs>
変数名 内 容
lat 緯度(全て±dd.mm,ss.sssの度分秒表記)
lon 経度(全て±dd.mm,ss.sssの度分秒表記)
geo 測地系(wgs84 / tokyo )
x-acc 測位レベル(3:水平誤差<50m 2:50m≦水平誤差<300m 1:300m≦水平誤差)
auの場合
<a href="device:gpsone?url=GPSを処理するスクリプトのURL&ver=1&datum=0&unit=1">
変数名 内 容
verGPSのバージョン
datum測地系(0:WGS84 1:tokyo)
unit経度緯度の表記方法( 0:dd.mm.ss.sssの度分秒表記 1:dd.dddの度表記)
lat緯度
lon経度
alt高度
time時間 YYYYMMDDHHiiss
smaj長軸半径誤差
smin短軸半径誤差
vert高度誤差
majaa誤差楕円長軸角度
fm測位方法(数値が少ないほど精度が高い)
SoftBankの場合
<a href="location:auto?url=GPSを処理するスクリプトのURL">
変数名 内 容
posN**.**.**.**E***.**.**.** 座標値(1/100秒単位で度分秒表記 N は北緯、Sは南緯、Eは東経、Wは西経)
geo測地系(wgs84 / tokyo / itrf)
x-acr精度(1:簡易位置情報(300m以上) 2:S!GPSナビ(50m~300m) 3:S!GPSナビ(50m以内))
Willcomの場合
<a href="https://location.request/dummy.cgi?my=GPSを処理するスクリプトのURL&pos=$location">
変数名 内 容
posN**.**.**.**E***.**.**.** 座標値(1/100秒単位で度分秒表記 N は北緯、Sは南緯、Eは東経、Wは西経)

サンプル・プログラム

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

このプログラムはNTT DoCoMoのGPSレシーバ搭載携帯電話専用である。前述の情報を使えば、簡単に他社キャリアに対応できる。

携帯電話の識別

プライバシー保護の観点から、あらかじめ設定された携帯電話の情報だけ拾うことにした。
そのために、携帯電話のシリアル番号判定を行うユーザー関数 isCellPhone を用意した。判定ロジックは、「PHPでユーザー・アクセス情報を表示する」を参照のこと。
また、あらかじめ登録しておく携帯電話のシリアル番号(HTTP USER AGENT で示される文字列)は、グローバル変数 $CellSerials に配列の形で用意しておく。

  13: /**
  14:  * 登録携帯電話のシリアル番号リスト
  15:  * @global  bool $CellSerials
  16: */
  17: $CellSerials = array(
  18:     'DoCoMo/2.0 xxx(xxxxx)'
  19: );
  20: 
  21: /**
  22:  * 登録している携帯電話以外かどうかを調べる
  23:  * @param   string $serials シリアル番号テーブル
  24:  * @return  bool TRUE/FALSE
  25: */
  26: function isCellPhone($serials) {
  27:     //登録シリアルがなければ無条件でTRUE
  28:     if (count($serials) == 0)       return TRUE;
  29: 
  30:     //登録シリアルと合致するかどうかチェック
  31:     foreach ($serials as $val) {
  32:         if ($_SERVER['HTTP_USER_AGENT'] == $val)    return TRUE;
  33:     }
  34:     return FALSE;
  35: }

測地系の違い

携帯電話が返す緯度・経度には2種類の座標系がある。いわゆる「日本測地系」と「世界測地系」である。同じ地点でも、測地系が違うと、緯度・経度にして12秒ほど異なる。これは大きな違いだ。
そこで今回は、表示する緯度・経度を世界測地系(WGS-84)に統一することにした。

明治初期、当時の東京天文台(東京都港区麻布台2-18-1)で行った観測によって日本経緯度原点が定められた。ここを基準にした三角測量によって全国の緯度・経度が測定された。これが日本測地系である。
一方、GPS衛星で測量している世界測地系の一種を WGS-84 と呼ぶ。
日本測地系では、1841年(天保11年)に定められたベッセル楕円体の地球の長半径(6,377,397.155m)を用いてきた。一方の世界措置系では、1980年(昭和55年)に定められたGRS80地球楕円体の長半径(6,378,137m)を利用している。同じ地点でも、測地系が違うと、緯度・経度にして12秒の差が生じするのである。

携帯電話が日本測地系を返す場合には、ユーザー関数 tokyo_wgs84 によって世界測地系に変換する。
今回は使わないが、世界測地系を日本測地系に変換するユーザー関数 wgs84_tokyo も用意した。
いずれも近似式なので、日本以外で使うと誤差が発生することがある。

  46: /**
  47:  * 日本測地系を世界測地系に変換する
  48:  * @param   double $long 経度(日本測地系)
  49:  * @param   double $lat  緯度(日本測地系)
  50:  * @return  double array(経度,緯度)(世界測地系)
  51: */
  52: function tokyo_wgs84($long, $lat) {
  53:     $glong = $long - $lat * 0.000046038 - $long * 0.000083043 + 0.010040;
  54:     $glat  = $lat  - $lat * 0.00010695  + $long * 0.000017464 + 0.0046017;
  55:     return array($glong, $glat);
  56: }
  57: 
  58: /**
  59:  * 世界測地系を日本測地系に変換する
  60:  * @param   double $long 経度(世界測地系)
  61:  * @param   double $lat  緯度(世界測地系)
  62:  * @return  double array(経度,緯度)(日本測地系)
  63: */
  64: function wgs84_tokyo($long, $lat) {
  65:     $glong = $long + $lat * 0.000046047 + $long * 0.000083049 - 0.010041;
  66:     $glat  = $lat  + $lat * 0.00010696  - $long * 0.000017467 - 0.0046020;
  67:     return array($glong, $glat);
  68: }

(この項おわり)
header