Posts Tagged ‘uk’

Geocoding UK Postcodes using PHP

Monday, May 12th, 2008

This solution is a PHP class that allows you to supply a postcode and have the latitude and longitude values returned in an array. It uses 4 existing mapping sites to retrieve the information - the sites are tried one at a time and the first one to return a result gets used. It works by sending an HTTP request with the supplied postcode in the querystring. The response is then tested against a regular expression pattern to find any matching latitude and longitude values. Two of the URLs return JSON formatted responses, so you could avoid the regex patterns and simply decode the JSON to get at the coordinates.

Please note that this method might be against the TOS of these sites. Most of these sites allow you to sign up for API access (for heavy users, that’s probably a better option).

<?php
/**
 * PHP class to show how you can use 4 popular map sites to
 * retrieve coordinates from a UK postcode.
 */
class PostcodeLookup
{
    var $sites;

    public function PostcodeLookup() {
        $this->sites = array(
                array('url'=>'http://www.streetmap.co.uk/streetmap.dll?GridConvert&name=%s&type=PostCode',
                    'pattern'=>'/\( ([0-9.-]+) \).*?\( ([0-9.-]+) \)/',
                    'name'=>'Streetmap'),
                array('url'=>'http://maps.google.com/?q=%s',
                    'pattern'=>'/geocode:"[^,]+,([0-9.-]+),([0-9.-]+)"/',
                    'name'=>'Google'),
                array('url'=>'http://maps.yahoo.com/services/1.0.0/location?appid=ymapsaura&flags=HJD&count=30&q=%s&r=1',
                    'pattern'=>'/"latitude":"([0-9.-]+)","longitude":"([0-9.-]+)"/',
                    'name'=>'Yahoo'),
                array('url'=>'http://www.multimap.com/API/geocode/1.2/public_api?output=json&callback=MMGeocoder.prototype._GeneralJSONCallback&qs=%s&countryCode=GB',
                    'pattern'=>'/"lat":"([0-9.-]+)","lon":"([0-9.-]+)"/',
                    'name'=>'MultiMap')
            );
    }

    public function getCoordinates($postcode) {
        // create context for HTTP requests
        $context = stream_context_create(array(
        'http'=>array(
            'method'=>'GET',
            'timeout'=>10,
            'header'=>"Accept-language: en\r\n" .
                    "User-Agent: Mozilla/5.0\r\n"
        )
        ));
        // shuffle sites within our array
        shuffle($this->sites);
        // loop through sites and attempt to retrieve coordinates
        foreach ($this->sites as $site) {
            extract($site);
            // send HTTP request
            $response = @file_get_contents(sprintf($url, urlencode($postcode)), false, $context);
            // if it contains the information we're after (coordinates)...
            if (preg_match($pattern, $response, $matches)) {
                // return them
                return array('lat'=>$matches[1], 'lon'=>$matches[2], 'site_name'=>$name);
            } else {
                // otherwise, tell us which site failed and continue checking the rest
                echo "$name failed!\n";
            }
        }
    }
}
?>

To test this out, include the class in your file and run this code

$lookup = new PostcodeLookup();
$pcode = $lookup->getCoordinates('SW1W 9TQ');
var_dump($pcode);

You should see something like this returned

array(3) {
  ["lat"]=>
  string(9) "51.494915"
  ["lon"]=>
  string(9) "-0.146670"
  ["site_name"]=>
  string(5) "Yahoo"
}

See also: