Eric Nagel

Eric Nagel

CTO, PHP Programmer, Affiliate Marketer & IT Consultant

Geo-Targeting PHP Script

I have been, or can be if you click on a link and make a purchase, compensated via a cash payment, gift, or something else of value for writing this post. Regardless, I only recommend products or services I use personally and believe will be good for my readers.

I spent a few minutes with Dr_Ngo and Neil Turner at Affiliate Summit, and we were talking about geo-targeting users. Pretty powerful stuff, if your landing page can say, “Find singles in Buffalo, NY” or something similar (whatever your offer is about).

The easy (but ghetto) way to do this to put the city & state in the query string. So it’d be like page.php?city=Buffalo&state=NY. Then in your code, you just echo the city and state variables, like < ?= htmlentities(stripslashes($_GET['city'])) ? >. But what if you just want 1 landing page, without using the query string? It’s actually pretty simple, and I’m going to walk you though it.

So first, you need a database. Here’s a good free one. So from your ssh line, you’ll want to get this database by typing:

Cron this to run monthly (looks like they do updates on the 1st, so run your cron on the 5th or so) and then unzip it:
gunzip GeoLiteCity.dat.gz

OK, now you’re going to want to get the PHP module to use this data. From this directory, download

  • geoipregionvars.php

So in a single directory, you’ll have these 3 files and GeoLiteCity.dat. Now you’re about to see how unbelievably easy this script is:


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

$rsGeoData = geoip_record_by_addr($gi, $_SERVER['REMOTE_ADDR']);



You’ll see I just do a print_r to show all the variables available to you, but for me, I see:

geoiprecord Object
[country_code] => US
[country_code3] => USA
[country_name] => United States
[region] => NY
[city] => Buffalo
[postal_code] => 14217
[latitude] => 42.9761
[longitude] => -78.8727
[area_code] => 716
[dma_code] => 514

So now your landing page will say,

Find singles in <?= htmlentities($rsGeoData->city . ", " . $rsGeoData->region) ?>

With the latitude & longitude, you can even show a map of the area using the Google Maps API. Having the Zip Code would be great for zip submit offers (only 2 1 left in 14217! – Enter your Zip Code to claim the prize!) or lots of other great ideas using a Zip Code database.

Beware of foreign IPs, though. If you’re not in the US, I don’t know what city or region will give back. You can replace $_SERVER[‘REMOTE_ADDR’] above with a known IP to see what it returns.

In case you were wondering, I started this installing this script at 3:40 and had it done at 3:50. It took me longer to write this blog post than it did to install the script, so don’t be afraid to try it yourself. If you have problems, though, just contact me.

  • Ken Savage
    Posted August 16, 2008 6:43 pm 0Likes

    You must have been thinking the same things I was last weekend. I’m doing the same thing the ghetto way now through my ppc stuff but I’m going to take you up on this script and try that out.

    I am looking to show ads on organic results based on coutry IP later on too but this is a good start. Nice stuff Eric.

  • Neil
    Posted August 20, 2008 1:16 pm 0Likes

    Nice! Thanks for script. The zip submit idea is great.

  • Dave
    Posted August 29, 2008 12:26 am 0Likes

    Hey Eric good explanation … I’ve always wondered how to do this. Thanks!

  • Kevin Carlson
    Posted September 28, 2008 12:50 pm 0Likes

    Just FYI, some hosting providers have disabled the fopen() function used by geoip_open, for security reasons.
    To make it work, the file would need to be rewritten to use the CURL library instead of fopen().

    I’ve alerted Maxmind to this issue, hopefully they will update their API to address this…

  • Trackback: BC$ MobileTV - Press » Blog Archive » Geo-Targeting with ZipCodeMap
  • Trackback: Thanks for the Coffee! - Nagel Family Website
  • Akram
    Posted December 30, 2008 12:34 am 0Likes


    My name is akram. I am software engineer and running my own company named ‘hive’.I am developing a website in which i want to get the country name object, I have redden your post and found very helpful but i could not access the country object please tell me how can i access and country object.

  • Akram
    Posted December 30, 2008 12:46 am 0Likes

    Thanks for your post it is very helpful for me and i get the answer “$rsGeoData->country_name”.


  • Eric
    Posted December 30, 2008 8:22 am 0Likes

    As Akram said, $rsGeoData is an object, so you’d access the object variables with ->, like “$rsGeoData->country_name”

  • garry egan
    Posted January 11, 2009 10:35 am 0Likes

    That was an awesome post. Once I found out what this piece was ‘called’ (geotargeting), your site made it easy to deploy.

    Way cool. I think this will most certainly increase conversions…

  • Al
    Posted February 3, 2009 3:41 pm 0Likes

    Hey guys….i am an EXTREME newbie to this, but REALLY want to learn it. I did what you said with the three files and the database, and then copied the code intothe page like this:


    $gi = geoip_open(“;“;, GEOIP_STANDARD);

    $rsGeoData = geoip_record_by_addr($gi, $_SERVER[‘REMOTE_ADDR’]);



    I then copied the bit of code for the city and state like this:

    So now your landing page will say, “Find singles in city . “, ” . $rsGeoData->region) ? >”.

    but i do not get anything that works.

    Can oneof you folks give me a hand?


  • Eric
    Posted February 3, 2009 3:44 pm 0Likes

    Al – what does print_r($rsGeoData); give you?

  • Josh
    Posted February 7, 2009 6:25 am 0Likes

    I’m a little confused – putting this directly onto a PHP page does not work?


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

    $rsGeoData = geoip_record_by_addr($gi, $_SERVER[‘REMOTE_ADDR’]);



  • Kojak
    Posted February 22, 2009 5:20 pm 0Likes

    Any demo that already running this geo targetted script?

  • Eric
    Posted February 22, 2009 5:29 pm 0Likes

    I don’t have a demo (that I’m going to share), but basically any affiliate dating website will use this. After all, people only want to date others that live around them.

  • Kojak
    Posted February 22, 2009 5:31 pm 0Likes

    Hi thanks for the reply eric. I just installed the database earlier which you can see here do you know how to change the country abbreviation into full country name? for example:

    US change into United States


  • Eric
    Posted February 22, 2009 5:35 pm 0Likes

    Use country_name instead of country_code or country_code3.

  • Greg
    Posted March 3, 2009 9:02 am 0Likes

    just curious – is there any other way to do this? just wondered if you had tinkered with any other methods(?)

    btw, thank you / it works great

  • Eric
    Posted March 3, 2009 9:18 am 0Likes


    There’s a Javascript one out there somewhere, but they require a link back to their website. Sorry, but for the life of me, I can’t find it. Besides, you don’t want to link back to someone else 🙂

  • Greg
    Posted March 3, 2009 2:46 pm 0Likes

    please let me know if you remember… i’ll be googl’ing too. thank you!

    Posted March 9, 2009 9:24 pm 0Likes

    Here is the a javascript version that takes directly from google.

    <script type="text/javascript" src=""> </script>
    <script type="text/javascript">
    if (typeof( != null) {
    +", "
    } else {
    document.write("Unknown location")

  • Jerry McKinish
    Posted May 7, 2009 2:48 pm 0Likes

    I inserted this into the head of my document.

    Then I inserted this into the body of the document. Now My whole page is blank. Can you help?

    <? $gi = geoip_open(“geo/./GeoLiteCity.dat”, GEOIP_STANDARD);

    $rsGeoData = geoip_record_by_addr($gi, $_SERVER[‘REMOTE_ADDR’]);


    geoip_close($gi); ?>

    city . “, ” . $rsGeoData->region) ? >

  • newbienoob
    Posted May 14, 2009 8:52 pm 0Likes

    I enter in the following code to my header.php file. I’ve placed all four files into the same directory as my header.php file.


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

    $rsGeoData = geoip_record_by_addr($gi, $_SERVER[‘REMOTE_ADDR’]);



    After placing this into my header and saving it my website shows me a blank page.

    Any suggestions?

  • Eric
    Posted May 15, 2009 7:44 am 0Likes

    Check your quotes – make sure you’re using " and not ”. Sorry, but WordPress puts “smart” quotes in my posts, which PHP does NOT like.

  • Stephane
    Posted May 19, 2009 5:14 pm 0Likes

    Hi, this is nice ! My question is : would you know how to get the continent_code ?

  • Eric
    Posted May 19, 2009 6:53 pm 0Likes

    @Stephane: – you’ll need an associative array and this data. So you’ll have:

    $rsContinents[‘US’] = ‘NA’;
    $rsContinents[‘TN’] = ‘AF’;

    Then you’ll know that if I’m in the US, I’m in NA (North America) and if I’m in TN (Tunisia) I’m in AF (Africa)

  • Stephane
    Posted May 20, 2009 3:27 am 0Likes

    Ok, I see. But if you use Apache Module (mod_geoip), you can do :


    I was hoping there was such a method like $rsGeoData->continent_code …

  • chris
    Posted May 25, 2009 6:16 pm 0Likes

    CashTactics, your javascript works fine! In fact i had been looking for that kind of thing for ages. The method talked about in the post is probably easy too, but
    I didn’t understand a thing. Copy&paste is all my lazy brain can do.

  • Trackback: Geo Caching For Fun & Profit (a.k.a How to find your arse with a funnel script) By Gregory Milby
  • Mark Heppner
    Posted July 12, 2009 12:28 pm 0Likes

    This is a great script! I am trying to use it to dynamically change the background and header on my website to match the time of day and weather of the user viewing it. To do this, I’m using XML data called from a weather API such as Yahoo, WeatherBug, or NOAA. However, no services let you call the data by the latitude and longitude. When I test your script, it does not throw back the zip code. It does work and it tells my correct location, but it is just blank for the zip. I need the zip codes to call the weather data! How did you get the zip code database to work? Is it included with the main database? Thanks for any help!

  • Jehzeel Laurente
    Posted October 12, 2009 12:17 pm 0Likes

    this is exactly what I need for my US only campaigns. Thank you so much for sharing this! 🙂

  • Trackback: Get a Free Zip Code Database and GeoLocate Your Content
  • Soufia
    Posted February 7, 2010 6:57 pm 0Likes

    thank you / it works great

  • Carl
    Posted March 5, 2010 1:09 pm 0Likes

    Thanks for the info, Eric! You made it really easy for a PHP newb like me to follow.

    For those who aren’t very skilled with using SSH, this came in really handy for me –

    It’s specific to bluehost, but i’m sure can apply to any other hosting service as well.

  • Joe
    Posted April 27, 2010 3:58 pm 0Likes

    Hi all,

    I want to know if it is possible to use the any of the (
    [country_code] => US
    [country_code3] => USA
    [country_name] => United States
    [region] => NY
    [city] => Buffalo
    [postal_code] => 14217
    [latitude] => 42.9761
    [longitude] => -78.8727
    [area_code] => 716
    [dma_code] => 514

    in a mysql GET query?

    e.g. SELECT *
    FROM geobytes_countries
    WHERE ISO3 = country (Param is $_rsGeoData[‘country_code3’]) or something like?

    Simply is there must be a $_GET[‘country_code3’] or $_SERVER[‘country_code3’] statement to get the variable detail in a RS.


  • Eric Nagel
    Posted April 27, 2010 4:22 pm 0Likes

    Hi Joe – yes, simply:
    SELECT * FROM geobytes_countries WHERE ISO3 = ‘$rsGeoData->country_code3’

  • Chetan
    Posted July 5, 2010 1:34 am 0Likes

    Can you pleas explain how to use this script on wordpress, I don’t understand much of the thing you explained above. Pleas explain with more details, I will be thankful to you.

  • Eric Nagel
    Posted July 5, 2010 10:56 am 0Likes

    @Chetan – use the Exec-PHP plugin for WordPress

  • qu
    Posted August 24, 2010 7:01 pm 0Likes

    To those getting a blank screen when trying this script: try running: php -f in shell — this should give you some more useful info. in my case, i was missing the mbstrings php extension. fixed (on CentOS) with: “yum install php-mbstring” followed by http server restart.

  • Evan
    Posted September 29, 2010 9:00 pm 0Likes

    For those who are interested, I wrote a script (Lambda GeoIP) to do all the normal Geo-targeting stuff but also find the nearest major city to the user. Its helpful if you want the user to think you’re nearby but also make it believable.

  • Joseph Gourvenec
    Posted November 23, 2010 7:24 am 0Likes

    Hi Eric, Hope you’re well!

    I was reviewing Maxmind and the GEO City Lite which says it does “MaxMind GeoLite City/ISP/Organization Edition Results” But I can seem to find the query strings for the ISP info, City, Etc?

    I wondered if you could help me and knew what they were.

    Cheers in advance,

  • φωτοβολταικα
    Posted April 17, 2011 12:47 pm 0Likes

    i was missing the mbstrings php extension. fixed (on CentOS) with: “yum install php-mbstring” followed by http server restart.

  • Greg Ricks
    Posted June 27, 2011 7:01 pm 0Likes

    Thanks for this page. Helped a lot.

  • Anny
    Posted October 17, 2011 9:17 am 0Likes

    Thank you for such useful information…

  • Trackback: Geolocation Click Redirection - LGR Internet Solutions
  • Steve
    Posted April 18, 2012 7:23 am 0Likes

    Great Script! I wanted to take it one stage further so that I can display the Subcountry codes but can’t seem to work it out!
    Here is the info on MaxMind –
    But can’t get it to work with your script… any ideas?

    • Eric Nagel
      Posted April 18, 2012 8:45 am 0Likes

      When you do a print_r($rsGeoData); do you see Subcountry info?

      • Steve
        Posted April 18, 2012 5:54 pm 0Likes

        No, that is the problem! can’t find out how to integrate the Subcountry info into the output
        Should I simply replace the subcountry codes with the main .dat file?

        • Eric Nagel
          Posted April 19, 2012 8:23 am 0Likes

          That may be it, Steve. My scripts use the “GeoLite City” database, so that’s all I’m familiar with.

          • Steve
            Posted April 20, 2012 10:22 am 0Likes

            ok thanks…
            I’ve checked the fips dat file from maxmind and by comparing it to the results I get from your script I can see that
            Example Data Results from your script
            [country_code] => GB
            [region] => M9
            matches correctly with the fips data file
            Any idea how I could get this to display
            I’m sure alot of your visitors would be interested as it allows for state/county anywhere not just UK


        • Eric Nagel
          Posted April 20, 2012 9:19 pm 0Likes

          Unfortunately, it’s not my script that reads the database, it’s from

          Looking at that fips file, you’d have to loop through it and find the M9 line, then pull from that “Staffordshire”. The better way would be to store that in a database, so you can access it quicker. The “fips 10-4 region code” to “name” relationship is 1:1

  • hitman
    Posted April 19, 2012 8:07 am 0Likes

    is geoip_close necessary?

    i have it in a foreach loop then use flush at the end.

    any issues with not using geoip_close?

    • Eric Nagel
      Posted April 19, 2012 8:20 am 0Likes

      Your open should be before the loop, and close after the loop. The only call within the loop is
      $rsGeoData = geoip_record_by_addr($gi, $_SERVER[‘REMOTE_ADDR’]);

      (plus whatever you’re going to do with that data)

  • Korush
    Posted November 18, 2012 7:06 am 0Likes

    Am i being stupid, but how come i cant get results using my mobile network.

  • Dave S
    Posted April 7, 2014 4:35 pm 0Likes

    This is pretty close to what I want to do but it looks like the last comments are back in 2012. Any reason this wouldn’t work in 2014? I have a database of 60,000 retail pharmacy locations in the US and am trying to create an easy “find the closest pharmacy to me” app. I’d like the pharmacies to sit in a mysql db if possible. Thanks! this is by far the easiest approach I’ve found after digging for hours.

    • Eric Nagel
      Posted April 7, 2014 4:38 pm 0Likes

      Hi Dave,

      I just used this method a few months ago on a project – it still works great

Leave A Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.