Google Map API 結合PHP實現登入地圖定位
Google Map API 結合PHP實現登入定位主要思想是在使用者登入系統時記錄下IP地址,在通過相關的地址索引由IP轉換到物理地址,最後通過Google Map API將取得的物理地址標示在Google地圖上。
?
php平台由ThinkPHP架構搭建。具體流程圖如下:
?
這裡用到了CoralWry這個資料檔案,網上有的下載的,以前的彩虹QQ什麼的都是用這個檔案解析的,不過可能有時候需要更新IP的緣故會對此檔案進行更新,下面有下載包。這個檔案放在根目錄下
?
繼續,在TP中引入一下兩個檔案作為外鏈調用庫,可以直接放入TP核心檔案夾的Lib下的ORG擴充庫中
IpLocation類,這個擴充類是從DAT檔案中將IP提取地址所用
?
class IpLocation {var $fp;var $firstip; //第一條ip索引的位移地址var $lastip; //最後一條ip索引的位移地址var $totalip; //總ip數//*//建構函式,初始化一些變數//$datfile 的值為純真IP資料庫的名子,可自行修改.//*function ipLocation($datfile = "CoralWry.Dat"){ $this->fp=fopen($datfile,'rb')or die("CoralWry.Dat不存在,請去網上下載純真IP資料庫, 'CoralWry.dat' 放到目前的目錄下"); //二制方式開啟 $this->firstip = $this->get4b(); //第一條ip索引的絕對位移地址 $this->lastip = $this->get4b(); //最後一條ip索引的絕對位移地址 $this->totalip =($this->lastip - $this->firstip)/7 ; //ip總數 索引區是定長的7個位元組,在此要除以7, register_shutdown_function(array($this,"closefp")); //為了相容php5以下版本,本類沒有用解構函式,自動關閉ip庫.}//*//關閉ip庫//*function closefp(){fclose($this->fp);}//*//讀取4個位元組並將解壓成long的長模式//*function get4b(){ $str=unpack("V",fread($this->fp,4)); return $str[1];}//*//讀取重新導向了的位移地址//*function getoffset(){ $str=unpack("V",fread($this->fp,3).chr(0)); return $str[1];}//*//讀取ip的詳細地址資訊//*function getstr(){$str=""; $split=fread($this->fp,1); while (ord($split)!=0) { $str .=$split;$split=fread($this->fp,1); } return $str;}//*//將ip通過ip2long轉成ipv4的互連網地址,再將他壓縮成big-endian位元組序//用來和索引區內的ip地址做比較//*function iptoint($ip){ return pack("N",intval(ip2long($ip)));}//*//擷取用戶端ip地址//注意:如果你想要把ip記錄到伺服器上,請在寫庫時先檢查一下ip的資料是否安全.//*function getIP() { if (getenv('HTTP_CLIENT_IP')) {$ip = getenv('HTTP_CLIENT_IP'); }elseif (getenv('HTTP_X_FORWARDED_FOR')) { //擷取用戶端用Proxy 伺服器訪問時的真實ip 地址$ip = getenv('HTTP_X_FORWARDED_FOR');}elseif (getenv('HTTP_X_FORWARDED')) { $ip = getenv('HTTP_X_FORWARDED');}elseif (getenv('HTTP_FORWARDED_FOR')) {$ip = getenv('HTTP_FORWARDED_FOR'); }elseif (getenv('HTTP_FORWARDED')) {$ip = getenv('HTTP_FORWARDED');}else { $ip = $_SERVER['REMOTE_ADDR'];}return $ip;}//*//擷取地址資訊//*function readaddress(){ $now_offset=ftell($this->fp); //得到當前的指標位址 $flag=$this->getflag(); switch (ord($flag)){ case 0: $address=""; break; case 1: case 2: fseek($this->fp,$this->getoffset()); $address=$this->getstr(); break; default: fseek($this->fp,$now_offset); $address=$this->getstr(); break; } return $address;}//*//擷取標誌1或2//用來確定地址是否重新導向了.//*function getflag(){ return fread($this->fp,1);}//*//用二分尋找法在索引區內搜尋ip//*function searchip($ip){ $ip=gethostbyname($ip); //將網域名稱轉成ip $ip_offset["ip"]=$ip; $ip=$this->iptoint($ip); //將ip轉換成長整型 $firstip=0; //搜尋的上邊界 $lastip=$this->totalip; //搜尋的下邊界 $ipoffset=$this->lastip; //初始化為最後一條ip地址的位移地址 while ($firstip <= $lastip){ $i=floor(($firstip + $lastip) / 2); //計算近似中間記錄 floor函數記算給定浮點數小的最大整數,說白了就是四舍五也舍fseek($this->fp,$this->firstip + $i * 7); //定位指標到中間記錄$startip=strrev(fread($this->fp,4)); //讀取當前索引區內的開始ip地址,並將其little-endian的位元組序轉換成big-endian的位元組序if ($ip < $startip) { $lastip=$i - 1;}else { fseek($this->fp,$this->getoffset()); $endip=strrev(fread($this->fp,4)); if ($ip > $endip){ $firstip=$i + 1; } else { $ip_offset["offset"]=$this->firstip + $i * 7; break; }} } return $ip_offset;}//*//擷取ip地址詳細資料//*function getaddress($ip){ $ip_offset=$this->searchip($ip); //擷取ip 在索引區內的絕對編移地址 $ipoffset=$ip_offset["offset"]; $address["ip"]=$ip_offset["ip"]; fseek($this->fp,$ipoffset); //定位到索引區 $address["startip"]=long2ip($this->get4b()); //索引區內的開始ip 地址 $address_offset=$this->getoffset(); //擷取索引區內ip在ip記錄區內的位移地址 fseek($this->fp,$address_offset); //定位到記錄區內 $address["endip"]=long2ip($this->get4b()); //記錄區內的結束ip 地址 $flag=$this->getflag(); //讀取標誌位元組 switch (ord($flag)) { case 1: //地區1地區2都重新導向 $address_offset=$this->getoffset(); //讀取重新導向地址 fseek($this->fp,$address_offset); //定位指標到重新導向的地址 $flag=$this->getflag(); //讀取標誌位元組 switch (ord($flag)) { case 2: //地區1又一次重新導向,fseek($this->fp,$this->getoffset());$address["area1"]=$this->getstr();fseek($this->fp,$address_offset+4); //跳4個位元組$address["area2"]=$this->readaddress(); //地區2有可能重新導向,有可能沒有break;default: //地區1,地區2都沒有重新導向fseek($this->fp,$address_offset); //定位指標到重新導向的地址$address["area1"]=$this->getstr();$address["area2"]=$this->readaddress();break; } break; case 2: //地區1重新導向 地區2沒有重新導向 $address1_offset=$this->getoffset(); //讀取重新導向地址 fseek($this->fp,$address1_offset); $address["area1"]=$this->getstr(); fseek($this->fp,$address_offset+8); $address["area2"]=$this->readaddress(); break; default: //地區1地區2都沒有重新導向 fseek($this->fp,$address_offset+4); $address["area1"]=$this->getstr(); $address["area2"]=$this->readaddress(); break; } //*過濾一些無用資料 if (strpos($address["area1"],"CZ88.NET")!=false){ $address["area1"]="未知"; } if (strpos($address["area2"],"CZ88.NET")!=false){ $address["area2"]=" "; } return $address; }}
?
?
mapService類,方法類
?
?
/** * Google Map Service * 2011.4.8 */import("ORG.IPA.IpLocation");class mapService{public static function getIPaddress($ip){//返回格式$format = "text";//預設text,json,xml,js//返回編碼$charset = "utf8"; //預設utf-8,gbk或gb2312$ip_l=new IpLocation();$address=$ip_l->getaddress($ip);$address["area1"] = iconv('GB2312','utf-8',$address["area1"]);$address["area2"] = iconv('GB2312','utf-8',$address["area2"]);$add=$address["area1"].$address["area2"];if($add=="本機地址 "){$add="杭州";}return $add;}}
?
然後就可以在登陸的Action介面函數中調用兩個檔案類了:
?
?
import("ORG.IPA.MapService"); $ipaddress = get_client_ip();$adrInfo=MapService::getIPaddress($ipaddress);
?
?
接下去就可以將上述資訊記錄到資料庫中了,而在使用者進入地圖頁面便可以將資料從資料庫匯出,並發送到view層進行顯示,並在前端層調用Google Map API
?
後台控制層代碼很簡單:
?
?
public function map(){parent::islogin();$model = D("Topicview"); $list = $model->field('id,tid,imgid,avatar,address,create_time,topic_from,content,nickname,rootid,homepage') ->where("Topic.status=1 and Topic.type='first'") ->order("id desc")->find();//dump($list);$this->assign('addrList',$list);parent::showSiteInfo("Lab前端實驗室 - Map Position"); $this->display(); }
?
?
接下來是前台模板層js代碼:
?
?
if (typeof flowg == "undefined" || !flowg) { var flowg = {};}flowg.initMap = (function(){var htmlString = '' + '' + '' + '' + '' + '{$addrList.nickname} : {$addrList.content}' +'他在{$addrList.address}' + '' + ''; var geocoder; var map; var oldinfo = null; function initialize(){ geocoder = new google.maps.Geocoder(); var latlng = new google.maps.LatLng(34.016, 103.535); var myOptions = { zoom: 8, center: latlng, mapTypeId: google.maps.MapTypeId.ROADMAP }; map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); codeAddress("{$addrList.address}", htmlString); } function codeAddress(address, html){ geocoder.geocode({ 'address': address }, function(results, status){ if (status == google.maps.GeocoderStatus.OK) { map.setCenter(results[0].geometry.location); var marker = new google.maps.Marker({ map: map, position: results[0].geometry.location }); var contentString = html; var infowindow = new google.maps.InfoWindow({ content: contentString }); infowindow.open(map, marker); if (oldinfo != null) { oldinfo.close(); } oldinfo = infowindow; } else { return false; } }); } return initialize;})();$(flowg.initMap);
?
?
上面直接調用了google map的marker功能對於資訊進行展示,:
?