{"id":440,"date":"2008-01-11T21:34:28","date_gmt":"2008-01-12T02:34:28","guid":{"rendered":"http:\/\/blogs.n1zyy.com\/n1zyy\/2008\/01\/11\/geolocation\/"},"modified":"2008-01-11T21:34:28","modified_gmt":"2008-01-12T02:34:28","slug":"geolocation","status":"publish","type":"post","link":"https:\/\/blogs.n1zyy.com\/n1zyy\/2008\/01\/11\/geolocation\/","title":{"rendered":"Geolocation"},"content":{"rendered":"<p>The concept of matching an IP to a country is known as IP geolocation, often just &#8220;IPGeo&#8221; or &#8220;GeoIP.&#8221; There are lots of reasons for using IP geolocation, ranging from the mundane (identifying countries in your webserver logfiles) to the questionable (banning countries from your server to cut down on spam) to the neat (doing it at firewall\/router level and redirecting a user to the closest data center).<\/p>\n<p>Most of the work is just done on a country level. You take an IP (72.36.178.234, my server) and look it up in a database, and get &#8220;UNITED STATES&#8221; as an answer. There do exist databases on finer levels, down to the city, but they&#8217;re expensive and often wrong. (I keep getting ads to find hot singles in Mashpee, more than 100 miles away and in a different state&#8230; Or maybe it&#8217;s Mattapan. Whatever the case, they&#8217;re not even close.)<\/p>\n<p>It turns out that you can download a <a href=\"http:\/\/ip-to-country.webhosting.info\/node\/view\/9\">free database of IP-country mappings<\/a>. It&#8217;s not infallible, but they say it&#8217;s 98% accurate. The database itself won&#8217;t do you any good. It&#8217;s a compressed CSV (comma-separated variable).<\/p>\n<p>In the comments section <a href=\"http:\/\/ip-to-country.webhosting.info\/node\/view\/6\">here<\/a>, there&#8217;s a snippet of PHP code to take the CSV and convert it to a huge series of SQL inserts, which you input into a database&#8230; (Hint: for whatever reason, his preg_match is imperfect and leaves a few instances of the word &#8220;error&#8221; in the middle of the file. It&#8217;s probably a bad idea, but I just commented out the &#8220;echo error&#8221; line. I end up with a 5.7MB SQL query. You can also just download the thing directly <a href=\"http:\/\/ttwagner.com\/geoip\/sql.sql\">here<\/a> (warning: 5.7 MB SQL file). Note that, per the license terms, I disclose in the comments that it&#8217;s a derivative work of their CSV file.<\/p>\n<p>The other important catch is that IPs are stored as long integers, not &#8216;normal&#8217; IPs. You&#8217;ll presumably want to use PHP + MySQL to get the country associate with PHP, so I&#8217;ll provide pseudocode in a minute. PHP provides an ip2long() function, but it only takes you halfway, but leaves you with sign problems. (Argh!) It&#8217;s an easy fix, though, and you want something like the following:<\/p>\n<blockquote>\n<pre>$long = sprintf(\"%u\", ip2long($ip));\n$query = \"SELECT a2,a3,country FROM ip2c WHERE start <= $long AND end >= $long\";<\/pre>\n<\/blockquote>\n<p>You then, of course, run $query and parse through it&#8230; You get 2- and 3-letter country codes, as well as the full country name. I use it, with good results, in seeing what country comment spam is coming from. (Most of it comes from the US.)<\/p>\n<p>A MySQL query isn&#8217;t the <em>proper<\/em> way to do this: there exist binary files with the same data that result in faster lookups. But this is the simplest way to start doing IP geolocation in ten minutes time, and, with the <a href=\"http:\/\/blogs.n1zyy.com\/n1zyy\/enabling-mysqls-query-cache\/\">query cache enabled<\/a>, there&#8217;s not a ton of overhead.<\/p>\n<p>I&#8217;m tempted to write some scripts to allow people to &#8216;browse&#8217; the database, either looking up an IP, or to view it by country.<\/p>\n<p><strong>Update<\/strong>: Weird Silence has a binary implementation of this same database that&#8217;s supposedly much faster. The <a href=\"http:\/\/weirdsilence.net\/software\/ip2c\/\">main page<\/a> is here, the PHP one is <a href=\"http:\/\/weirdsilence.net\/software\/85\/\">here<\/a>, and <a href=\"http:\/\/weirdsilence.net\/software\/88\/\">the C one<\/a> is (t)here. (I&#8217;m wondering if it makes sense to write a PHP script to call the C version, and what the performance implications would be?)<\/p>\n<p><strong>Update 2:<\/strong> Get your <a href=\"http:\/\/ip-to-country.webhosting.info\/node\/view\/91\">country flags<\/a> here.<\/p>","protected":false},"excerpt":{"rendered":"<p>The concept of matching an IP to a country is known as IP geolocation, often just &#8220;IPGeo&#8221; or &#8220;GeoIP.&#8221; There are lots of reasons for using IP geolocation, ranging from the mundane (identifying countries in your webserver logfiles) to the &hellip; <a href=\"https:\/\/blogs.n1zyy.com\/n1zyy\/2008\/01\/11\/geolocation\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,5,10,12,13,18,22],"tags":[],"class_list":["post-440","post","type-post","status-publish","format-standard","hentry","category-computers","category-cool-links","category-ideas","category-interesting","category-linux-tips","category-ocd","category-programming"],"_links":{"self":[{"href":"https:\/\/blogs.n1zyy.com\/n1zyy\/wp-json\/wp\/v2\/posts\/440","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.n1zyy.com\/n1zyy\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.n1zyy.com\/n1zyy\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.n1zyy.com\/n1zyy\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.n1zyy.com\/n1zyy\/wp-json\/wp\/v2\/comments?post=440"}],"version-history":[{"count":0,"href":"https:\/\/blogs.n1zyy.com\/n1zyy\/wp-json\/wp\/v2\/posts\/440\/revisions"}],"wp:attachment":[{"href":"https:\/\/blogs.n1zyy.com\/n1zyy\/wp-json\/wp\/v2\/media?parent=440"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.n1zyy.com\/n1zyy\/wp-json\/wp\/v2\/categories?post=440"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.n1zyy.com\/n1zyy\/wp-json\/wp\/v2\/tags?post=440"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}