Saturday, October 02, 2010

Google GeoCoding from PHP with Curl & JSON

GeoCoding is the process of converting an address into a latitude and longitude. Google provides a Geocoding API that you can access from PHP. Here's how you do it:

$a = urlencode($addr);
   $geocodeURL = 
   "http://maps.googleapis.com/maps/api/geocode/json?address=$a&sensor=false";
   $ch = curl_init($geocodeURL);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
   $result = curl_exec($ch);
   $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
   curl_close($ch);
   if ($httpCode == 200) {
      $geocode = json_decode($result);
      $lat = $geocode->results[0]->geometry->location->lat;
      $lng = $geocode->results[0]->geometry->location->lng; 
      $formatted_address = $geocode->results[0]->formatted_address;
      $geo_status = $geocode->status;
      $location_type = $geocode->results[0]->geometry->location_type;
   } else {
     $geo_status = "HTTP_FAIL_$httpCode";
   }

Let's break it down a few lines at a time. First you want to build the URL with the address encoded using PHP's urlencode() function. This makes sure that no unsavory characters appear within the URL. In the words of the PHP manual, urlencode():
Returns a string in which all non-alphanumeric characters except -_. have been replaced with a percent (%) sign followed by two hex digits and spaces encoded as plus (+) signs.
Note that the URL also specifies the format we want Google to use for the results. In this case the "/json" part of the URL says we want results returned in JSON format (the other option is XML).

$a = urlencode($addr);
$geocodeURL = "http://maps.googleapis.com/maps/api/geocode/json?address=$a&sensor=false";

Now we setup CURL. We initialize it with the URL, and then set the "return transfer" option. This option basically says, to return the results into a PHP variable rather than putting them in a file on the disk.

$ch = curl_init($geocodeURL);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

Now we tell CURL to do it's thing, and check the result. When we call curl_exec(), it opens an HTTP connection to the URL we specified and performs an HTTP GET, returning the results into the $result variable. The call to cur_getinfo() returns the HTTP response code. If everything worked, it should be 200.:

$result = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

In the success case, we decode the JSON string which is stored in the $result variable, then pull some of the data out of it. Note that if everything went well on Google's end, then $geo_status should get set to "OK".

if ($httpCode == 200) {
      $geocode = json_decode($result);
      $lat = $geocode->results[0]->geometry->location->lat;
      $lng = $geocode->results[0]->geometry->location->lng; 
      $formatted_address = $geocode->results[0]->formatted_address;
      $geo_status = $geocode->status;
      $location_type = $geocode->results[0]->geometry->location_type;

Finally, we handle the failure case, where the HTTP response code was not 200. Here we just set $geo_status to something that will tell us there was a HTTP failure, and record the response code:

} else {
     $geo_status = "HTTP_FAIL_$httpCode";
   }

At this point you could store the data into a database record. When you go to actually use the data, be sure to check $geo_status to make sure it is set to "OK". In other words, don't assume lat and lng are set correctly, unless $geo_status is "OK".

Finally, note that there are a number of fields returned by Google. For a full description of the API, see the Google Geocoding API documentation. Happy geocoding!

JAVASCRIPT EQUIVALENT?


The code is exactly what you've been looking for, except that it is in php. You are wondering if there's a javascript equivalent of the above code.

Geocoding from Javascript is a good thing to do since the requests will be sent to Google from many different client IP addresses, rather than the address of your server. That way you avoid running into the daily limits Google places on requests from the same IP address.

Google has an example of geocoding from Javascript here.

9 comments:

Anonymous said...

Sweet! thanks for adding this. I needed it for my app.

maxpower9000 said...

In my project I needed to silently (PHP) geocode an address given by a user to retrieve the coordinates to push into the database along with the address to avoid geocoding on the fly everytime I initialize the map on the website.

(1) So I know the address. (2) And I want the geodata returned on the server side. (3) I want to be able to read and understand the returned data.

The approach:
$gmap['address'] = 'somestreet 101, 12345 berlin, germany';
$gmap['address'] = urlencode( $gmap['address'] );
$gmap['apiurl'] = "http://maps.google.com/maps/api/geocode/json?address={$gmap['address']}&sensor=false&language=DE";
$gmap['json'] = @file_get_contents( $gmap['apiurl'] );
$gmap['result'] = json_decode( $gmap['json'], true );
echo '<pre>'; print_r($gmap['result']); echo '</pre>';

The result:
The script puts a request to the API via the PHP function "file_get_contents", then decodes the returned JSON data into a more accessible PHP array. Voilá! Done! You may (as above) print out the returned data whilst testing your script, so you can easily pick out the desired variables.

Hope somebody can use it.

Eduardo Capanema said...

Excellent, thanks a lot! Can you tell me if you know about any limit of requests per IP or other?

Thanks,
Ed

CSSRule said...

Ed, Thank you for your comment. Regarding usage limits, these are subject to change but most recently it was 2,500 geolocation requests a day. Users of Google Maps API for Business get 100,000 requests a day.

Danny Le page said...

This is brilliant thanks again. I'm pretty rubbish however at retrieving other particular bits of data out of the json decoded response. How would I for example select specifically the name of the region? I'm happy to work it out for myself if someone didn't mind pointing me to the right direction for a tutorial? I've just never done this before and I'm finding it hard to find any basic resources on the topic and php.net is not being a massive help to me.

Thanks,
Danny.

CSSRule said...

Danny,
In the above code, just after this line:
$geocode = json_decode($result);

Add the following:
print_r($geocode);

That tells PHP to dump out the entire data structure. After you run this you may want to do a "view source" in your browser to see the output nicely formatted.

Then all you need to understand is how to access PHP objects and arrays. Look at the remaining lines of code above to see examples of accessing specific data items, then do a similar thing for the data you are trying to extract.

virginia said...

Easy! thanks

Unknown said...

Holy crap! Thank you so much! That totally worked. Reverse geocoding from a GoDaddy vDed server totally failed using file_get_contents(). But curl made it happen!

CSSRule said...

Aaron, Thank you for your comment.

Post a Comment

Note: Only a member of this blog may post a comment.