UK Postcode Search

Hi,

I don’t know how how difficult this is but i need to create a postcode search on the following site:

http://www.babiesinthecity.co.uk/search/?searchbutton=&search=M1

What you can see here is a set of “Reviews” which are being pulled out of a database. Each review has a postcode.

Now what i need to show on this page is the distance the inputted postcode which is “M1” is to each review.

I know i need an API, and i looked into The Google Directions API

The site is coded in PHP, but i don’t quite know how or where to begin? Can anyone point me in the right direction?

Thanks

I must say Anthony your method sounds the best! :wink:

I think i was just being stupid looking for an easy way out…

Anyway just to re-iterate what you’ve suggested, the logic will be:

  1. Lookup postcodes to see if given postcodes exist in database
  2. If they do, simply show those results
  3. If not, insert them into database and show results

If you see now, the page works:

http://babiesinthecity.co.uk/test/?searchbutton=&search=M5

This is because i haven’t reached my limit yet. But what you are saying makes sense, if i store the postcodes in a database, it will result in less requests…

Am i thinking along the right lines now Anthony? :smiley:

Perfecto! Brilliant.

Afternoon Billy,

You’re not listening. :wink:

The lookup of the distance, should only happen once. Not once per page load, day, summer holiday or full moon.

Once.

Create a background job to lookup all records in your database that do not have the distance between the x -> y already calculated. The job will look up the distance, if found/available/possible and update the record accordingly.

Any look ups which fail will automatically be picked back up on the next run.

If the records postcode changes, clear the distance column too and it auto-magic-tastically will be updated.

If you cannot create a cron job, cache it locally so the external call only happens once.

Bob requests the page, no distance found, look it up, save it, display page. Now, when Joe visits the page, the distance already exists and no external request is made.

Thoughts? :cool:

How about making use of a free api for UK Postcodes.
http://www.uk-postcodes.com/api.php

It will:

[list][]Return data for a postcode
[
]Return data for the nearest postcode to a point
[*]Return data for postcodes within x distance (miles) of a postcode or lat/lng[/list]

You could store returned values in a database so that before repeating a request to google, you check your local store of data first - this should reduce your requests. Alternatively, you can switch to using GClientGeocoder client side which means the limit is now applicable per visitor ip rather than server ip.

Hi,

I have this code:


class PostcodeSearch{

    public function get_distance($from, $to){
      $xml = new SimpleXMLElement(
        sprintf(
          'http://maps.google.com/maps/api/directions/xml?origin=%s&destination=%s&sensor=false',
          urlencode($from),
          urlencode($to)
        )
    );
      $distance = 0;
      if('OK' === (string)$xml->status){
        $query = $xml->xpath("route/leg/distance/value/text()");
        if(0 < count($query)){
          $distance = (int)$query[0];
        }
      }
      return $distance;
    }

}

And then i call the code like this:


$review = Review::searchAllReviewsByTitlePoscodeAndAddress();
				while($row = mysql_fetch_array($review)){ 
                                        $text = strip_tags($row['body']);
                                        $intro = substr($text, 0, 600);

$pcode = PostcodeSearch::get_distance($_GET['search'], $row['postcode']);
}

Thats all i have, any ideas what it might be?

That error points to this line:


    public function get_distance($from, $to){
      $xml = new SimpleXMLElement(
        sprintf(
          'http://maps.google.com/maps/api/directions/xml?origin=%s&destination=%s&sensor=false',
          urlencode($from),
          urlencode($to)
        )
    [B]);[/B]

See bold closing bracket…


function get_distance($from, $to){
  $xml = new SimpleXMLElement(
    sprintf(
      'http://maps.google.com/maps/api/directions/xml?origin=&#37;s&destination=%s&sensor=false',
      urlencode($from),
      urlencode($to)
    )
  );
  $distance = 0;
  if('OK' === (string)$xml->status){
    $query = $xml->xpath("route/leg/distance/value/text()");
    if(0 < count($query)){
      $distance = (int)$query[0];
    }
  }
  return $distance;
}

Hi Anthony…

I have been looking at Google’s Directions API… And have managed to put together something… This is my code:


class PostcodeSearch{

    public function LoadXml($origin, $destination){        
        $xml = simplexml_load_file("http://maps.google.com/maps/api/directions/xml?origin=".$origin."&destination=".$destination."&sensor=false");

        foreach ($xml->xpath('//distance') as $distance):
            $lastvalue = $distance->value;
        endforeach;

        $total = $lastvalue * 0.00062137119;
        $total = number_format($total, 2);

        return $total;
    }
}

Then in my front end i have this:


<?
$review = Review::searchAllReviewsByTitlePoscodeAndAddress();
				while($row = mysql_fetch_array($review)){ 
                                        $pcode = PostcodeSearch::LoadXml($_GET['search'], $row['postcode']);
?>

<div style="margin:0 0 10px 0; font-weight: bold">Distance: <span style="color:#990000"><?=$pcode?> miles</span></div>

<? } ?>

Now i am trying to get this working on this page:

http://www.babiesinthecity.co.uk/search/?searchbutton=&search=M25

Notice i have already put in a search of “M25”…

So basically for each review i loop through and check its postcode against the given input which in this case is “M25”. The first result is “Heaton Park” which has a postcode of “M25 2SW”… If we put this into the xml link like so:

http://maps.google.com/maps/api/directions/xml?origin=M25&destination=M25%202SW&sensor=false

It gives no results… Hence why i am getting the error on the display page:

Notice: Undefined variable: lastvalue in /home/migbabie/public_html/classes/PostcodeSearch.class.php on line 11

Yet if we look in Google:

http://maps.google.co.uk/maps?f=q&source=s_q&hl=en&geocode=&q=M25+to+M25+2SW&sll=53.800651,-4.064941&sspn=11.488016,39.506836&ie=UTF8&t=h&z=15

It works fine.

Any ideas why i am having this problem. This is all i need to do, just show the distance…

Don’t understand why it won’t work…

Thanks

Ok it looks quite difficult to do, but i will start from the beginning and work my way forward…

So first things first, you mentioned i need to get the long and lat values. So i understand why i need to get these values for the given postcode, however what do you mean when you say:

“The starting point is easy, you can manually find that, the second however will need to be ‘found’ by the code…”

Which starting point? And what needs to be found by the code? Once i have these values in my database, i presume i would then need to develop a method where the script calculates how far each Reviews postcode is against the given postcode…

Thanks Anthony,

I am getting an error:

http://www.babiesinthecity.co.uk/search/?searchbutton=&search=M25

In the front end i am calling the method like so:


$pcode = PostcodeSearch::get_distance($_GET['search'], $row['postcode']);

Any ideas why i get the error?

Thanks again

Well, first you need to find a longitude and latitude for the given postcode. The starting point is easy, you can manually find that, the second however will need to be ‘found’ by the code.

Remember though, you’ll only need to do this the once, the long and lat ain’t gonna change so just pop 'em in your database once obtained.

For the reverse GeoCoding you can use a rather funky YQL query such as this. This will find the long and lat for you, now the math begins.

You now have 2 sets of long and lats. To calculate the distance (as the crow flies) you can apply the Great Circle Distance formula which takes into account the curvature of the earth too.

Who says math aint cool?

Entity: line 1: parser error : Start tag expected, ‘<’ not found in /home/migbabie/public_html/classes/PostcodeSearch.class.php on line 24

Sorry, I cannot test as my internal dev server has no internet access (I’m at work). The above message states the problem, try a spot of debugging. :wink:

Thanks pmw57.

Well what i essentially need is to check the given postcode (By the user in the search box) against a series of “Reviews”… Each review has it’s own postcode so it’s quite simple to pull that out.

I visited that page you have suggested… So lets say the enters “M5 4WT” and i want to check it against “OL12 0JJ”. I would want the results in xml as i can sift through the different nodes to get what i need, such as the distance.

Would the URL be as such:

http://www.uk-postcodes.com/distance.php?postcode=OL11%201PH&distance=M1&format=xml

Can you see where i’m going wrong? I just need to find the distance between the two postcodes?

Thanks

Ok i have been doing some more debugging and testing…

Turns out the code i was using before, which is this:


    public function LoadXml($origin, $destination){
        $xml = simplexml_load_file("http://maps.google.com/maps/api/directions/xml?origin=".$origin."&destination=".$destination."&sensor=false");

        foreach ($xml->xpath('//distance') as $distance):
            $lastvalue = $distance->value;
        endforeach;

        $total = $lastvalue * 0.00062137119;
        $total = number_format($total, 2);
        
        return $total;
    }

The reason i say this is because it was successfully giving me the correct distance between a given postcode but then suddenly stopped working.

I did a print_r on the XML object and got this:

OVER_QUERY_LIMIT

Looked this up on Google and come to know it meant my daily limit has been reached??

Can anyone shed some light on this?

What can i do to overcome this?

Thanks

Ok cool,

Well first things first, i want to make this code work better, because on some search results i get this:

http://babiesinthecity.co.uk/test/?searchbutton=&search=m1

The top results show fine with the distance being shown. But the bottom results show an error saying “lastvalue” is undefined??

Anyway, this is my code:


    public function LoadXml($origin, $destination){
 
        $xml = simplexml_load_file("http://maps.google.com/maps/api/directions/xml?origin=".$origin."&destination=".$destination."&sensor=false");

        foreach ($xml->xpath('//distance') as $distance):
            $lastvalue = $distance->value;
        endforeach;

        $total = $lastvalue * 0.00062137119;
        $total = number_format($total, 2);

        return $total;
    }

I had a look at code suggested by Anthony, the error i was getting when using that code was because a third parameter was missing? I viewed the link to the documents, and i found this at the very top:


SimpleXMLElement::__construct  ( string $data  [, int $options  [, bool $data_is_url  [, string $ns  [, bool $is_prefix  ]]]] )

Showing 3 parameters. I just wasn’t quite sure how or where to add this to that code :confused:

An option for getting the coordinates for postcodes is a think from Ordinance Survey called Code-Point, which has coordianates for each post code, though before you use it you should contact Ordinance Survey to check on licensing, etc for your intended plans. I don’t know how much they will charge for the use of the data.

Another alternative is the Royal Mail PAF but the costs of it, licensing etc is expensive.

If you go for either option it may well pay to contact them and go through with them the relevant options for your intended use and licensing, costs, etc.

By the way, this is the error:

Warning: SimpleXMLElement::__construct() [simplexmlelement.–construct]: Entity: line 1: parser error : Start tag expected, ‘<’ not found in /home/migbabie/public_html/classes/PostcodeSearch.class.php on line 24

Warning: SimpleXMLElement::__construct() [simplexmlelement.–construct]: http://maps.google.com/maps/api/directions/xml?origin=M25&destination=M25+2SW&se in /home/migbabie/public_html/classes/PostcodeSearch.class.php on line 24

Warning: SimpleXMLElement::__construct() [simplexmlelement.–construct]: ^ in /home/migbabie/public_html/classes/PostcodeSearch.class.php on line 24

Fatal error: Uncaught exception ‘Exception’ with message ‘String could not be parsed as XML’ in /home/migbabie/public_html/classes/PostcodeSearch.class.php:24 Stack trace: #0 /home/migbabie/public_html/classes/PostcodeSearch.class.php(24): SimpleXMLElement->__construct(‘http://maps.goo…’) #1 /home/migbabie/public_html/search/index.php(36): PostcodeSearch::get_distance(‘M25’, ‘M25 2SW’) #2 {main} thrown in /home/migbabie/public_html/classes/PostcodeSearch.class.php on line 24

Bah! Thanks Salathe.

As Salathe states, there are some parameters missing from SimpleXMLElement, care to fix it yourself Billy?

All you need is the manual.

It’s not clear from the error message, but are you trying to create the SimpleXMLElement object without telling the class that you are providing a URL (as opposed to an XML string)? See the docs, especially the optional third parameter which defaults to false.

If you’re already doing that, can we see the PHP code?