Some consumers are up in arms because that fake blog they read by someone who just happens to be from the same city they live in, turns out to be a bit phony. They’re surprised to find out that a piece of software is behind the trick, which does a GeoIP lookup on their IP address, and then uses that within the text of the splog, or ad, making the reader feel a bit more of a connection to the ad copy.

Even before these splogs popped up, I had been interested in GeoIP lookup techniques for Google Maps mashup purposes, but the splog trick finally made me figure out how it was done.

DISCLAIMER: I don’t condone the use of these techniques for deceptive advertising techniques. At best, they are disingenuous, and at worst, may be illegal, according to the FTC. Like The Force, this technique can be used for good or evil. Which path you choose is up to you.

MaxMind has a paid GeoIP City database service that costs $370 up front and $90 a month for database updates, which they advertise as 99.8% accurate in determining location from IP address. However, they also make a free database available, that is 99.5% accurate. We’ll cover the free version since the accuracy difference is negligible for our purposes.

The crucial information is spread out over four pages on the MaxMind site:

APIs for GeoIP products
GeoLite Country information
GeoLite City information
and our API of choice, the GeoIP PHP API

It should be noted that the GeoIP PHP API has three methods of being implemented, each being more efficient with webserver resources than the previous: a pure PHP module, a PECL module that allows you to embed the GeoIP C Library inside PHP, and mod_geoip, an Apache module that you can access via PHP. Since our needs are fairly minimal, we’ll go with the easiest to implement, the pure PHP module, which requires no PHP or Apache changes.

1) Download the following PHP files from MaxMind:,, and geoipregionvars.php .

2) Download the latest GeoLite City Binary Format file, which is updated on the 1st of each month, and gunzip it.

3) Put all of those files in their own directory somewhere on your webserver, and for this example, we’ll name the directory GeoIP.

4) Put the following code in a web-accessible PHP page, changing the PATH/TO parts to match your setup, and view the page in a web browser:

  1. <?php
  2. require_once('/PATH/TO/GeoIP/');
  3. $gi = geoip_open('/PATH/TO/GeoIP/GeoLiteCity.dat', GEOIP_STANDARD);
  4. $location = GeoIP_record_by_addr($gi, $_SERVER&#91;'REMOTE_ADDR']);
  5. geoip_close($gi);
  7. echo '<pre>';
  8. print_r($location);
  9. echo '</pre>';
  10. ?>
  12. I believe you are in <?php echo $location->city ?>, <?php echo $location->region ?>

The database says I’m in Los Angeles when in fact we’re in Mission Viejo (Orange County), which isn’t a huge deal, but shows the possible slight inaccuracy in IP->location lookup.

One thing this could benefit from is a quick state abbreviation to full state name conversion function, so the text would be “Los Angeles, California” instead of “Los Angeles, CA”. I think the full spelling looks more natural in some instances. I’ve uploaded a PHP state abbreviation to state name conversion function for your use.

Update: Danger Brown steals the show for GeoIP made REALLY easy. He’s got a two line javascript snippet that does the same thing, but is reliant on the MaxMind servers each time the script is called. My experience with using javascript that is resident on outside servers is that it works great until it doesn’t. One day your site will be slow or completely down because the outside javascript is failing to load. Some well crafted code can mitigate the risk, but I prefer to have all executing code on my server. Except for Google Analytics, because I tend to be no match for their servers.

Update 2: I’ve uploaded my modified that includes the abbreviation to state/province function, with ON->Ontario included, and the call to that function in GeoIP_record_by_addr. Note that I could have also put the $record->region_name = Abbreviation_GetStateName($record->region); code within the _get_record function, but I chose to put it in the higher-level GeoIP_record_by_addr function.

Update 3: has a post about a very simple way to use the Google javascript API to do geolocation