How to Get the Geographic Location of an IP Address

An IP address used to mean nothing to us, other than where they are in the cyber world, but it is now possible to find out where they are in the real world, using databases that arefreely available. In this article, I will disclose where you can get a free database that will tell you the geographic location of every IP address and how to use it.

The database I’m going to use is freely available from MaxMind. They are a company that provides geolocation technologies and credit card fraud detection. We will be using their free database in this article.

Importing the Data

We will be importing the data into a MySQL database, so let’s prep the database first. Create an empty database on your server, and add the following tables:

01. --
02. -- Table structure for table `CityBlocks`
03. --
04.  
05. CREATE TABLE `CityBlocks` (
06. `startIpNum` bigint(10) NOT NULL,
07. `endIpNum` bigint(10) NOT NULL,
08. `locId` mediumint(9) NOT NULL,
09. KEY `startIpNum` (`startIpNum`,`endIpNum`)
10. ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
01. --
02. -- Table structure for table `CityLocation`
03. --
04.  
05. CREATE TABLE `CityLocation` (
06. `locId` mediumint(9) NOT NULL,
07. `country` varchar(2) NOT NULL,
08. `region` varchar(55) NOT NULL,
09. `city` varchar(55) NOT NULL,
10. `postalCode` varchar(10) NOT NULL,
11. `latitude` decimal(7,4) NOT NULL,
12. `longitude` decimal(7,4) NOT NULL,
13. `metroCode` varchar(3) NOT NULL,
14. `areaCode` varchar(3) NOT NULL,
15. KEY `locId` (`locId`)
16. ) ENGINE=MyISAM DEFAULT CHARSET=latin1;

There are two tables because one location can have more than one IP address, or even an IP range. For all you database gurus, that would be a one (location) to many (IP addresses) relationship.

Once the database tables are in place, download the latest GeoLite City database in CSV Format. Extract the archive, and make note of where the CSV files are extracted. Next, import the files into their respective tables with these two queries:

01. --
02. -- Import data for `CityBlocks`
03. --
04. LOAD DATA LOCAL INFILE 'GeoLiteCity-Blocks.csv'
05. INTO TABLE CityBlocks
06. FIELDS TERMINATED BY ','
07. ENCLOSED BY '\"'
08. LINES TERMINATED BY '\n'
09. IGNORE 2 LINES
10. (startIpNum, endIpNum, locId)
01. --
02. -- Import data for `CityLocation`
03. --
04. LOAD DATA LOCAL INFILE 'GeoLiteCity-Location.csv'
05. INTO TABLE CityLocation
06. FIELDS TERMINATED BY ','
07. OPTIONALLY ENCLOSED BY '\"'
08. LINES TERMINATED BY '\n'
09. IGNORE 2 LINES
10. (locId,country,region,city,postalCode,latitude,longitude,metroCode,areaCode)

You may have to insert the absolute path to the data files, so ‘GeoLiteCity-Blocks.csv’ might be ‘/path/to/GeoLiteCity-Blocks.csv’ for a Linux enviornment.

Once these queries are processed, there should be ~3 million records in the CityBlocks table and ~200k records in the CityLocation table. Now we are ready to query this data.

Querying and Using the Data

The first thing we need is the visitor’s IP in long form. PHP has a simple function, ip2long(), that takes care of this. The long version of the IP address is stored in the database because a certain location can contain a range of IP addresses.

PHP will return a signed integer on some systems. I encountered this problem with I developed an application on a 64-bit server, and deployed it on a 32-bit server. When I moved the PHP application, IP addresses wern’t found that should be. Long story short, I learned from this postthat 32-bit systems return a signed integer. We don’t want that, so you will see me use sprintf()with ‘%u’ to force an unsigned integer and eliminate this problem.

Once we get the visitor’s IP address, fetching the data here can be done in two simple queries:

1. SELECT locId FROM CityBlocks WHERE $ip BETWEEN startIpNum AND endIpNum LIMIT 1
2.  
3. -- PHP code to fetch the row and assign the locID to $locId --
4.  
5. SELECT FROM CityLocation WHERE locId = $locId LIMIT 1

We will get a result like this after the second query:

01. array(9) {
02. ["locId"]=>
03. string(5) "14237"
04. ["country"]=>
05. string(2) "US"
06. ["region"]=>
07. string(2) "TX"
08. ["city"]=>
09. string(6) "Austin"
10. ["postalCode"]=>
11. string(5) "78773"
12. ["latitude"]=>
13. string(7) "30.3264"
14. ["longitude"]=>
15. string(8) "-97.7713"
16. ["metroCode"]=>
17. string(3) "635"
18. ["areaCode"]=>
19. string(3) "512"
20. }

So there you have it. That should be all you need to create your own geolocation app using PHP & MySQL. I will continue with a couple more advanced code samples to show how this can be expanded and applied.

Automating the Data Imports

The script is pretty self-explanatory and commented pretty well, so I won’t explain it line-for line. Replace line ~79 with your own DB connection code, and make sure that the database link is assigned to $db. Please post a comment if you have any questions.

It is not recommended to run this script repeatedly as it puts an unnecessary bandwidth load on maxmind.com when this script is run again and again. If you are using this script, and you have issues where it imports data into the database, comment line ~71 where wit_download_file() is called, so it’s not downloading that huge file every time you try it.

01. <?php
02. #die('remove line 2 before running'); /* remove this line before running */
03.  
04. /**
05. * Download any remote file using PHP's cURL extension
06. *
07. * @param string $source the URL to download
08. * @param string $destination where the file is to be saved
09. * @return bool
10. */
11. function wit_download_file($source$destination, &$err_str)
12. {
13. $destination fopen($destination'w');
14.  
15. if (!$destination)
16. {
17. return false;
18. }
19.  
20. $ch = curl_init();
21.  
22. curl_setopt($ch, CURLOPT_FILE, $destination);
23. curl_setopt($ch, CURLOPT_HEADER, 0);
24. curl_setopt($ch, CURLOPT_URL, $source);
25.  
26. curl_exec($ch);
27. $err_str = curl_error($ch);
28. curl_close($ch);
29.  
30. fclose($destination);
31.  
32. return ($err_str == '') ? true : false;
33. }
34.  
35. /**
36. * actual script starts here
37. */
38. header('Content-type: text/plain');
39.  
41.  
42. /* download the file - may take some time */
43. echo "Downloading data file...\n";
44. wit_download_file($link'GeoLiteCity.zip'$errstror die('Failed to download data file: ' $errstr);
45.  
46. /* extract the data file */
47. echo "Extracting...\n";
48. if (!is_dir('geoip')) mkdir('geoip', 0744);
49. shell_exec('unzip -oj GeoLiteCity.zip -d geoip/');
50.  
51. echo "Inserting into database...\n";
52. require('../includes/database.php');
53. $db = db_connect();
54.  
55. /* load the CityBlocks data */
56. mysql_query("TRUNCATE TABLE CityBlocks");
57. $query = "LOAD DATA LOCAL INFILE 'geoip/GeoLiteCity-Blocks.csv'
58. INTO TABLE CityBlocks FIELDS TERMINATED BY ',' ENCLOSED BY '\"'
59. LINES TERMINATED BY '\n' IGNORE 2 LINES (startIpNum, endIpNum, locId)";
60. $result = mysql_query($query);
61.  
62. /* load the location data */
63. mysql_query("TRUNCATE TABLE CityLocation");
64. $query = "LOAD DATA LOCAL INFILE 'geoip/GeoLiteCity-Location.csv'
65. INTO TABLE CityLocation FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"'
66. LINES TERMINATED BY '\n' IGNORE 2 LINES
67. (locId,country,region,city,postalCode,latitude,longitude,metroCode,areaCode)";
68. $result = mysql_query($query);
69.  
70. echo "Optimizing Tables...\n";
71. mysql_query("OPTIMIZE TABLE CityBlocks");
72. mysql_query("OPTIMIZE TABLE CityLocation");
73.  
74. echo "Deleting temp directory...\n";
75. shell_exec('rm -rf geoip/');
76.  
77. echo "Done!\n";
78. ?>

Geolocation Sample

Here is a simple example that gets the location of the current visitor, according to Maxmind’s free GeoCity database, and plots it on a Google Map. Please note that you will have to change the Google API Key if you plan on using this code on your own site.

Run This Example

01. <?php
02. /* replace with your own DB connection code */
03. require('../includes/database.php');
04. $db = db_connect();
05.  
06. /* get the IP address and make sure it is an unsigned integer */
07. $ip = sprintf('%u'ip2long($_SERVER['REMOTE_ADDR']));
08.  
09. /* fetch the location id */
10. $query "SELECT locId FROM CityBlocks WHERE $ip BETWEEN startIpNum AND endIpNum LIMIT 1";
11. $result = mysql_query($query$dbor die(mysql_error());
12. $row = mysql_fetch_assoc($result);
13.  
14. /* now fetch the location */
15. $locId $row['locId'];
16. $query "SELECT * FROM CityLocation WHERE locId = $locId LIMIT 1";
17. $result = mysql_query($query$dbor die(mysql_error());
18. $location = mysql_fetch_assoc($result);
19. ?>
20. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
21. <html>
22. <head>
23. <title>IP Geolocation Example</title>
24. <meta name="generator" content="Bluefish 1.0.7">
25. <meta name="author" content="Andrew Wells">
26. <meta name="date" content="2008-12-26T16:48:50-0600">
27. <meta http-equiv="content-type" content="text/html; charset=UTF-8">
28. <meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8">
29. <script src="http://maps.google.com/maps?file=api&;amp;v=2&amp;key=ABQIAAAAx6XuOYsDLrUX-imS2wkJshQcGiGm0nt-HEPscddBWrEOoLM0sRSH68H2XyBqlLiKczSojl9wJMHkqw"type="text/javascript"></script>
30. <script type="text/javascript">
31. //<![CDATA[
32. function load()
33. {
34. if (GBrowserIsCompatible())
35. {
36. var map = new GMap2(document.getElementById("map"));
37. map.setCenter(new GLatLng(<?=$location['latitude']?>, <?=$location['longitude']?>), 10);
38. map.addControl(new GMapTypeControl());
39. map.addControl(new GSmallMapControl());
40.  
41. var point = new GLatLng(<?=$location['latitude']?>, <?=$location['longitude']?>);
42. marker = new GMarker(point);
43. map.addOverlay(marker);
44. marker.openInfoWindowHtml('Lat/Lon: <?=$location['latitude']?>, <?=$location['longitude']?><br />City: <?=$location['city']?><br />Region: <?=$location['region']?><br />');
45. }
46. }
47. //]]>
48. </script>
49.  
50. </head>
51. <body onload="load()" onunload="GUnload()">
52. <h2>Map for (<?=$_SERVER['REMOTE_ADDR']?>):</h2>
53. <div id="map" style="width:800px;height:600px"></div>
54.  
55. <h2>Details from DB Record:</h2>
56. <pre><?php var_dump($location); ?></pre>
57. </body>
58. </html>

The application possibilities with this data is limitless. Companies have been known to use this data for targeted advertising, usage statistics, and even fraud detection. How you will use it in your own application is up to you. :)

Reference: http://phpstarter.net/2008/12/how-to-get-the-geographic-location-of-an-ip-address/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值