#!/usr/local/bin/perl require 'jcode.pl'; my %posParams; # 位置情報群 my %queryParams; # クエリ部分をキー配列にしたもの my $carrier; # 電話会社名 my $agent; # userAgent文字列 my $sDateTime; # 現在日時 my $havePos; # 位置情報ありのフラグ # 現在日時 sub getStrDateTime{ my @days = ("Sun","Mon","Tue","Wed","Thu","Fri","Sat"); my $sec, $min, $hour, $mday, $mon, $year, $wday; ($sec, $min, $hour, $mday, $mon, $year, $wday) = localtime(time); $year += 1900; $mon += 1; if( (length $min)==1 ){ $min = '0' . $min; } if( (length $hour)==1 ){ $hour = '0' . $hour; } $wday = $days[$wday]; return "$year/$mon/$mday($wday) $hour:$min";# :$sec 秒は不要? } $sDateTime = &getStrDateTime(); ################################################# #■ 関数群 sub roundDegree{ # 度(degree)の深い小数桁の丸め return int( $_[0] *10000000 ) /10000000; } # 換算 sub dmsToDegree{ # 度分秒(DMS)を、度(degree) に変換。度は、+- で表現する。 # $_[0] my $sigMinus; #負 my $dms = $_[0]; if( $dms =~ /^[SW-]/i ){ $sigMinus = 1; } #$dms =~ s/^[\w+-]//; #最初の文字[NSEW+-]を消す $dms =~ s/^[^\d]+//; my @ary = split( /\./, $dms ); my $rtnV = 0; if( $ary[0] ){ $rtnV = $rtnV + $ary[0]; }# 度 if( $ary[1] ){ $rtnV = $rtnV + $ary[1] / 60; }# 分 if( $ary[2] ){ $rtnV = $rtnV + $ary[2] / 3600; }# 秒 if( $ary[3] ){# 秒の小数部 my $dn = '0.' . $ary[3];# 小数の形にする。 $rtnV = $rtnV + 1/3600 * $dn;# 1秒相当に小数秒を掛ける。 } $rtnV = &roundDegree( $rtnV );# 深い小数桁を捨てる # int( $rtnV *10000000 ) /10000000; if( $sigMinus ){ $rtnV *= -1; }#南緯・西経の場合 return $rtnV; } sub degreeToDMS{ # 度(degree) を、度分秒(DMS) に変換 # $_[0]: degree , $_[1]: flag{"lat"|"lon"} my $sigMinus; #負 my $azim; #方位 my ( $degree, $flag ) = @_; if( 0 > $degree ){ $sigMinus = 1; $degree *= -1; #符号取去る } if( $flag eq 'lat' ){ if( $sigMinus ){ $azim = 'S'; } else{ $azim = 'N'; } } elsif( $flag eq 'lon' ){ if( $sigMinus ){ $azim = 'W'; } else{ $azim = 'E'; } } else{ if( $sigMinus ){ $azim = '-'; } #else{ $azim = '+'; } } my $d = int( $degree );# 度 my $mvUp = ( $degree - $d ) * 60;# 小数部の繰上げ my $m = int( $mvUp );# 分 $mvUp = ( $mvUp - $m ) * 60;# my $s = int( $mvUp );# 秒 my $f = $mvUp - $s;# 秒の小数部 #$f =~ s/^0\.//; $f = substr( $f, 0, 3 ); #$f = substr( $f, 2, 3 ); $f = int( $f * 1000 +0.5 ) / 1000; # 小数部分を 3桁に丸める<<< $f =~ s/^0\.//; return $azim . $d . '.' . $m . '.' . $s . '.' . $f; } sub degWgs_to_degTokyo{ # 世界測地系→日本測地系、単位は度 # http://blog.gpso.info/2006/08/post_2.html による # $_[0]: lat度 $_[1]: lon度 # 戻り値、( lat, lon ) my ( $la, $ln ) = @_; my $lat = $la + $la * 0.00010696 - $ln * 0.000017467 - 0.0046020; my $lng = $ln + $la * 0.000046047 + $ln * 0.000083049 - 0.010041; return ( &roundDegree( $lat ), &roundDegree( $lng ) ); # 小数の桁数調整(丸め)して返す } sub degTokyo_to_degWgs{ # 日本測地系→世界測地系、単位は度 # http://blog.gpso.info/2006/08/post_2.html による # 高橋登史郎「 入門 Ajax 」にも同じ式をみたが、元の出所は判らない。 my ( $la, $ln ) = @_; my $lat = $la - $la * 0.00010695 + $ln * 0.000017464 + 0.0046017; my $lng = $ln - $la * 0.000046038 - $ln * 0.000083043 + 0.010040; return ( &roundDegree( $lat ), &roundDegree( $lng ) ); } ################################################# #■ USER_AGENT とキャリア $agent = $ENV{'HTTP_USER_AGENT'}; if( $agent =~ /emobile/i ){ $carrier = 'emobile'; } elsif( $agent =~ /DoCoMo/i ){ $carrier = 'DoCoMo'; } elsif( $agent =~ /SoftBank/i ){ $carrier = 'SoftBank'; } elsif( $agent =~ /WILLCOM/i ){ $carrier = 'WILLCOM'; } elsif( $agent =~ /KDDI/i ){ $carrier = 'au'; } #elsif( $agent =~ // ){ carrier = ''; } #■ クエリ( ? 以降)の解析 $query_str = $ENV{'QUERY_STRING'}; @q_list = split( /&/, $query_str ); #分割 foreach $q (@q_list){ my($name, $value) = split( /=/, $q ); # %xx のデコード $name =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg; $queryParams{ $name } = $value; } #■ 位置情報 $posParams{''} # 引数 $queryParams{''} から、位置情報 $posParams{''} を得る。 # 経緯度 if( $queryParams{'pos'} ){# EMOBILE|SoftBank|WILLCOM #$queryParams{'pos'} =~ /(\D[\d.]+)(\D[\d.]+)/; #/[^\d\.]?[\d\.]+/g $queryParams{'pos'} =~ /([^\d\.]?[\d\.]+)([^\d\.]?[\d\.]+)/; $posParams{'lat'} = $1; $posParams{'lon'} = $2; } else{# au|DoCoMo #$posParams{'lat'} = $queryParams{'lat'} || $queryParams{'LAT'}; #$posParams{'lon'} = $queryParams{'lon'} || $queryParams{'LON'}; if( exists $queryParams{'lat'} ){ $posParams{'lat'} = $queryParams{'lat'}; } elsif( exists $queryParams{'LAT'} ){ $posParams{'lat'} = $queryParams{'LAT'}; } if( exists $queryParams{'lon'} ){ $posParams{'lon'} = $queryParams{'lon'}; } elsif( exists $queryParams{'LON'} ){ $posParams{'lon'} = $queryParams{'LON'}; } } # 位置情報が与えられたかどうか、上の経緯度の有無、 if( exists $posParams{'lat'} || exists $posParams{'lon'} ){ $havePos = 1; } # 単位、dms|degree #if( $queryParams{'unit'} eq "1" )# au 単位が「度」 # { $posParams{'unit'} = 'degree'; } if( $posParams{'lat'} =~ /\..+\./ ) # ドットが2つ以上なら「度分秒」 { $posParams{'unit'} = 'dms'; } else{ $posParams{'unit'} = 'degree'; }# 「度」 # 測地系 if( $queryParams{'geo'} ) { $posParams{'geo'} = lc( $queryParams{'geo'} ); } elsif( $queryParams{'GEO'} )# iエリア(DoCoMo) { $posParams{'geo'} = lc( $queryParams{'GEO'} ); } elsif( exists $queryParams{'datum'} ){# au if( $queryParams{'datum'} =~ /[^\d.+-]/ ){# 文字列=数字以外がある、/[a-z]/i $posParams{'info'} = 'eznavi'; # au 簡易位置情報 if( $queryParams{'datum'} =~ /tokyo/i ){ $posParams{'geo'} = 'wgs84'; } #「"tokyo"と..なるが、実際の測地系はWGS84」と。 else{ $posParams{'geo'} = $queryParams{'datum'}; } }else{ if( $queryParams{'datum'} eq "0" ){ $posParams{'geo'} = 'wgs84'; }# au GPS 0|1 elsif( $queryParams{'datum'} eq "1" ){ $posParams{'geo'} = 'tokyo'; } #else{ $posParams{'geo'} = $queryParams{'datum'}; } } } # 精度 $posParams{'accuracy'} = $queryParams{'x-acy'} || $queryParams{'x-acr'} || $queryParams{'x-acc'} || $queryParams{'XACC'} || $queryParams{'fm'}; if( ! defined( $posParams{'accuracy'} ) ){ delete $posParams{'accuracy'}; } # 補足的情報、GPSでなく基地局測位である? if( exists $queryParams{'XACC'} ){ $posParams{'info'} = 'open-iarea'; } # $posParams{'info'} : 'open-iarea' (DoCoMo オープンiエリア)。 # | 'eznavi' (au 簡易位置情報) 既に datum 引数で判別。 # 経緯度の換算 if( $havePos ){ # 位置情報ありなら ↓ ### # 位置が渡されているなら、 ## 引数が日本測地系の場合 if( $posParams{'geo'} =~ /tokyo/i ){ if( $posParams{'unit'} eq 'dms' ){#「度分秒」単位なら $posParams{'tkyDmsLat'} = $posParams{'lat'}; $posParams{'tkyDmsLon'} = $posParams{'lon'}; $posParams{'tkyDegLat'} = &dmsToDegree( $posParams{'tkyDmsLat'} ); $posParams{'tkyDegLon'} = &dmsToDegree( $posParams{'tkyDmsLon'} ); }else{#「度」単位なら $posParams{'tkyDegLat'} = $posParams{'lat'}; $posParams{'tkyDegLon'} = $posParams{'lon'}; $posParams{'tkyDmsLat'} = &degreeToDMS( $posParams{'tkyDegLat'}, 'lat' ); $posParams{'tkyDmsLon'} = &degreeToDMS( $posParams{'tkyDegLon'}, 'lon' ); } # 世界測地系への変換 my @ary = &degTokyo_to_degWgs( $posParams{'tkyDegLat'}, $posParams{'tkyDegLon'} ); $posParams{'wgsDegLat'} = $ary[0]; $posParams{'wgsDegLon'} = $ary[1]; $posParams{'wgsDmsLat'} = &degreeToDMS( $posParams{'wgsDegLat'}, 'lat' ); $posParams{'wgsDmsLon'} = &degreeToDMS( $posParams{'wgsDegLon'}, 'lon' ); } ## 引数が世界測地系の場合 else{ if( $posParams{'unit'} eq 'dms' ){#「度分秒」単位なら $posParams{'wgsDmsLat'} = $posParams{'lat'}; $posParams{'wgsDmsLon'} = $posParams{'lon'}; $posParams{'wgsDegLat'} = &dmsToDegree( $posParams{'wgsDmsLat'} ); $posParams{'wgsDegLon'} = &dmsToDegree( $posParams{'wgsDmsLon'} ); }else{#「度」単位なら $posParams{'wgsDegLat'} = $posParams{'lat'}; $posParams{'wgsDegLon'} = $posParams{'lon'}; $posParams{'wgsDmsLat'} = &degreeToDMS( $posParams{'wgsDegLat'}, 'lat' ); $posParams{'wgsDmsLon'} = &degreeToDMS( $posParams{'wgsDegLon'}, 'lon' ); } # 日本測地系への変換 my @ary = &degWgs_to_degTokyo( $posParams{'wgsDegLat'}, $posParams{'wgsDegLon'} ); $posParams{'tkyDegLat'} = $ary[0]; $posParams{'tkyDegLon'} = $ary[1]; $posParams{'tkyDmsLat'} = &degreeToDMS( $posParams{'tkyDegLat'}, 'lat' ); $posParams{'tkyDmsLon'} = &degreeToDMS( $posParams{'tkyDegLon'}, 'lon' ); } }# 閉、位置情報ありなら ↑ ### ################################################# #■ 出力 # &jcode::sjis('文字列', 'euc'); # Shift_JISで出力。携帯では、Shift_JIS が標準?。 print 'Content-type: text/html; charset=shift_jis', "\n\n"; print '<html lang="ja">', "\n", '<title>', &jcode::sjis('位置情報の表示:', 'euc'), 'CGI</title>', "\n"; print '<body>', "\n"; #▼ 位置情報の表示 if( $havePos ){ # 位置情報ありなら↓↓↓ ### #▽ リンク if( $posParams{'wgsDegLat'} && $posParams{'wgsDegLon'} ){ print '<div>'; print '<a href="http://www.google.co.jp/m/lcb?mp=1' . '&amp;zp=I&amp;loc=' #zp=I:1段階拡大 . $posParams{'wgsDegLat'} . ',' . $posParams{'wgsDegLon'} . '" >Google</a>(' . &jcode::sjis('周辺情報', 'euc') . ') '; # メール my $escDate = $sDateTime; # 置換で元の文字列が変更されない方法は? $escDate =~ s/ /%20/; my $mailBody = 'Date:%20' . $escDate .'%0A' .'World:%20' . $posParams{'wgsDmsLat'} .', ' . $posParams{'wgsDmsLon'} .'%0A' .'%20(Degree)%20' . $posParams{'wgsDegLat'} .', ' . $posParams{'wgsDegLon'} .'%0A' .'Tokyo:%20' . $posParams{'tkyDmsLat'} .', ' . $posParams{'tkyDmsLon'} .'%0A' .'%20(Degree)%20' . $posParams{'tkyDegLat'} .', ' . $posParams{'tkyDegLon'} .'%0A' ; if( $posParams{'accuracy'} ){ $mailBody = $mailBody . 'accuracy:%20' . $posParams{'accuracy'} .'%20'; my $str = ''; if( $carrier eq 'au' ){ $str = '(au: fm)'; } else{ if( $posParams{'accuracy'} eq "1" ){ $str = '(err: 300m--)'; } elsif( $posParams{'accuracy'} eq "2" ){ $str = '(err: 50-300m)'; } elsif( $posParams{'accuracy'} eq "3" ){ $str = '(err: 0-50m)'; } } $mailBody = $mailBody . $str . '%0A'; } if( $posParams{'info'} ){# GPSでなく基地局測位?である場合 $mailBody = $mailBody . '* ' . $posParams{'info'} . '%0A'; } print &jcode::sjis('位置を', 'euc') .'<a href="mailto:?subject=LocationNotice&amp;body=' . $mailBody . '" >' . &jcode::sjis('メール', 'euc'). '</a>'; my $amp = '%26'; if( ($carrier eq 'emobile') && ($agent !~/windows/i) ){ $amp = '%2526'}; # 文字 & が渡らないので。 $mailBody_url = 'Google%20(mobile)%0Ahttp://www.google.co.jp/m/lcb?mp=1'. $amp .'loc=' . $posParams{'wgsDegLat'} .','. $posParams{'wgsDegLon'} .'%0A' .'Google%20Maps%20(PC)%0Ahttp://maps.google.co.jp/maps?q=' . $posParams{'wgsDegLat'} .','. $posParams{'wgsDegLon'} .'%0A' .'Yahoo!%20Map%20(PC)%0Ahttp://map.yahoo.co.jp/pl?lat=' . $posParams{'tkyDegLat'} . $amp .'lon='. $posParams{'tkyDegLon'} . $amp .'mode=map'. $amp .'type=scroll' .'%0A' .'Google%20Basic%0Ahttp://maps.google.co.jp/maps?output=html'. $amp .'q=' . $posParams{'wgsDegLat'} .','. $posParams{'wgsDegLon'} .'%0A' .'Yahoo!%20Static%0Ahttp://map.yahoo.co.jp/pl?lat=' . $posParams{'tkyDegLat'} . $amp .'lon='. $posParams{'tkyDegLon'} . $amp .'mode=map'. $amp .'type=static' .'%0A' ; print "\n". &jcode::sjis('地図URLを', 'euc') .'<a href="mailto:?subject=LocationNotice&amp;body=' .$mailBody_url .'%0A'. $mailBody . '" >' . &jcode::sjis('メール', 'euc'). '</a>'; print '</div>'; } #▽ 日時 print $sDateTime, '<br>', "\n"; #▽ 換算結果 #if( exists $posParams{'wgsDmsLat'} ){ print &jcode::sjis('▽世界測地系', 'euc'), '<br>', "\n"; print $posParams{'wgsDmsLat'}, '<br>', "\n"; print $posParams{'wgsDmsLon'}, '<br>', "\n"; print &jcode::sjis('度: ', 'euc'), $posParams{'wgsDegLat'}, '<br>', "\n"; print '&nbsp; &nbsp;', $posParams{'wgsDegLon'}, '<br>', "\n"; #} if( exists $posParams{'tkyDmsLat'} ){ print &jcode::sjis('▽日本測地系', 'euc'), '<br>', "\n"; print $posParams{'tkyDmsLat'}, '<br>', "\n"; print $posParams{'tkyDmsLon'}, '<br>', "\n"; print &jcode::sjis('度: ', 'euc'), $posParams{'tkyDegLat'}, '<br>', "\n"; print '&nbsp; &nbsp;', $posParams{'tkyDegLon'}, '<br>', "\n"; #▽ 精度 if( exists $posParams{'accuracy'} ){ print &jcode::sjis('*精度:', 'euc'), $posParams{'accuracy'}; if( $carrier eq 'au' ) { print &jcode::sjis( ' (au、小が精度高?)', 'euc' ); } elsif( $posParams{'accuracy'} eq '1' ) { print &jcode::sjis( ' (誤差300m以上)', 'euc' ); } elsif( $posParams{'accuracy'} eq '2' ) { print &jcode::sjis( ' (誤差50〜300m)', 'euc' ); } elsif( $posParams{'accuracy'} eq '3' ) { print &jcode::sjis( ' (誤差50m以内)', 'euc' ); } print '<br>', "\n"; } if( $posParams{'info'} ){# GPSでなく基地局測位である? print '* ' . $posParams{'info'} . '<br>', "\n"; } }# 位置情報ありなら、閉じ↑↑↑ ### else{# print &jcode::sjis('位置情報がない?', 'euc'), '<br>', "\n"; } #▼ キャリア(事業者) print '<hr>', "\n"; if( $carrier ){ print &jcode::sjis('キャリア: ', 'euc'), $carrier, '<br>', "\n"; } else{ print 'userAgent: ', $agent, "<br>\n"; } # userAgentを、キャリアが不明なら表示。 #▼ クエリの表示 print &jcode::sjis('▽引数', 'euc'), '<br>', "\n"; my $num = keys %queryParams; if( $num ){ foreach my $key( keys %queryParams ){ print "$key: $queryParams{$key}<br>\n"; } }else{ print &jcode::sjis('なし。', 'euc'), '<br>', "\n"; } print '<\/body><\/html>', "\n"; exit;