转自:http://www1.huachu.com.cn/read/readbookinfo.asp?sectionid=1000004203

第3章 实战Google Maps API之一——IP地理位置可视化查询

3.2 根据IP定位地理位置

 
 
 

在初步了解Google Maps API后,接下来就可以开始学习本章核心内容——根据IP定位地理位置。本节将初步介绍根据IP定位地理位置这项技术的背景,通过实例讲解如何利用MaxMind®提供的开源数据库查询某IP所在地理位置,并最终完成IP定位查询和Google地图的整合。

3.2.1  IP定位地理位置概述及准备工作

IP定位地理位置并不是一项很新的技术,从显示QQ用户的位置到站点统计,到处都有其应用。不过相对其发展潜力而言,目前的应用还是很不够的。例如广告方面,有地域针对性地投放是很有必要的,把北京某超市促销的广告显示给来自上海的用户看的收效是可想而知的。当然,这不是本书重点,不在深究,下面将介绍其基本原理及常用的IP地理位置数据库。

IP和地理位置的关系实际上比较简单,因为大量IP段是根据地域来分配的,这就为查询IP对应的地理位置带来了方便。此外,还有相当一部分IP是固定分配的,长期以来都不会改变,这就是著名的“纯真IP数据库甚至能定位到某些网吧”。必须承认,这种数据库不可能100%准确,因为存在大量IP是动态分配的,而且即使是固定IP也会出现变更而数据库来不及更新的情况。当然,即使无法100%地精确定位,IP定位地理位置技术依旧是很有意义的。

目前网络上中国人比较熟悉的就是纯真IP数据库了。不过和其他国产免费IP数据库一样,该IP库无法用于IP地理位置可视化查询系统。原因是该数据库只提供文本的地理位置信息,而并未提供相应的经纬度数据。比较流行的国外数据库有MaxMind®的GeoIP®数据库和IP2Location™的相应数据库。

因为MaxMind®除了发布商业授权的数据库外,还发布了GPL授权的免费GeoLiteCity数据库,并提供丰富的API支持,所以本章将以该数据库为基础进行详细介绍。

GPL发布的GeoLiteCity数据库下载地址为http://www. maxmind.com/download /geoip/database/。该数据库分为两个版本,一个为方便导入MySQL、Microsoft SQL Server等数据库的CSV数据库,另一个为二进制版的数据库。这里我们下载后者http://www. maxmind.com/download/geoip/database/GeoLiteCity.dat.gz,因为该版本官方提供查询API,且经过官方优化,效率更高。下载完成后用WinRAR等压缩工具解压为GeoLiteCity.dat即可。

除此之外需要的下载的有官方提供的API,见http://www.maxmind.com/app/php。本例中将使用免费的PHP版API,下载地址为http://www.maxmind.com/download/ geoip/api/php/,需要的文件为geoip.inc、geoipcity.inc和geoipregionvars.php。

将以上所有文件(包括GeoLiteCity数据库)放到网页服务器的同一目录(例如D:\www\geoip\),准备工作就完成了。

3.2.2  利用GeoIP®数据库及API进行地理定位查询

地理定位查询主要可分为两个步骤:第一,获取待查询的IP;第二,利用MaxMind® API进行查询并返回查询结果。本例中数据比较简单,因此可以把查询结果直接以Javascript字符串的形式返回给客户端,用eval调用即可。下面将详细介绍上述步骤。

1.获取待查询的IP

首先,在文件开始的部分引入MaxMind® API的库文件。

<?php

//导入库文件

include("geoipcity.inc");

include("geoipregionvars.php")

?>

如果未传递任何参数,则使用当前访客的IP,如此就可以在加载的时候使用显示当前访客的信息了。代码如下。

//接上面程序

//获取客户端IP的函数

function getClientIP()

{

if (isset($HTTP_SERVER_VARS["HTTP_X_FORWARDED_FOR"]))

{

$ip = $HTTP_SERVER_VARS["HTTP_X_FORWARDED_FOR"];

}

elseif (isset($HTTP_SERVER_VARS["HTTP_CLIENT_IP"]))

{

$ip = $HTTP_SERVER_VARS["HTTP_CLIENT_IP"];

}

elseif (isset($HTTP_SERVER_VARS["REMOTE_ADDR"]))

{

$ip = $HTTP_SERVER_VARS["REMOTE_ADDR"];

}

elseif (getenv("HTTP_X_FORWARDED_FOR"))

{

$ip = getenv("HTTP_X_FORWARDED_FOR");

}

elseif (getenv("HTTP_CLIENT_IP"))

{

$ip = getenv("HTTP_CLIENT_IP");

}

elseif (getenv("REMOTE_ADDR"))

{

$ip = getenv("REMOTE_ADDR");

}

else

{

$ip = false;

}

return $ip;

}

//如果传递的查询参数为空

if(empty($_GET['q']))

{

$ip = getClientIP();

if (!isset($ip))

{

echo 'alert("Cannot get your IP address!");';

die();

}

}

如果有参数传递,则判断是否为IP或域名信息。如果都不是,报错,终止查询。代码如下。

//接上面程序

//如果传递的查询参数不为空

else

{    //探测字符串是否为IP的正则表达式

$pattern
=
"/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/";

if(preg_match($pattern, $_GET['q']))          //如果查询的信息为IP

{

$ip = $_GET['q'];

}

else     //如果查询的信息为域名

{

$ip = gethostbyname($_GET['q']);       //若域名查询成功,则返回的字符串为IP

if(!preg_match($pattern, $ip))            //检测是否返回IP,若未返回IP,即域名查询失败,报错

{

echo 'alert("Invalid Input!"); ';

die();

}

}

}

经过以上一系列处理,就可以从参数中获取真实的IP用于查询了。

2.通过IP获取地理信息

利用MaxMind®取得某IP的地理信息是相对容易的,查询的结果是一个结构体,包含国家代码、国家名称、城市名称和城市经纬度等信息。下面对其中元素进行一一说明。

—    country_code – 国家代码(两位),如中国为CN。

—    country_code3 – 国家代码(三位),如中国为CHN。

—    country_name – 国家名称(英文),如中国为China。

—    region – 区域代码,通过$GEOIP_REGION_NAME[$record->country_code] [$record->region]可获得区域的名称。对于中国,region得到的是省级行政区的名称,如$GEOIP_REGION_NAME["CN"]["01"]对应的行政区即位Anhui(安徽)。

—    city – 城市名称。

—    postal_code – 邮编,仅美国可用。

—    latitude – 纬度。

—    longitude – 经度。

—    dma_code – DMA代码,仅美国可用。

—    area_code – 地区代码,仅美国可用。

了解数据的组织结构后就可以方便地使用其中的数据了。代码如下:

//接上面程序

//如果取消下一行将使用共享内存打开GeoLiteCity数据库,可加快查询。但前提是服务器支持共享内存

//$gi = geoip_open("./GeoLiteCity.dat",GEOIP_MEMORY_CACHE);

//以常规方式打开GeoLiteCity数据库,一般情况下都可以使用

$gi = geoip_open("./GeoLiteCity.dat",GEOIP_STANDARD);

//以上是假定GeoLiteCity数据库和PHP文件在同一个目录,故使用"./GeoLiteCity.dat"为路径

//如果不是,请改为实际目录

//获取IP的信息

$record = geoip_record_by_addr($gi, $ip);

//关闭数据库

geoip_close($gi);

//如果获取了相关数据

if($record)

{

echo 'loadGeoInfo('.

'"'.   $_GET['q']   .'",'.              //原始查询信息

'"'.   $ip   .'",'.                 //被查IP

'"'.   $record->country_code   .'",'. //国家代码(两位)

'"'.   $record->country_code3  .'",'. //国家代码(三位)

'"'.   $record->country_name   .'",'. //国家名称

'"'.   $GEOIP_REGION_NAME[$record->country_code] [$record->region]   .'",'.                          //地区名称

'"'.   $record->city   .'",'.        //城市名称

$record->latitude   .','.           //纬度

$record->longitude   .')';              //经度

//如果数据库中不存在相关数据

else

{

echo 'alert("The Information for '.$ip.' is not available now!"); ';

}

?>

将以上代码整合到一起,保存为search.php,放到本程序的主目录中(search.php完整代码在光盘中本章节目录里可以找到)。

在浏览器中输入http://服务器地址/程序所在路径/search.php?q=google.com,应该会显示与下面信息类似的输出结果。

loadGeoInfo("google.com", "64.233.187.99", "US", "USA", "United States", "California", "Mountain View", 37.4192,-122.0574)

而输入http://服务器地址/程序所在路径/search.php?q=202.114.64.139,则输出应该和下面类似。

loadGeoInfo("202.114.64.139", "202.114.64.139", "CN", "CHN", "China", "Hubei", "Wuhan" ,30.5833, 114.2667)

3.2.3  在Google地图上显示查询结果

上一节中,服务器端程序已经可以正常返回查询结果。本节将介绍如何从服务器取得该结果并显示在地图上。这一过程主要分为三个步骤:第一,需要获取服务器端的查询结果;第二,实现loadGeoInfo()接口;第三,显示查询结果等其他工作。

1.获取服务器端的查询结果

本程序将使用流行的AJAX技术取得查询结果,一方面减少了流量,另一方面由于加载速度快,还可以增强用户体验。当然Google Maps API在这里也提供了相当便捷的使用AJAX的方法,完全没有必要使用其他AJAX的应用程序框架。在Google Maps API中,异步调用有两种方法,一种是使用GXmlHttp对象,另一种是使用GDownloadUrl()函数。

(1)使用GXmlHttp对象

创建GXmlHttp对象使用AJAX和直接创建XmlHttpRequest对象基本没有区别,使用十分灵活。由于Google封装时已经考虑到了浏览器的兼容性,所以GXmlHttp相对普通XmlHttpRequest的优势在于可以直接在不同浏览器上直接使用。目前GXmlHttp不仅可以支持Internet Explorer、Firefox和Opera等流行的浏览器,在Safari、Konquorer等用户群比较少的浏览器上都可以得到比较好的支持。下面仅给出一段模版形式的代码以供参考。

//创建GXmlHttp对象

var request = GXmlHttp.create();

//打开GXmlHttp,这里可以设置的参数有三个

//第一个参数:获取方法,判断是使用GET方法还是POST方法

//第二个参数:需获取的文件名

//第三个参数:获取模式,异步为真,同步为假

request.open("GET", "myfile.txt", true);

//回调函数,可以用function(){…}直接在此调用

//也可以预先定义函数XXX(),在此赋值 request.onreadystatechange=XXX

request.onreadystatechange = function()

{

//判断状态,可根据不同的状态做不同的响应,本例中只捕捉了完全加载的状态4

if (request.readyState == 4)

{

alert(request.responseText);

}

}

//发送信息

request.send(null);

(2)使用GDownloadUrl()函数

GDownloadUrl()函数应该说是一个简化版的异步处理函数,只能使用GET方法,不判断加载状态,只是在完全加载后调用回调函数。虽然GDownloadUrl()函数功能有限,但是因为其使用非常简单,所以应用也相当广泛。GDownloadUrl()调用方法如下。

GDownloadUrl(url, onload)

第一个参数即为需要用GET方法获取的URL,第二个参数onload是完全加载后的回调函数。

在本例IP地理位置可视化查询中,GDownloadUrl()已经完全符合要求,故在此使用GDownloadUrl()函数。获取服务器数据的函数getGeoInfo()如下。

function getGeoInfo(q)

{

//q为待查信息

GDownloadUrl("search.php?q="+q, function(data)

{

//直接用eval执行返回的Javascript字符串

eval(data);

});

}

2.实现loadGeoInfo()接口

loadGeoInfo()接口需要实现在Google地图上定位目标IP,添加信息窗口显示其详细信息等功能。在此仅给出接口部分的代码,如有疑问,请回顾本章上一节的内容。

function loadGeoInfo(q, ip, country_code, country_code3, country, region, city, latitude, longitude)

{

//新的信息窗口中的内容

var info = "<div align=\"left\" style=\"overflow:X; font-size:12px\">"

+ "<span style=\"font-size:14px\"><strong>" + q + "</strong></span><br />"

+ "<strong>IP:</strong> &nbsp;" + ip + "<br />"

+ "<strong>国家:</strong> &nbsp;" + country + "<br />"

+ "<strong>代码:</strong> &nbsp;" + country_code + "(" + country_code3 + ")" + "<br />"

+ "<strong>省份:</strong> &nbsp;" + city + "<br />"

+ "<strong>城市:</strong> &nbsp;" + region + "<br />"

+ "<strong>经度:</strong> &nbsp;" + longitude + "<br />"

+ "<strong>纬度:</strong> &nbsp;" + latitude + "<br />"

+ "</div>";

//移动地图中心到新的位置

var point = new GLatLng(latitude, longitude);

map.panTo(point);

//如果创建了marker地标,则关闭当前的信息窗口并移除地标

if(marker)

{

map.closeInfoWindow();

map.removeOverlay(marker);

}

//创建新的地标

marker = new GMarker(point);

map.addOverlay(marker);

//显示信息窗口

marker.openInfoWindowHtml(info);

}

最后为网页设计好LOGO,添加相应的事件响应(如搜索按钮单击,搜索栏回车等)就可以使用了。完整的首页index.html代码如下。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<meta http-equiv="content-type" content="text/html; charset=utf-8"/>

<title>GeoIP 搜索者</title>

<!--导入Google Maps API库文件。注意将本代码中的API Key替换为前文申请到的API Key-->

<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=ABQIAAAA1- j86tnUDFv8OAt C8dZVtKRT2yXp_ZAY8_ufC3CFXhHIE1NvwkxSzmwrQ90SNUILzGRpsBiaa860gfQ" type="text/javascript"></script>

<script type="text/javascript">

//<![CDATA[

var map;     //全局GMap2对象

var marker;  //用于标识查询IP的GMarker地标

//初始化

function load()

{

if (GBrowserIsCompatible())

{

map = new GMap2(document.getElementById("map"));

map.setCenter(new GLatLng(39.92, 116.46), 2);

//添加相应GControl()控件

map.addControl(new GSmallMapControl());

map.addControl(new GMapTypeControl());

//设定地图类型为混合地图

map.setMapType(G_HYBRID_MAP);

//查询当前访客信息

getGeoInfo("");

}

}

//响应查询栏的回车

//因为FireFox中event不是全局的,所以必须从相应DOM对象里传回event

//如下写法可兼容IE和Firefox

function pressEnter(event, q)

{

//如果输入了回车,则执行查询

if(event.keyCode==13 || event.keyCode==10)

{

getGeoInfo(q);

}

}

//查询函数

function getGeoInfo(q)

{

GDownloadUrl("search.php?q="+q, function(data)

{

eval(data);

});

}

//服务器端数据调用接口

function loadGeoInfo(q, ip, country_code, country_code3, country, region, city, latitude, longitude)

{

//新的信息窗口中的内容

var info = "<div align=\"left\" style=\"overflow:X; font-size:12px\">"

+ "<span style=\"font-size:14px\"><strong>" + q + "</strong></span><br />"

+ "<strong>IP:</strong> &nbsp;" + ip + "<br />"

+ "<strong>国家:</strong> &nbsp;" + country + "<br />"

+ "<strong>代码:</strong> &nbsp;" + country_code + "(" + country_code3 + ")" + "<br />"

+ "<strong>省份:</strong> &nbsp;" + city + "<br />"

+ "<strong>城市:</strong> &nbsp;" + region + "<br />"

+ "<strong>经度:</strong> &nbsp;" + longitude + "<br />"

+ "<strong>纬度:</strong> &nbsp;" + latitude + "<br />"

+ "</div>";

//移动地图中心到新的位置

var point = new GLatLng(latitude, longitude);

map.panTo(point);

//如果创建了marker地标,则关闭当前的信息窗口并移除地标

if(marker)

{

map.closeInfoWindow();

map.removeOverlay(marker);

}

//创建新的地标

marker = new GMarker(point);

map.addOverlay(marker);

//显示信息窗口

marker.openInfoWindowHtml(info);

}

//]]>

</script>

<style>

td{

text-align:center;

}

</style>

</head>

<body onload="load()" onunload="GUnload()">

<table cellSpacing="0" cellPadding="0" width="600" border="0"  align="center">

<tbody>

<tr>

<td>

<img src="geoipseeker.jpg" title="geoipseeker" alt="geoipseeker" width="450" height="50" style="boder:0" />

<td>

</tr>

<tr>

<td height="25">

<!--此处onsubmit为"return false;"可防止表单提交,因为本例中用AJAX查询,无须提交表单-->

<form onsubmit="return false;">

<!--分别为输入框和按钮都添加了事件监听。回车和点击按钮都可以进行查询-->

<label for="q">在此输入IP或域名<input maxLength="50" size="25" name="q" id="q" onkeypress="pressEnter(event, this.value); "  />

<input type="button" value="查找" id="search" onclick="getGeoInfo(q. value)" /></label>

</form>

</td>

</tr>

<tr>

<td height="20" id="info"></td>

</tr>

<tr>

<td>

<div id="map" style="width:580px;height:350px"></div>

</td>

</tr>

<tr>

<td height="20" id="link">

<a href="http://blog.gmap2.net">Power by <strong>GMap2.net</strong></a>

</td>

</tr>

</tbody>

</table>

</body>

</html>

效果如图3.12所示。在此只讨论Google Maps API技术,没有对界面做过多设计,有兴趣的读者可自行设计一下界面。

图3.12  根据IP定位地理位置

Google Maps-IP地址的可视化查询的更多相关文章

  1. google全球ip地址库

    当我们为不能使用google搜索业务时,这里有全球的google ip库,能够使用当中任一个来利用google搜索 https://github.com/justjavac/Google-IPs ht ...

  2. [分享]Google 全球 IP 地址库[Google Global Cache IPs]

    Google 全球 IP 地址库 IP 地址来源:http://www.kookle.co.nr,共计4351个. Bulgaria 93.123.23.1 93.123.23.2 93.123.23 ...

  3. Google 全球 IP 地址库

    ## Google 全球 IP 地址库 IP 地址来源:http://www.kookle.co.nr Bulgaria 93.123.23.1 93.123.23.2 93.123.23.3 93. ...

  4. 大规模IP地址黑名单高性能查询实现

    嗯……前阵子接了个活儿,需要做一个基于IP地址黑名单的分流网关.刚接到的时候心想iptables不就行了么,没想到一看客户给的IP黑名单规模……我擦……上亿个…… 黑名单到了这个规模,就不得不考虑下优 ...

  5. Python实现IP地址归属地查询

    一.使用淘宝IP地址库查询 使用淘宝的Rest API,可以快速查询IP地址的归属地: 图00-淘宝IP地址库RestAPI使用说明 图01-使用淘宝免费IP地址库-查询IP归属地 存在问题:淘宝的免 ...

  6. [转]Google 全球 IP 地址库

    IP 地址来源:http://www.kookle.co.nr Bulgaria 93.123.23.1 93.123.23.2 93.123.23.3 93.123.23.4 93.123.23.5 ...

  7. IP地址归属地查询

    http://www.ipip.net/download.html#ip_code 下载免费版 IP 地址数据库. 网站下面有官方给出的查找IP地址所属国家.省.市的办法. python版本列出 py ...

  8. Google的IP地址一览表,加上代理服务器

    Bulgaria 93.123.23.1 93.123.23.2 93.123.23.3 93.123.23.4 93.123.23.5 93.123.23.6 93.123.23.7 93.123. ...

  9. 手机归属地查询-IP地址查询-身份证查询-域名备案查询--Api接口

    使用这些接口是需要密钥的 公共密钥 appkey: 10003  secret: d1149a30182aa2088ef645309ea193bf  生成后sign: b59bc3ef6191eb9f ...

随机推荐

  1. C# winIO32位,64位的使用(运行时要用管理员身份)

    下载地址: http://www.internals.com/utilities/WinIo.zip 一个按键的消息产生流程如下: 1)硬件中断/硬件端口数据 WinIO能模拟,或者修改IDT是在这一 ...

  2. python面向对象-2深入类的属性

    在交互式环境中输入: >>> class A: a=0 def __init__(self): self.a=10 self.b=100 >>> a=A() > ...

  3. python nan 变成0

    在使用numpy数组的过程中时常会出现nan或者inf的元素,可能会造成数值计算时的一些错误.这里提供一个numpy库函数的用法,使nan和inf能够最简单地转换成相应的数值. numpy.nan_t ...

  4. DIV+CSS实战(三)

    一.说明 在上篇博客<DIV+CSS实战(二)>中,实现了头部以及Tab标签卡,下面开始实现内容区域,要实现的效果如下: 二.内容最外层的设计(边框) 给最外层加边框,并且设置高度随着里面 ...

  5. 201709021工作日记--CAS解读

    CAS主要参考博文:classtag  http://www.jianshu.com/p/473e14d5ab2d CAS(Compare and swap)比较和替换是设计并发算法时用到的一种技术 ...

  6. PO Release Final Closed 灾难恢复

    今天不小心 Final Closed了一条Po Release,只能通过后台更新数据恢复了. 更新后可接收可匹配,但不保证更新数据有遗漏,慎用. 更新前备份各表数据 UPDATE PO_LINE_LO ...

  7. Android-Android版美图秀秀

    Android版美图秀秀,主要是修改图片的显示效果,修改图片的透明的显示范围,修改图片的红色显示范围,修改图片绿色显示范围,修改图片蓝色显示范围: 想要修改图片的颜色就必须要重新绘制,一想到重新绘制就 ...

  8. Android Studio 集成 TFS,实现安卓移动开发的持续集成和交付(DevOps)

    目录 1 集成TFS系统.... 1.1 概述.... 1.2 安装TFS插件.... 1.2.1 在线安装方式.... 1.2.2 离线安装方案.... 1.3 常见操作.... 1.3.1 新建G ...

  9. HttpWebRequest 模拟浏览器访问网站

    最近抓网页时报错: 要么返回 The remote server returned an error: (442)要么返回: 非法访问,您的行为已被WAF系统记录! 想了想,就当是人家加了抓网页的东西 ...

  10. .net core An assembly specified in the application dependencied mainfest<****.json>was not found解决办法

    最近在开发项目中,遇到了一个问题.在本机开发中部署到本机iis上或者本机控制台都没有问题,运行正常.当发布部署到服务器(windowsServer)中的时候一直运行不起来,用控制台也运行不起来,直接报 ...