我想从他们的 IP 地址中检索访问者的城市、州和国家等信息,以便我可以根据他们的位置自定义我的网页。在 PHP 中有没有好的可靠的方法来做到这一点?我使用 JavaScript 编写客户端脚本,使用 PHP 编写服务器端脚本,使用 MySQL 编写数据库。
20 回答
您可以下载免费的 GeoIP 数据库并在本地查找 IP 地址,或者您可以使用第三方服务并执行远程查找。这是更简单的选项,因为它不需要设置,但它确实会引入额外的延迟。
您可以使用的一项第三方服务是我的http://ipinfo.io。它们提供主机名、地理位置、网络所有者和其他信息,例如:
$ curl ipinfo.io/8.8.8.8
{
"ip": "8.8.8.8",
"hostname": "google-public-dns-a.google.com",
"loc": "37.385999999999996,-122.0838",
"org": "AS15169 Google Inc.",
"city": "Mountain View",
"region": "CA",
"country": "US",
"phone": 650
}
这是一个 PHP 示例:
$ip = $_SERVER['REMOTE_ADDR'];
$details = json_decode(file_get_contents("http://ipinfo.io/{$ip}/json"));
echo $details->city; // -> "Mountain View"
您也可以在客户端使用它。这是一个简单的 jQuery 示例:
$.get("https://ipinfo.io/json", function (response) {
$("#ip").html("IP: " + response.ip);
$("#address").html("Location: " + response.city + ", " + response.region);
$("#details").html(JSON.stringify(response, null, 4));
}, "jsonp");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<h3>Client side IP geolocation using <a href="http://ipinfo.io">ipinfo.io</a></h3>
<hr/>
<div id="ip"></div>
<div id="address"></div>
<hr/>Full response: <pre id="details"></pre>
以为我会发布,因为似乎没有人提供有关此特定 API 的信息,但它返回的正是我所追求的,你可以让它以多种格式返回,json, xml and csv
.
$location = file_get_contents('http://freegeoip.net/json/'.$_SERVER['REMOTE_ADDR']);
print_r($location);
这将为您提供您可能想要的所有东西:
{
"ip": "77.99.179.98",
"country_code": "GB",
"country_name": "United Kingdom",
"region_code": "H9",
"region_name": "London, City of",
"city": "London",
"zipcode": "",
"latitude": 51.5142,
"longitude": -0.0931,
"metro_code": "",
"areacode": ""
}
一个纯 Javascript 示例,使用https://geolocation-db.com的服务,它们提供 JSON 和 JSONP 回调解决方案。
不需要 jQuery!
<!DOCTYPE html>
<html>
<head>
<title>Geo City Locator by geolocation-db.com</title>
</head>
<body>
<div>Country: <span id="country"></span></div>
<div>State: <span id="state"></span></div>
<div>City: <span id="city"></span></div>
<div>Postal: <span id="postal"></span></div>
<div>Latitude: <span id="latitude"></span></div>
<div>Longitude: <span id="longitude"></span></div>
<div>IP address: <span id="ipv4"></span></div>
</body>
<script>
var country = document.getElementById('country');
var state = document.getElementById('state');
var city = document.getElementById('city');
var postal = document.getElementById('postal');
var latitude = document.getElementById('latitude');
var longitude = document.getElementById('longitude');
var ip = document.getElementById('ipv4');
function callback(data)
{
country.innerHTML = data.country_name;
state.innerHTML = data.state;
city.innerHTML = data.city;
postal.innerHTML = data.postal;
latitude.innerHTML = data.latitude;
longitude.innerHTML = data.longitude;
ip.innerHTML = data.IPv4;
}
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://geoilocation-db.com/json/geoip.php?jsonp=callback';
var h = document.getElementsByTagName('script')[0];
h.parentNode.insertBefore(script, h);
</script>
</html>
使用谷歌 APIS:
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script>
contry_code = google.loader.ClientLocation.address.country_code
city = google.loader.ClientLocation.address.city
region = google.loader.ClientLocation.address.region
</script>
您需要使用外部服务...例如http://www.hostip.info/如果您在 Google 上搜索“geo-ip”,您可以获得更多结果。
Host-IP API 基于 HTTP,因此您可以根据需要在 PHP 或 JavaScript 中使用它。
我使用来自ipapi.co的 API 编写了一个机器人,以下是获取 IP 地址(例如1.2.3.4
)位置的方法php
:
设置标题:
$opts = array('http'=>array('method'=>"GET", 'header'=>"User-Agent: mybot.v0.7.1"));
$context = stream_context_create($opts);
获取 JSON 响应
echo file_get_contents('https://ipapi.co/1.2.3.4/json/', false, $context);
获取特定字段(国家、时区等)
echo file_get_contents('https://ipapi.co/1.2.3.4/country/', false, $context);
这个问题是受保护的,我理解。但是,我在这里没有看到答案,我看到的是很多人展示了他们从同样的问题中得出的结论。
目前有五个具有不同程度功能的区域互联网注册管理机构作为知识产权所有权方面的第一联络点。这个过程是不断变化的,这就是为什么这里的各种服务有时工作而有时不工作的原因。
然而,Who Is(显然)是一个古老的 TCP 协议——它最初的工作方式是连接到端口 43,这使得通过租用连接、防火墙等进行路由变得有问题。
目前——大部分 Who Is 是通过 RESTful HTTP 和 ARIN、RIPE 和 APNIC 完成的 RESTful 服务。LACNIC 返回 503 而 AfriNIC 显然没有这样的 API。(不过,它们都有在线服务。)
这会给你——IP 的注册所有者的地址,但——不是你客户的位置——你必须从他们那里得到它,而且——你必须要求它。此外,在验证您认为是发起者的 IP 时,代理是您最不必担心的问题。
人们不喜欢他们被跟踪的想法,所以——我的想法是——直接从你的客户那里得到他们的许可,并期待很多人对这个想法犹豫不决。
Ben Dowling 响应中的服务已更改,因此现在更简单了。要查找位置,只需执行以下操作:
// no need to pass ip any longer; ipinfo grabs the ip of the person requesting
$details = json_decode(file_get_contents("http://ipinfo.io/"));
echo $details->city; // city
坐标以单个字符串形式返回,例如 '31,-80',因此您只需:
$coordinates = explode(",", $details->loc); // -> '31,-89' becomes'31','-80'
echo $coordinates[0]; // latitude
echo $coordinates[1]; // longitude
查看 hostip.info 中的 API - 它提供了大量信息。
PHP 中的示例:
$data = file_get_contents("http://api.hostip.info/country.php?ip=12.215.42.19");
//$data contains: "US"
$data = file_get_contents("http://api.hostip.info/?ip=12.215.42.19");
//$data contains: XML with country, lat, long, city, etc...
如果您信任 hostip.info,它似乎是一个非常有用的 API。
我喜欢 Maxmind 的免费GeoLite City,它适用于大多数应用程序,如果不够精确,您可以从中升级到付费版本。包括一个PHP API,以及其他语言。如果您将 Lighttpd 作为网络服务器运行,您甚至可以使用一个模块来获取每个访问者的 SERVER 变量中的信息(如果这是您需要的话)。
我应该补充一下,还有一个免费的Geolite Country(如果您不需要查明 IP 来自的城市会更快)和 Geolite ASN(如果您想知道谁拥有 IP),最后所有这些都是可在您自己的服务器上下载,每月更新一次,并且使用提供的 API 可以快速查找,因为它们声明“每秒可进行数千次查找”。
我在IPLocate.io运行该服务,您可以通过一个简单的电话免费连接:
<?php
$res = file_get_contents('https://www.iplocate.io/api/lookup/8.8.8.8');
$res = json_decode($res);
echo $res->country; // United States
echo $res->continent; // North America
echo $res->latitude; // 37.751
echo $res->longitude; // -97.822
var_dump($res);
该$res
对象将包含您的地理位置字段,如country
,city
等。
查看文档以获取更多信息。
假设您想自己做而不依赖其他提供商,IP2Nation提供了一个映射的 MySQL 数据库,该数据库会随着区域注册机构的变化而更新。
PHP 对此有一个扩展。
来自 PHP.net:
GeoIP 扩展允许您查找 IP 地址的位置。城市、州、国家、经度、纬度和其他信息,如 ISP 和连接类型都可以在 GeoIP 的帮助下获得。
例如:
$record = geoip_record_by_name($ip);
echo $record['city'];
Ipdata.co是一个快速、高度可用的 IP 地理定位 API,具有可靠的性能。
它具有极强的可扩展性,全球有 10 个端点,每个端点每秒能够处理超过 10,000 个请求!
此答案使用非常有限的“测试”API 密钥,仅用于测试几个调用。注册您自己的免费 API 密钥并每天收到多达 1500 个开发请求。
在php中
php > $ip = '8.8.8.8';
php > $details = json_decode(file_get_contents("https://api.ipdata.co/{$ip}?api-key=test"));
php > echo $details->region;
California
php > echo $details->city;
Mountain View
php > echo $details->country_name;
United States
php > echo $details->latitude;
37.751
这是一个客户端示例,展示了如何获取国家、地区和城市;
$.get("https://api.ipdata.co?api-key=test", function (response) {
$("#response").html(JSON.stringify(response, null, 4));
$("#country").html('Country: ' + response.country_name);
$("#region").html('Region ' + response.region);
$("#city").html('City' + response.city);
}, "jsonp");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="country"></div>
<div id="region"></div>
<div id="city"></div>
<pre id="response"></pre>
免责声明;
我建立了服务。
有关多种语言的示例,请参阅文档
另请参阅对最佳 IP 地理定位 API的详细分析。
万一有人偶然发现了这个线程,这里有另一个解决方案。在timezoneapi.io,您可以请求一个 IP 地址并获得几个对象作为回报(我已经创建了该服务)。创建它是因为我需要知道我的用户在哪个时区、世界上的哪个地方以及现在是什么时间。
在 PHP 中 - 返回位置、时区和日期/时间:
// Get IP address
$ip_address = getenv('HTTP_CLIENT_IP') ?: getenv('HTTP_X_FORWARDED_FOR') ?: getenv('HTTP_X_FORWARDED') ?: getenv('HTTP_FORWARDED_FOR') ?: getenv('HTTP_FORWARDED') ?: getenv('REMOTE_ADDR');
// Get JSON object
$jsondata = file_get_contents("http://timezoneapi.io/api/ip/?" . $ip_address);
// Decode
$data = json_decode($jsondata, true);
// Request OK?
if($data['meta']['code'] == '200'){
// Example: Get the city parameter
echo "City: " . $data['data']['city'] . "<br>";
// Example: Get the users time
echo "Time: " . $data['data']['datetime']['date_time_txt'] . "<br>";
}
使用 jQuery:
// Get JSON object
$.getJSON('https://timezoneapi.io/api/ip', function(data){
// Request OK?
if(data.meta.code == '200'){
// Log
console.log(data);
// Example: Get the city parameter
var city = data.data.city;
alert(city);
// Example: Get the users time
var time = data.data.datetime.date_time_txt;
alert(time);
}
});
如果您需要从 IP 地址获取位置,您可以使用可靠的地理 ip 服务,您可以在此处获取更多详细信息。它支持 IPv6。
作为奖励,它允许检查 ip 地址是否是 tor 节点、公共代理或垃圾邮件发送者。
您可以使用 javascript 或 php,如下所示。
Javascript代码:
$(document).ready(function () {
$('#btnGetIpDetail').click(function () {
if ($('#txtIP').val() == '') {
alert('IP address is reqired');
return false;
}
$.getJSON("http://ip-api.io/json/" + $('#txtIP').val(),
function (result) {
alert('City Name: ' + result.city)
console.log(result);
});
});
});
php代码:
$result = json_decode(file_get_contents('http://ip-api.io/json/64.30.228.118'));
var_dump($result);
输出:
{
"ip": "64.30.228.118",
"country_code": "US",
"country_name": "United States",
"region_code": "FL",
"region_name": "Florida",
"city": "Fort Lauderdale",
"zip_code": "33309",
"time_zone": "America/New_York",
"latitude": 26.1882,
"longitude": -80.1711,
"metro_code": 528,
"suspicious_factors": {
"is_proxy": false,
"is_tor_node": false,
"is_spam": false,
"is_suspicious": false
}
以下是我发现的一个片段的修改版本,它使用http://ipinfodb.com/ip_locator.php来获取其信息。请记住,您也可以向他们申请 API 密钥并直接使用 API 来获取您认为合适的信息。
片段
function detect_location($ip=NULL, $asArray=FALSE) {
if (empty($ip)) {
if (!empty($_SERVER['HTTP_CLIENT_IP'])) { $ip = $_SERVER['HTTP_CLIENT_IP']; }
elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; }
else { $ip = $_SERVER['REMOTE_ADDR']; }
}
elseif (!is_string($ip) || strlen($ip) < 1 || $ip == '127.0.0.1' || $ip == 'localhost') {
$ip = '8.8.8.8';
}
$url = 'http://ipinfodb.com/ip_locator.php?ip=' . urlencode($ip);
$i = 0; $content; $curl_info;
while (empty($content) && $i < 5) {
$ch = curl_init();
$curl_opt = array(
CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_HEADER => 0,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => $url,
CURLOPT_TIMEOUT => 1,
CURLOPT_REFERER => 'http://' . $_SERVER['HTTP_HOST'],
);
if (isset($_SERVER['HTTP_USER_AGENT'])) $curl_opt[CURLOPT_USERAGENT] = $_SERVER['HTTP_USER_AGENT'];
curl_setopt_array($ch, $curl_opt);
$content = curl_exec($ch);
if (!is_null($curl_info)) $curl_info = curl_getinfo($ch);
curl_close($ch);
}
$araResp = array();
if (preg_match('{<li>City : ([^<]*)</li>}i', $content, $regs)) $araResp['city'] = trim($regs[1]);
if (preg_match('{<li>State/Province : ([^<]*)</li>}i', $content, $regs)) $araResp['state'] = trim($regs[1]);
if (preg_match('{<li>Country : ([^<]*)}i', $content, $regs)) $araResp['country'] = trim($regs[1]);
if (preg_match('{<li>Zip or postal code : ([^<]*)</li>}i', $content, $regs)) $araResp['zip'] = trim($regs[1]);
if (preg_match('{<li>Latitude : ([^<]*)</li>}i', $content, $regs)) $araResp['latitude'] = trim($regs[1]);
if (preg_match('{<li>Longitude : ([^<]*)</li>}i', $content, $regs)) $araResp['longitude'] = trim($regs[1]);
if (preg_match('{<li>Timezone : ([^<]*)</li>}i', $content, $regs)) $araResp['timezone'] = trim($regs[1]);
if (preg_match('{<li>Hostname : ([^<]*)</li>}i', $content, $regs)) $araResp['hostname'] = trim($regs[1]);
$strResp = ($araResp['city'] != '' && $araResp['state'] != '') ? ($araResp['city'] . ', ' . $araResp['state']) : 'UNKNOWN';
return $asArray ? $araResp : $strResp;
}
使用
detect_location();
// returns "CITY, STATE" based on user IP
detect_location('xxx.xxx.xxx.xxx');
// returns "CITY, STATE" based on IP you provide
detect_location(NULL, TRUE); // based on user IP
// returns array(8) { ["city"] => "CITY", ["state"] => "STATE", ["country"] => "US", ["zip"] => "xxxxx", ["latitude"] => "xx.xxxxxx", ["longitude"] => "-xx.xxxxxx", ["timezone"] => "-07:00", ["hostname"] => "xx-xx-xx-xx.host.name.net" }
detect_location('xxx.xxx.xxx.xxx', TRUE); // based on IP you provide
// returns array(8) { ["city"] => "CITY", ["state"] => "STATE", ["country"] => "US", ["zip"] => "xxxxx", ["latitude"] => "xx.xxxxxx", ["longitude"] => "-xx.xxxxxx", ["timezone"] => "-07:00", ["hostname"] => "xx-xx-xx-xx.host.name.net" }
您还可以使用“智能 IP”服务:
$.getJSON("http://smart-ip.net/geoip-json?callback=?",
function (data) {
alert(data.countryName);
alert(data.city);
}
);
我已经对 IP 地址服务进行了大量测试,这里有一些我自己做的方法。首先是我使用的一些有用网站的链接:
https://db-ip.com/db 有免费的 ip-lookup 服务,还有一些免费的 csv 文件可以下载。这使用附加到您的电子邮件的免费 api 密钥。它限制在每天 2000 个查询。
http://ipinfo.io/ 没有 api-key PHP 功能的免费 ip-lookup 服务:
//uses http://ipinfo.io/.
function ip_visitor_country($ip){
$ip_data_in = get_web_page("http://ipinfo.io/".$ip."/json"); //add the ip to the url and retrieve the json data
$ip_data = json_decode($ip_data_in['content'],true); //json_decode it for php use
//this ip-lookup service returns 404 if the ip is invalid/not found so return false if this is the case.
if(empty($ip_data) || $ip_data_in['httpcode'] == 404){
return false;
}else{
return $ip_data;
}
}
function get_web_page($url){
$user_agent = 'Mozilla/5.0 (Windows NT 6.1; rv:8.0) Gecko/20100101 Firefox/8.0';
$options = array(
CURLOPT_CUSTOMREQUEST =>"GET", //set request type post or get
CURLOPT_POST =>false, //set to GET
CURLOPT_USERAGENT => $user_agent, //set user agent
CURLOPT_RETURNTRANSFER => true, // return web page
CURLOPT_HEADER => false, // don't return headers
CURLOPT_FOLLOWLOCATION => true, // follow redirects
CURLOPT_ENCODING => "", // handle all encodings
CURLOPT_AUTOREFERER => true, // set referer on redirect
CURLOPT_CONNECTTIMEOUT => 120, // timeout on connect
CURLOPT_TIMEOUT => 120, // timeout on response
CURLOPT_MAXREDIRS => 10, // stop after 10 redirects
);
$ch = curl_init( $url );
curl_setopt_array( $ch, $options );
$content = curl_exec( $ch );
$err = curl_errno( $ch );
$errmsg = curl_error( $ch );
$header = curl_getinfo( $ch );
$httpCode = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
curl_close( $ch );
$header['errno'] = $err; //curl error code
$header['errmsg'] = $errmsg; //curl error message
$header['content'] = $content; //the webpage result (In this case the ip data in json array form)
$header['httpcode'] = $httpCode; //the webpage response code
return $header; //return the collected data and response codes
}
最后你会得到这样的东西:
Array
(
[ip] => 1.1.1.1
[hostname] => No Hostname
[city] =>
[country] => AU
[loc] => -27.0000,133.0000
[org] => AS15169 Google Inc.
)
http://www.geoplugin.com/ 稍旧,但这项服务为您提供了许多额外有用的信息,例如国家/地区以外的货币、大陆代码、经度等。
http://lite.ip2location.com/database-ip-country-region-city-latitude-longitude 提供了一堆可下载的文件,其中包含将它们导入数据库的说明。一旦您在数据库中拥有这些文件之一,您就可以相当轻松地选择数据。
SELECT * FROM `ip2location_db5` WHERE IP > ip_from AND IP < ip_to
使用 php 函数 ip2long(); 将 IP 地址转换为数值。例如 1.1.1.1 变为 16843009。这使您可以扫描数据库文件给您的 ip 范围。
所以为了找出 1.1.1.1 属于哪里,我们要做的就是运行这个查询:
SELECT * FROM `ip2location_db5` WHERE 16843009 > ip_from AND 16843009 < ip_to;
这将返回此数据作为示例。
FROM: 16843008
TO: 16843263
Country code: AU
Country: Australia
Region: Queensland
City: Brisbane
Latitude: -27.46794
Longitude: 153.02809
执行 IP 地理定位有两种广泛的方法:一种是下载数据集,将其托管在您的基础架构上并保持最新状态。这需要时间和精力,尤其是当您需要支持大量请求时。另一种解决方案是使用现有的 API 服务来管理您的所有工作以及更多。
有很多 API Geolocation 服务:Maxmind、Ip2location、Ipstack、IpInfo 等。最近,我工作的公司已经切换到Ipregistry(https://ipregistry.co),我参与了决策和实施过程。以下是您在寻找 IP 地理定位 API 时应考虑的一些要素:
- 服务准确吗?他们是否使用单一信息源?
- 他们真的能承受你的负担吗?
- 它们是否在全球范围内提供一致且快速的响应时间(除非您的用户是特定国家/地区的)?
- 他们的定价模式是什么?
这是一个获取 IP 地理位置信息的示例(但也可以通过一次调用获取威胁和用户代理数据):
$ip = $_SERVER['REMOTE_ADDR'];
$details = json_decode(file_get_contents("https://api.ipregistry.co/{$ip}?key=tryout"));
echo $details->location;
注意:我不是来推广 Ipregistry 并说它是最好的,但我花了很长时间分析现有的解决方案,他们的解决方案确实很有希望。