Recently I had a requirement from a client to be able to display numerous different Google maps on their website. “Simple” you might say – just use the Google Static Maps API to generate each map, and you’re done. Well, it wasn’t quite that simple. The client basically wanted to be able to generate maps on the fly, using addresses stored in a database. They then wanted to be able to pinpoint the exact location of the property using a marker. In order to be able to do that, not only do you have to give Google an address and postcode to centre the map on, but you also have to give it a Latitude and Longitude (lat/long) pair to generate the marker. To this end, I’d built a bespoke Content Management System for them, using PHP and MySQL, which enabled them to add properties to the database then display them on the site. The details stored for each property included Property Name, full address, postcode, lat/long co-ordinates etc. The client wanted it to be as easy for them to add a property as possible (don’t they always?) So the last thing they wanted to do was manually work out the lat/long for each property. So I had to build a feature into the system for them. So what would happen was:
- The client would input the full address, and click a ‘Save’ button to save the details to the database
- The system would send the address to Google’s Geocoding API (http://code.google.com/apis/maps/documentation/geocoding/)
- The API would return the data either as JSON or XML
- The system would extract the lat/long pair from the returned data, and save it into the database record for the property.
Now I’m going to show you how I did it. Hopefully it will save you some time!
How I dunnit
Step 1: Geocoding the address In the end, it was really quite simple. I used a PHP library called CURL (Client URL Library: http://php.net/manual/en/book.curl.php) to send the address data to the API. But first I had to format the address so that the API could accept it. The API requires the data in the following format:
You’ll see that all spaces in the address have to be replaced with a plus (+) sign Now, the address data I was going to use had been posted to this script, so the first thing I had to do was to go through the string, and replace all of the + signs. I did this automatically using PHP’s handy str_replace:
For non-PHP coders, what the above is doing is the replace all spaces (denoted by ” “) with pluses in the data from a field in my form called ‘addr1’. I then created a PHP variable which would hold the data $addr and did the str_replace thing on all of the address data that I needed to format. I also concatenated it together into a single string:
$address = str_replace(" ","+",$_POST['addr1']) . ",+" . str_replace(" ","+",$_POST['addr2']) . ",+" . str_replace(" ","+",$_POST['towncity']) . ",+" . str_replace(" ","+",$_POST['postcode']) . ",+UK";
Then came the good bit; using CURL to send that to Google’s API. Here’s the code I used:
//Query Google Geocoding API $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "http://maps.googleapis.com/maps/api/geocode/xml?address=".$addr."&sensor=false"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $xml = curl_exec($ch);
- The first line, curl_init() simply initiates the CURL library
- The second line (curl_setopt($ch, CURLOPT_URL…) sets the address that the data is to be sent to, and includes the formatted $address variable that we created earlier. The last parameter, ‘sensor’ is set to false. As I understand it, if you set that to true, this API can be used with GPS-enabled devices such as smart phone to give directions from the phone’s current location. But in our case, this wasn’t needed so I set it to false. It must be set to either true or false – it can’t be left blank.
- The third line, (curl_setopt($ch, CURLOPT_RETURNTRANSFER…) tells the CURL library to return the data to a variable; in this case $xml on the…
- Fourth line:
$xml = curl_exec($ch);
So at this point, I had a variable called $xml, containing an XML-formatted string of data which had been returned from Google’s API. Sweet. What I needed to do next was read the XML, and extract the bit I needed, the latitude and longitude co-ordinates. I did this using the following code:
//Use SimpleXML library to get the data from the XML string $xml = new SimpleXMLElement($xml); $lat = $xml->result->geometry->location->lat; $lng = $xml->result->geometry->location->lng; $coords = $lat . "," . $lng; curl_close($ch); //Close the CURL instance, to keep things tidy
All this did was to read the XML string into an instance of the SimpleXML library. The code on lines two and three just iterated through the XML structure until it came to the data I wanted. I stored that in two variable called $lat and $long, which I then concatenated into one variable on line 4, $coords. Lastly for this step, I stored the $coords in my database record for the property, using a standard SQL query similar to the following (thought this example is shortened): “INSERT INTO properties (coords) VALUES (‘$coords’)” Step 2: Using the geocoded data to create the marker This bit’s the easy bit. You just create an <img> tag, and give it a src attribute which includes the postcode (so the map has somewhere to centre on), and the lat/long co-ordinates for the marker:
<img class="border" src="http://maps.google.com/maps/api/staticmap?center=<?=$postcode;?>&zoom=15&size=198x198&maptype=roadmap&markers=color:red|label:A|<?=$row['coords'];?>&sensor=false" alt="" />
<?=$postcode;?> would be replaced with the postcode of the property
<?=$row[‘coords’];?> would be replaced with the value I saved in the database record. In the case of this example, it’s 40.711614,-74.012318
This breaks down as follows: http://maps.google.com/maps/api/staticmap = The API reference that tells it to use the Static Maps API center = postcode (of the property, so the API knows where to centre the map) zoom = the zoom level of the map. I think this can be between 1 (zoomed right in) to 20 (zoomed right out) size = the size (in pixels) of the <img> maptype = roadmap (can also be satellite, terrain or hybrid) markers = color:red|label:A|<coords> – Set s the label color, style (alpha or numeric) and the co-ordinates at which to place the marker.
More info on all of this can be found here: http://code.google.com/apis/maps/documentation/staticmaps/
This gives you something like:
Ta da! Pretty sweet , yes?
So hopefully you can see how to: a) Take a full address and postcode, and use it to generate a pair of lat/long co-ordinates b) Use those co-ordinates, along with the postcode, to display a map of the area, along with a marker showing the exact, accurate location of the property.
It’s not an easy process to understand, or to do, but I hope it helps someone out there. Otherwise, you’re welcome to ask me to do it for you!