Tuesday, December 16, 2008

PHP > Postal Code Distance Calculator

 

Two very simple functions that work together to calculate the distance between two different Canadian postal codes.

Alternatively you could pay $600 for a database of all Canadian postal codes with longitudes and latitudes, but I don't think that's why your reading this page. This method is easy to implement, connects to a constantly updated database, and did I mention--it's free?

How it works

The one function, "getCoord", uses Google Maps API's XML feed to fetch the longitude and latitude of each postal code, the second, "calcDistance", does some freaky math to calculate the distance in kilometers.

DON'T FORGET: You'll need to signup to use the Google Maps API at http://www.google.com/apis/maps/signup.html before you can use the getCoord function. Take the key Google gives you and store it in the constant 'KEY'.

Drawbacks

I used to use GeoCoder do the same calculations which only allowed for 100 lookups a day. Now with Google we have a 50,000 lookup limit. Which I doubt you'll ever surpass.

<?php
/**
* GETCOORD
* Uses Google Maps to resolve the coordinates of a postal code

* @param   String   $postal   Postal code to lookup
* @return  Array    Returns array with latitude and longitude
* @return  Boolean  False if an error occurred
*/
// ---- | REQUIRED GOOGLE MAPS KEY | --------
// Get yours here: http://www.google.com/apis/maps/signup.html
define('KEY', '---fill me in---');
function getCoord($postal)
{
$d = file_get_contents('http://maps.google.com/maps/geo?q=' . $postal . '&output=xml&key=' . KEY);
    if (!$d)
        return false; // Failed to open connection
$coord = new SimpleXMLElement($d);
    if ((string) $coord->Response->Status->code != '200')
        return false; // Invalid status code
list($lng, $lat) = explode(',', (string) $coord->Response->Placemark->Point->coordinates);
    return array('Lat' => (float) $lat, 'Lng' => (float) $lng); 
}
/**
* CALCDISTANCE
* Calculates the distance between to postal codes

* @param   String   $postal1   Starting postal code
* @param   String   $postal2   Ending postal code
* @return  Float    Returns distance in kilometers
* @return  Boolean  False if an error occurred
*/
function calcDistance($postal1, $postal2)
{
$dst1 = getCoord($postal1);
$dst2 = getCoord($postal2);
    if (!$dst1 or !$dst2)
        return false; // Invalid postal codes
$kms = rad2deg(acos(sin(deg2rad($dst1['Lat'])) * sin(deg2rad($dst2['Lat'])) +  
cos(deg2rad($dst1['Lat'])) * cos(deg2rad($dst2['Lat'])) * 
cos(deg2rad($dst1['Lng'] - $dst2['Lng'])))) * 60 * 1.1515 * 1.609344; 
    return $kms;
}
echo calcDistance('r3g3j6', 'r0c3e0') . ' kms'; // prints 37.... kms
?>

No comments: