PHP Script fails to parse JSON returned by Google Maps Geocoder API if multiple results are returned by Geocoder

StackOverflow https://stackoverflow.com/questions/4878891

Question

I have a PHP script that attempts to read and parse JSON strings returned from Google's Geocoder API. The script works fine for most addresses but runs into trouble in a few occasions where Google's Geocoder API returns multiple results for a given address.

This is my code:

$mGeoFile = fopen("http://maps.googleapis.com/maps/api/geocode/json?address=" . str_replace(" ", "+", $mAddress0) . "&sensor=false", "r");       
$mGeoFileJSON = fread($mGeoFile, 10000);
fclose($mGeoFile);
$mGeocode_array = json_decode($mGeoFileJSON, true);

var_dump($mGeocode_array);
echo "<br />";
var_dump($mGeocode_array['results'][0]['geometry']['location']);

Which prints this for "115 Chestnut Street Upton, MA" (passed in $mAddress0):

array(2) { ["status"]=> string(2) "OK" ["results"]=> array(1) { [0]=> array(4) { ["types"]=> array(1) { [0]=> string(14) "street_address" } ["formatted_address"]=> string(37) "115 Chestnut St, Upton, MA 01568, USA" ["address_components"]=> array(8) { [0]=> array(3) { ["long_name"]=> string(3) "115" ["short_name"]=> string(3) "115" ["types"]=> array(1) { [0]=> string(13) "street_number" } } [1]=> array(3) { ["long_name"]=> string(11) "Chestnut St" ["short_name"]=> string(11) "Chestnut St" ["types"]=> array(1) { [0]=> string(5) "route" } } [2]=> array(3) { ["long_name"]=> string(5) "Upton" ["short_name"]=> string(5) "Upton" ["types"]=> array(2) { [0]=> string(8) "locality" [1]=> string(9) "political" } } [3]=> array(3) { ["long_name"]=> string(5) "Upton" ["short_name"]=> string(5) "Upton" ["types"]=> array(2) { [0]=> string(27) "administrative_area_level_3" [1]=> string(9) "political" } } [4]=> array(3) { ["long_name"]=> string(9) "Worcester" ["short_name"]=> string(9) "Worcester" ["types"]=> array(2) { [0]=> string(27) "administrative_area_level_2" [1]=> string(9) "political" } } [5]=> array(3) { ["long_name"]=> string(13) "Massachusetts" ["short_name"]=> string(2) "MA" ["types"]=> array(2) { [0]=> string(27) "administrative_area_level_1" [1]=> string(9) "political" } } [6]=> array(3) { ["long_name"]=> string(13) "United States" ["short_name"]=> string(2) "US" ["types"]=> array(2) { [0]=> string(7) "country" [1]=> string(9) "political" } } [7]=> array(3) { ["long_name"]=> string(5) "01568" ["short_name"]=> string(5) "01568" ["types"]=> array(1) { [0]=> string(11) "postal_code" } } } ["geometry"]=> array(4) { ["location"]=> array(2) { ["lat"]=> float(42.1476896) ["lng"]=> float(-71.5863099) } ["location_type"]=> string(18) "RANGE_INTERPOLATED" ["viewport"]=> array(2) { ["southwest"]=> array(2) { ["lat"]=> float(42.1445379) ["lng"]=> float(-71.5894495) } ["northeast"]=> array(2) { ["lat"]=> float(42.1508332) ["lng"]=> float(-71.5831542) } } ["bounds"]=> array(2) { ["southwest"]=> array(2) { ["lat"]=> float(42.1476815) ["lng"]=> float(-71.5863099) } ["northeast"]=> array(2) { ["lat"]=> float(42.1476896) ["lng"]=> float(-71.5862938) } } } } } } 
array(2) { ["lat"]=> float(42.1476896) ["lng"]=> float(-71.5863099) }

Also the Geocoder returns the following JSON string for "115 Chestnut Street Upton, MA"

{
  "status": "OK",
  "results": [ {
    "types": [ "street_address" ],
    "formatted_address": "115 Chestnut St, Upton, MA 01568, USA",
    "address_components": [ {
      "long_name": "115",
      "short_name": "115",
      "types": [ "street_number" ]
    }, {
      "long_name": "Chestnut St",
      "short_name": "Chestnut St",
      "types": [ "route" ]
    }, {
      "long_name": "Upton",
      "short_name": "Upton",
      "types": [ "locality", "political" ]
    }, {
      "long_name": "Upton",
      "short_name": "Upton",
      "types": [ "administrative_area_level_3", "political" ]
    }, {
      "long_name": "Worcester",
      "short_name": "Worcester",
      "types": [ "administrative_area_level_2", "political" ]
    }, {
      "long_name": "Massachusetts",
      "short_name": "MA",
      "types": [ "administrative_area_level_1", "political" ]
    }, {
      "long_name": "United States",
      "short_name": "US",
      "types": [ "country", "political" ]
    }, {
      "long_name": "01568",
      "short_name": "01568",
      "types": [ "postal_code" ]
    } ],
    "geometry": {
      "location": {
        "lat": 42.1476896,
        "lng": -71.5863099
      },
      "location_type": "RANGE_INTERPOLATED",
      "viewport": {
        "southwest": {
          "lat": 42.1445379,
          "lng": -71.5894495
        },
        "northeast": {
          "lat": 42.1508332,
          "lng": -71.5831542
        }
      },
      "bounds": {
        "southwest": {
          "lat": 42.1476815,
          "lng": -71.5863099
        },
        "northeast": {
          "lat": 42.1476896,
          "lng": -71.5862938
        }
      }
    }
  } ]
}

I run into a problem with an address such as 50 Franklin Street Boston, MA for which the google Geocoder API returns:

{
  "status": "OK",
  "results": [ {
    "types": [ "street_address" ],
    "formatted_address": "50 Franklin St, Boston, MA 02110, USA",
    "address_components": [ {
      "long_name": "50",
      "short_name": "50",
      "types": [ "street_number" ]
    }, {
      "long_name": "Franklin St",
      "short_name": "Franklin St",
      "types": [ "route" ]
    }, {
      "long_name": "Boston",
      "short_name": "Boston",
      "types": [ "locality", "political" ]
    }, {
      "long_name": "Boston",
      "short_name": "Boston",
      "types": [ "administrative_area_level_3", "political" ]
    }, {
      "long_name": "Suffolk",
      "short_name": "Suffolk",
      "types": [ "administrative_area_level_2", "political" ]
    }, {
      "long_name": "Massachusetts",
      "short_name": "MA",
      "types": [ "administrative_area_level_1", "political" ]
    }, {
      "long_name": "United States",
      "short_name": "US",
      "types": [ "country", "political" ]
    }, {
      "long_name": "02110",
      "short_name": "02110",
      "types": [ "postal_code" ]
    } ],
    "geometry": {
      "location": {
        "lat": 42.3556540,
        "lng": -71.0585261
      },
      "location_type": "ROOFTOP",
      "viewport": {
        "southwest": {
          "lat": 42.3525064,
          "lng": -71.0616737
        },
        "northeast": {
          "lat": 42.3588016,
          "lng": -71.0553785
        }
      }
    }
  }, {
    "types": [ "street_address" ],
    "formatted_address": "50 Franklin St, Boston, MA 02122, USA",
    "address_components": [ {
      "long_name": "50",
      "short_name": "50",
      "types": [ "street_number" ]
    }, {
      "long_name": "Franklin St",
      "short_name": "Franklin St",
      "types": [ "route" ]
    }, {
      "long_name": "Boston",
      "short_name": "Boston",
      "types": [ "locality", "political" ]
    }, {
      "long_name": "Boston",
      "short_name": "Boston",
      "types": [ "administrative_area_level_3", "political" ]
    }, {
      "long_name": "Suffolk",
      "short_name": "Suffolk",
      "types": [ "administrative_area_level_2", "political" ]
    }, {
      "long_name": "Massachusetts",
      "short_name": "MA",
      "types": [ "administrative_area_level_1", "political" ]
    }, {
      "long_name": "United States",
      "short_name": "US",
      "types": [ "country", "political" ]
    }, {
      "long_name": "02122",
      "short_name": "02122",
      "types": [ "postal_code" ]
    } ],
    "geometry": {
      "location": {
        "lat": 42.2871370,
        "lng": -71.0400105
      },
      "location_type": "ROOFTOP",
      "viewport": {
        "southwest": {
          "lat": 42.2839894,
          "lng": -71.0431581
        },
        "northeast": {
          "lat": 42.2902846,
          "lng": -71.0368629
        }
      }
    }
  }, {
    "types": [ "street_address" ],
    "formatted_address": "50 Franklin St, Boston, MA 02129, USA",
    "address_components": [ {
      "long_name": "50",
      "short_name": "50",
      "types": [ "street_number" ]
    }, {
      "long_name": "Franklin St",
      "short_name": "Franklin St",
      "types": [ "route" ]
    }, {
      "long_name": "Boston",
      "short_name": "Boston",
      "types": [ "locality", "political" ]
    }, {
      "long_name": "Boston",
      "short_name": "Boston",
      "types": [ "administrative_area_level_3", "political" ]
    }, {
      "long_name": "Suffolk",
      "short_name": "Suffolk",
      "types": [ "administrative_area_level_2", "political" ]
    }, {
      "long_name": "Massachusetts",
      "short_name": "MA",
      "types": [ "administrative_area_level_1", "political" ]
    }, {
      "long_name": "United States",
      "short_name": "US",
      "types": [ "country", "political" ]
    }, {
      "long_name": "02129",
      "short_name": "02129",
      "types": [ "postal_code" ]
    } ],
    "geometry": {
      "location": {
        "lat": 42.3785674,
        "lng": -71.0668132
      },
      "location_type": "RANGE_INTERPOLATED",
      "viewport": {
        "southwest": {
          "lat": 42.3754150,
          "lng": -71.0699535
        },
        "northeast": {
          "lat": 42.3817103,
          "lng": -71.0636583
        }
      },
      "bounds": {
        "southwest": {
          "lat": 42.3785579,
          "lng": -71.0668132
        },
        "northeast": {
          "lat": 42.3785674,
          "lng": -71.0667986
        }
      }
    }
  }, {
    "types": [ "street_address" ],
    "formatted_address": "50 Franklin St, Boston, MA 02136, USA",
    "address_components": [ {
      "long_name": "50",
      "short_name": "50",
      "types": [ "street_number" ]
    }, {
      "long_name": "Franklin St",
      "short_name": "Franklin St",
      "types": [ "route" ]
    }, {
      "long_name": "Boston",
      "short_name": "Boston",
      "types": [ "locality", "political" ]
    }, {
      "long_name": "Boston",
      "short_name": "Boston",
      "types": [ "administrative_area_level_3", "political" ]
    }, {
      "long_name": "Suffolk",
      "short_name": "Suffolk",
      "types": [ "administrative_area_level_2", "political" ]
    }, {
      "long_name": "Massachusetts",
      "short_name": "MA",
      "types": [ "administrative_area_level_1", "political" ]
    }, {
      "long_name": "United States",
      "short_name": "US",
      "types": [ "country", "political" ]
    }, {
      "long_name": "02136",
      "short_name": "02136",
      "types": [ "postal_code" ]
    } ],
    "geometry": {
      "location": {
        "lat": 42.2526044,
        "lng": -71.1332635
      },
      "location_type": "RANGE_INTERPOLATED",
      "viewport": {
        "southwest": {
          "lat": 42.2494625,
          "lng": -71.1364052
        },
        "northeast": {
          "lat": 42.2557577,
          "lng": -71.1301100
        }
      },
      "bounds": {
        "southwest": {
          "lat": 42.2526044,
          "lng": -71.1332635
        },
        "northeast": {
          "lat": 42.2526158,
          "lng": -71.1332517
        }
      }
    },
    "partial_match": true
  } ]
}

And my script returns:

NULL 
NULL

Any ideas what might be going on? Thanks!

Was it helpful?

Solution

It's quite possible that the response gets over 10k characters, in that case you're trying to decode an invalid JSON string. Make sure you're reading the whole stream before decoding. The simplest way is to use file_get_contents instead of fopen/fread/fclose. On the long run you should switch to curl.

OTHER TIPS

For me your string are decoded perfectly. Maybe the response are encoding in UTF-8 and exist a B.O.M (Byte Order Mark) character in the string. In this case, the string is not correctly a JSON formated structure (see RFC 4627).

In his place I would write a few more lines to see if this is the problem. You can strip B.O.M characteres packing CCC inna bynary string. Call this function recursively:

function removeBOM($str=""){
        if(substr($str, 0,3) == pack("CCC",0xef,0xbb,0xbf)) {
                $str=substr($str, 3);
        }
        return $str;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top