Programming and Technology
RSS icon Home icon
  • Get Geo Coordinates from Google Maps in PHP

    Posted on February 5th, 2010 brandon No comments

    Google maps offers a rich api for getting a lot of information as you are probably already aware. I’ve written a few locators in the last couple of years involving the use of google maps and doing radial searches based on zip codes. The difficult part for me was getting the geo coordinates of the queried zip code to use as a reference point for doing the radial search. I ended up writing a nice simple class to encapsulate converting zip codes into geo-coordinates.

    Credit totally goes to Marc at http://www.blogama.org/node/53 for providing the know-how for the base of this class. I took his concept and extended it.

    1.  
    2. class FP_Google_Maps {
    3.  
    4.         public static function getAddressGeoCoordinates($pAddress, $pCity, $pState, $pZip, $pKey, $pCountryCode=‘US’){
    5.             return self::getZipGeoCoordinates("{$pAddress}, {$pCity}, {$pState} {$pZip}", $pKey, $pCountryCode);
    6.         }
    7.  
    8.         public static function _geo($pQuery){
    9.             $d = file_get_contents($pQuery);
    10.  
    11.             if (!$d)
    12.                 return false; // Failed to open connection
    13.  
    14.             $d = utf8_encode($d);
    15.             $enc = mb_detect_encoding($d);
    16.             $d = mb_convert_encoding($d, ‘UTF-8′, $enc);
    17.  
    18.             return $d;
    19.  
    20.         }
    21.  
    22.         public static function getZipGeoCoordinates($pZip, $pKey, $pCountryCode=‘US’, $pCache=null){       
    23.            
    24.             $pZip = trim($pZip);
    25.            
    26.             if (!is_numeric($pZip))
    27.                 return false;
    28.  
    29.             if ($pCache){
    30.                 if ($geo = $pCache->load(‘google_geo_coordinates_’ . $pZip))
    31.                     return $geo;
    32.             }
    33.  
    34.             usleep(1000000);
    35.    
    36.             $query = ‘http://maps.google.com/maps/geo?q=’ . $pZip . ‘&output=xml&key=’ . $pKey;
    37.  
    38.             $d = self::_geo($query);
    39.  
    40.             if (!$d)
    41.                 return false; // Failed to open connection
    42.  
    43.             $coord = new SimpleXMLElement($d);
    44.  
    45.             $status_code = (string) $coord->Response->Status->code;
    46.  
    47.             if ($status_code != ‘200′){
    48.                 $success = false;
    49.                
    50.                 if ($status_code = ‘620′){                 
    51.                     $delay = 0;
    52.                     $attempts = 0;
    53.                
    54.                     while (($attempts <= 5) && $status_code != ‘200′){
    55.                         $attempts += 1;
    56.                         $delay += 2000000;
    57.                         usleep($delay);
    58.                    
    59.                         $d = self::_geo($query);
    60.                        
    61.                         if (!$d)
    62.                             return false; // Failed to open connection
    63.                         else {
    64.                             $coord = new SimpleXMLElement($d);
    65.                             $status_code = (string) $coord->Response->Status->code;                    
    66.                         }
    67.                     }
    68.  
    69.                     if ($status_code == ‘200′)
    70.                         $success = true;
    71.                 }
    72.                
    73.                 if (!$success){
    74.                     return false; // Invalid status code
    75.                 }
    76.             }
    77.        
    78.                 $nb_results = count($coord->Response->Placemark);
    79.                 $CA_results = 0;
    80.  
    81.                 for ($i=0;$i<$nb_results;$i++){
    82.  
    83.                         //get the accuracy. Result of 5 is a postal code
    84.                         foreach($coord->Response->Placemark[$i]->AddressDetails->attributes() as $a => $b) {
    85.                                 $accuracy = $b;
    86.                         }
    87.  
    88.                         if (($coord->Response->Placemark[$i]->AddressDetails->Country->CountryNameCode == $pCountryCode) && ($accuracy == 5)){
    89.                                 $CA_results++;
    90.                                 $ONLY_results = $i;
    91.                         }
    92.                 }
    93.  
    94.                 //multiple results
    95.                 if ($CA_results > 1){
    96.                         return false;
    97.                 }
    98.  
    99.                 //no results
    100.                 if ($CA_results < 1){
    101.                         return false;
    102.                 }
    103.  
    104.                 //Get the latitude and longitude
    105.                 list($lng, $lat) = explode(‘,’, (string) $coord->Response->Placemark[$ONLY_results]->Point->coordinates);
    106.                 $geo = array($lng, $lat);
    107.  
    108.                 if ($pCache)
    109.                     $pCache->save($geo, ‘google_geo_coordinates_’ . $pZip);
    110.                
    111.                 return $geo;
    112.         }
    113. }
    114. ?>
    115.  

    So at the moment, this class has only one useful method, getZipGeoCoordinates(). At a minimum it requires the zip could you wish to translate into geo-coordinates as well as your google maps api key. One of the extensions I made was the optional parameter to pass in a Zend_Cache object which allows frequently queried zip codes to remain cached rather than increasing your request count to the google maps api.

    The method takes your zip code and key and constructs a url which it uses to retrieve an xml response from the api. The xml is parsed for the information you desire and is passed back as an array with two elements, the longitude and latitude respectively.

    You may have noticed the loop that occurs if the api does not return the expected response code 200. If you have a really traffic site, like I did when I wrote this, you may run into the 620 code that google maps returns if you are making too many requests too quickly. If that happens, this class will retry it’s requests using a progressively longer delay (2 additional seconds) between each request.

    This class makes a great base for your google maps functionality and scales well on high traffic sites in a way that doesn’t get you black listed from the api. Enjoy

    • Share/Bookmark

    Leave a reply

Get Adobe Flash playerPlugin by wpburn.com wordpress themes