Using IP Geolocation and Radius Searching with PHP/MySQL

Delivering content relative to the physical location of your users is an excellent (and fairly easy) way to fine-tune the content you’re delivering to be most relevent to the people visiting your site. Two simple ways of doing this are to use an IP-based geolocation lookup, or to do a manual radius search (like a “store finder” type of functionality), where the user manually enters a postal code. Both function on the same logic – the real difference is that one requires a third-party service that can fetch the user’s latitude and longitude based on IP address. This functionality can be used to show content such as local news, local store branches, etc – as soon as the user visits your page.

The nuts and bolts of IP-based geolocation is as follows:

User lands on the web page

User’s IP is captured and posted to a third-party geolocation service, which returns a latitude and longitude for the IP address

Website performs a radius database search using the latitude and longitude provided by the third party service and returns content relative to that location

Bear in mind, your database must contain data that is stored with a latitude and longitude for this to work. You cannot compare a user’s latitude and longitude to the lat/long of a piece of data if you have no lat/long associated to your content.

Also, please note: the services mentioned here – and the code provided – is intended for US-based geolocation. The code will remain basically the same for non-US lookups, but you may need to use alternate third-party services if your country is not covered by the ones mentioned here.

1. Getting Latitude/Longitude for Your Database Data

The first part of this process starts with you tagging your existing or newly added database data with the correct latitude and longitude. Each item you wish to include in the radius search should have a valid lat/long value in the latitude and longitude fields. If you are modifying an existing database, you would execute an alter table command to add the new lat/long fields. For this example, we’ll be using a table called stores:

Now our table is set up to store the latitude and longitude data, but from where do we actually get the data, short of manually looking it up for each row of data in our stores table? Easy. There is a fabulous free service available at rpc.geocoder.us that lets you post an address to their API, to which it responds with the latitude and longitude values for that address. The easiest way to handle this process is to set up a cURL request in the admin area where you’re managing your data – otherwise you’ll need to write a script to cycle through the rows of data, fetching the latitude and longitude.(You will, of course, need to have PHP configured with cURL support for this to work.) Using this service, free lookups are throttled by your IP address to one request every 15 seconds – this may cause issues when you’re initially trying to get the lat/long data into your database for existing records, but shouldn’t be much of an issue afterwards.

// if the array does not contain data, no match was found in geocoder.us, so suggest using google maps to find the lat/long manually
} else {
echo ‘No geolocation match.’;

}[/sourcecode]

The code above will help you update your existing data if you were to use it in a script that cycles through your database records, or you can use it as part of your store administration area, doing the cURL request every time a new store is saved to the database.

2. Getting the Latitude and Longitude of the User

Now that you have base lat/long data for the data in your database, you have to obtain the lat/long for the user visiting the site. For this next part, you will again need to access a third-party service, this time to get the latitude and longitude based on the user’s IP address. I use a commercial service available from MaxMind.Com. It’s not free, but their prices are very reasonable ($20 per 50,000 queries) – and by using a cookie to store whether or not the user’s lat/long has already been returned, you can save on the number of accesses you use up on a busy site.

Now, you’ll only be querying MaxMind if the user hasn’t already accessed the site before and had their latitude and longtude stored in the cookie. Note the $license variable in the code above. When you sign up for the MaxMind Web Service, you will be given a license number, which you’ll insert there.

3. Putting the Two Together to Return Results Within X Miles

To tie the two together and query the database, returning only results that are within a specified number of miles of the user’s IP address, we’ll need two classes:

Store Locator Only

If you want to create a store-locator style script without automagically getting the user’s current location, you’d use the code above, almost verbatim. The difference is that you’d need an additional table of zipcodes with associated lat/long, available for purchase (again, not very expensive) from ZipCodeDownload.Com. The process would go as follows:

User arrives at your site, and enters a zip code and mile radius they wish to search using your search form – clicks submit

The script queries the zip code table to find the latitude and longitude associated with the postal code the user has entered, and uses THAT latitude and longitude as the values for $Latitude and $Longitude in the code above, and uses the user-entered values for $Miles from the search form.

Everything else stays exactly the same. Naturally, you’ll probably want to add some sanity checks in your own code (gracefully displaying default content if no latitude and longitude is returned, etc) but I decided to skip that here so as not to confuse anyone.

Enjoy, and if you end up using this anywhere, let me know how it works out.

About the author

snipe

I’m a tech geek/dev/infosec-nerd/scuba diver/blacksmith/sword-fighter/crime fighter/ENTP/warcrafter/activist. I run Grokability, Inc, and run several open source projects, including Snipe-IT Asset Management. Tweet at me @snipeyhead or read more…

Hey. This is great work. Thanks. I have successfully created a store locater with this script and zipcodedownload.

I have a question though. When I set the search radius to, let's say 25miles, it is showing me matches from outside 25miles (ie. it is showing me a store from 28.5miles). Do you know why that might be? Could there be something off in the calculations being performed on the lats and longs?

Search

About Me

I’m a tech geek/dev/infosec-nerd/scuba diver/blacksmith/sword-fighter/crime fighter/ENTP/warcrafter/activist. I run Grokability, Inc, and run several open source projects, including Snipe-IT Asset Management. Tweet at me @snipeyhead or read more…