Jan 15, 2012

Google Maps Server Side Geocoding Using PHP and Infobox Fully AJAX

Recently I got a new project of real estate where I had to display about 1000 of projects on the google map. I was having the address of 1000 projects, so I started with my php and js code. When I coded and started testing, I found that on the map only 20-30 markers were shown. When I debugged I found an error of OVER_QUERY_LIMIT. I started googling and found that Geocoding has some limitations on converting address into lat long. In API there are two ways of getting LAT LONG.

  • Client Side

  • Server Side


Client side geocoding has some limitation of 20 queries per minute or sec. Server side geocoding also has limitations but after 2500 queries.

google-map

 

So in this tutorial we will first code our simple HTML then PHP and finally our AJAX.

HTML is pretty short and simple.

Filename: index.php

 
[html]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Google Server Side Geocoding Using PHP and Infobox Fully AJAX</title>

<style>
#wrapper{width:1002px; margin:0px auto;}
#loading {
position: relative;
text-align: center;
top: 45%;
}
</style>

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false&language=en"></script>
<script type="text/javascript" src="http://google-maps-utility-library-v3.googlecode.com/svn-history/r290/trunk/infobox/src/infobox.js"></script>
<script type="text/javascript" src="http://localhost:8080/gmap/google.js"></script>

</head>

<body>
<div id="wrapper">
<div id="googlemaps" style="width:500px; height:500px;position:relative;border:1px solid #888888;margin: 0 auto;">
</div>
</div>
</body>
</html>
[/html]
 

Here we are leaving a blank div, which will be filled with our google map.

In our PHP code, we can call the addresses either from database or an array. I am using array in this tutorial.

In server side geocoding we actually pass our address through an URL which returns a CSV or json formatted data.

Then we extract the lat long from this data using explode function and store it in an array. This array is passed to our AJAX function in json formatted.

Filename: gmap.php
 
[php]
<?php
$address = array(
"1" => array("Address" => "Bandra, Mumbai, India" , "Name" => "Bandra"),
"2" => array("Address" => "Khar, Mumbai, India" , "Name" => "Khar"),
"3" => array("Address" => "Santacruz, Mumbai, India" , "Name" => "Santacruz"),
"4" => array("Address" => "Andheri, Mumbai, India" , "Name" => "Andheri"),
"5" => array("Address" => "Jogeshwari, Mumbai, India" , "Name" => "Jogeshwari"),
"6" => array("Address" => "Goregaon, Mumbai, India" , "Name" => "Goregaon"),
"7" => array("Address" => "Malad, Mumbai, India" , "Name" => "Malad"),
"8" => array("Address" => "Kandivili, Mumbai, India" , "Name" => "Kandivili"),
"9" => array("Address" => "Borivali, Mumbai, India" , "Name" => "Borivali"),
"10" => array("Address" => "Dahisar, Mumbai, India" , "Name" => "Dahisar"),
"11" => array("Address" => "Mira Road, Mumbai, India" , "Name" => "Mira Road"),
"12" => array("Address" => "Bhayander, Mumbai, India" , "Name" => "Bhayander"),
"13" => array("Address" => "Naigaon, Mumbai, India" , "Name" => "Naigaon"),
"14" => array("Address" => "Vasai, Mumbai, India" , "Name" => "Vasai"),
"15" => array("Address" => "Nallasopara, Mumbai, India" , "Name" => "Nallasopara"),
"16" => array("Address" => "Virar, Mumbai, India" , "Name" => "Virar"),
"17" => array("Address" => "Churchgate, Mumbai, India" , "Name" => "Churchgate"),
"18" => array("Address" => "Charni Road, Mumbai, India" , "Name" => "Charni Road"),
"18" => array("Address" => "Grant Road, Mumbai, India" , "Name" => "Grant Road"),
"19" => array("Address" => "Dadar, Mumbai, India" , "Name" => "Dadar"),
"20" => array("Address" => "Mahim, Mumbai, India" , "Name" => "Mahim"),
"21" => array("Address" => "King Circle, Mumbai, India" , "Name" => "King Circle"),
"22" => array("Address" => "Worli, Mumbai, India" , "Name" => "Worli"),
);

foreach($address as $Idx => $key){
$addr = urlencode($key['Address']);
$url = 'http://maps.google.com/maps/geo?q='.$addr.'&output=csv&sensor=false';
$get = file_get_contents($url);
$records = explode(",",$get);
$lat = $records['2'];
$lng = $records['3'];

$data[] = array('Lat'=>$lat, 'Lng'=>$lng, 'Name'=>$key['Name']);

}
echo json_encode($data);
?>
[/php]
 

Now we call our ajax function on the load of the page.

Filename: google.js

 
[js]
jQuery(function($) {
$(document).ready(function() {
getAdress();//On page load initialize our map function.
});
});
[/js]
 

We will use infobox to create stylish markers and windows. When we load our function on page load, this function consists with an AJAX call, which gets the data from our gmap.php file, which will be in JSON formatted. We convert it into normal array using JSON.parse(). Finally we throw this array into foreach loop and store the lat, long values in a variable.

 

These lat long variables are also an array so one more for loop and then we pass it to our createmarker function which will be creating the markers on map.

Filename: google.js

 
[js]
function getAdress() {
jQuery(function($) {
$("#googlemaps").html('<div id="loading"><img src="loading.gif" /></div>');
$.ajax( {
url : "gmap.php",
type : "GET",
success : function(data) {
// get the data string and convert it to a JSON object.
var jsonData = JSON.parse(data);
var latitude = new Array();
var longitude = new Array();
var name = new Array();
var logo = new Array();
var i = 0;
var j = 0;
var k = 0;
$.each(jsonData, function(Idx, Value) {
$.each(Value, function(x, y) {
//Creating an array of latitude, logitude
if(x == 'Lat')
{
i = i + 1;
latitude[i] = y;
}
if(x == 'Lng')
{
j = j + 1;
longitude[j] = y;
}
if(x == 'Name')
{
k = k + 1;
name[k] = y;
}
});
});
$("#googlemaps").html('');
//passing the array to initialize function, where our map will be formed
initialize(latitude,longitude,name, logo);
}
});
});
}
function initialize(latitude,longitude, name, logo) {

//initialization of map.
var geocoder = new google.maps.Geocoder();
var initCenter = new google.maps.LatLng(19.0759837, 72.87765590000004);//By default Mumbai is loaded
var map = new google.maps.Map(document.getElementById('googlemaps'), {
zoom: 11,
center: initCenter,
mapTypeId: google.maps.MapTypeId.ROADMAP
});

//initialization of infowindow
var infoWindow = new google.maps.InfoWindow;
var boxText = document.createElement("div");

var j = 1;
var image = new google.maps.MarkerImage('icon-home.gif');//Setting the marker image

//Infowindow is fully customizable, here we make our infowindow stylish by adding css styles to it.

var myOptions = {
content: boxText
,disableAutoPan: false
,maxWidth: 181
,zIndex: null
,boxStyle: {
background: "#000000"
,color: "#fff"
,width: "auto"
,padding: "10px"
,borderRadius: "20px"
,fontFamily: "Tahoma"
,opacity: "0.5"
}
,infoBoxClearance: new google.maps.Size(1, 1)
,isHidden: false
,pane: "floatPane"
,closeBoxURL: ""
,enableEventPropagation: false
};
var ib = new InfoBox(myOptions);

//Final for loop for creating the markers
for(var a = 1; a < latitude.length; ++a)
{
createMarkers(geocoder, map, name[a], latitude[a], longitude[a], ib, image);
}
}


function createMarkers(geocoder, map, name, latitude, longitude, ib, image) {

//Setting the onclick marker function
var onMarkerClick = function() {
var marker = this;
var latLng = marker.getPosition();
ib.setContent(name);
ib.open(map, marker);
};

google.maps.event.addListener(map, 'click', function() {
ib.close();
});

//In array lat long is saved as an string, so need to convert it into int.
var lat = parseFloat(latitude);
var lng = parseFloat(longitude);

var marker = new google.maps.Marker({
map: map,
icon: image,
position: new google.maps.LatLng(lat, lng),
title: name
});

//Adding the marker.
google.maps.event.addListener(marker, 'click', onMarkerClick);
}
[/js]
 

This above js file can be minified further, there are other ways of getting the data, but I found this very simple and easy. You can check the live demo. Any suggestions are welcome. Happy geocoding

34 comments :

  1. I try your codehere but not working . http://booksface.com/google/ kindly tell me problem .
    Thanks

    ReplyDelete
  2. look at your code, its calling wrong JS file,
    change this line
    http://localhost:8080/gmap/google.js

    download the files again, I have updated from localhost to actual file.

    ReplyDelete
  3. Hello, I tried to run your package on godaddy and it did not work- "loading" icon is displayed, but nothing else comes up. Are your sources correct?

    ReplyDelete
  4. Nirajmchauhan26/1/12 7:13 PM

    Can you give me the link of your live site where you tried this

    ReplyDelete
  5. Can you give me the link of your live site where you tried this

    ReplyDelete
  6. OK, this is what I got:

    Thank you for contacting Online Support. I
    apologize for any confusion in the previous response. JSON and JSON encoding is
    not supported on our shared (godaddy.com) hosting accounts. You would need a virtual
    dedicated or dedicated server for this. We apologize for any inconvenience.

    Please let us know if we can assist you in any other way.

    Regards,
    Mitchell P.
    Online Support

    ReplyDelete
  7. Which means that you have a problem with your server, try it on your localhost, it will work for sure. Try to get a new shared server.

    ReplyDelete
  8. I have a quetion, I need to pass a dinamic variable from index.php to gmap.php - how can I do that? Thank you!

    ReplyDelete
  9. You can easily do that by passing that dynamic variable to the json _encode line comma separated

    ReplyDelete
  10. Hello, I am just started doing java and who thing, so it is very hard for me to complethand. For example, I have a value $DT="hello world" in my index.php, I am not sure how can I use json to pass it into gmap.php. Could you please assit?

    ReplyDelete
  11. I believe that you want to access the $DT value in the javascript, so if you want to do that,

    $DT="hello world";
    $data[] = array('Lat'=>$lat, 'Lng'=>$lng, 'Name'=>$key['Name'], 'DT'=>$DT)

    then in javascript you access this inside the loop

    ReplyDelete
  12. Excellent! This is what I'm looking for! Works out of the box. Thanks for sharing! Thumbs up!

    ReplyDelete
  13. Thank you, worked great and just want I needed!!

    ReplyDelete
  14. THis seems to have the same problem of timing out after 9-10 requests - I don't think the problem is solved by moving the geocoding to the server in this way - Google still detects too many requests coming from the same IP.

    ReplyDelete
  15. It does, when you use client side geocoding it limits around 6-7 queries per time but in server side you can query around 2500 queries per minute. This is the reason of using server side rather then using client side.

    ReplyDelete
  16. Hmm I'm not sure what I'm doing wrong - it seems to accept 10-11 queries, then die for the next ~10, then accept another 10-11, etc. I'm not using AJAX though, but the PHP code is the same.

    How does Google know it's server-side? Is it just the fact you're using the URL instead of the javascript geocode() method?

    ReplyDelete
  17. Getting lat long using this URL  'http://maps.google.com/maps/geo?q=Mumbai&output=csv&sensor=false'  is server side geocoding.

    you can read more about it over here:
    http://code.google.com/apis/maps/articles/geocodestrat.html#client

    You might be doing some thing wrong, can you show me your work, where I can debug it?

    ReplyDelete
  18. hi, i tried to use the same code for gmap.php that you use in your download, but when i try to test it gmap.php doesn´t load in my browser

    ReplyDelete
  19. Do you have any live example, I ll have to check. See your firebug console for errors.

    ReplyDelete
  20. Schadrachyeye27/5/12 9:16 PM

    When i test your code chrome's terminal return this error 
    Uncaught SyntaxError: Unexpected token <

    ReplyDelete
  21. I tested it in chrome, its not giving me any error.

    ReplyDelete
  22. Saumya Suhagiya12/7/12 6:41 AM

    good article

    ReplyDelete
  23. First off... very nice script... it is a big help. This may have been covered below but I'm not sure... and i have spent a considerable amount of time trying to figure this out myself inan attempt to understand this better... (I know a lot about PHP but not so much about javascript I'm afraid)


    I need to pass PHP array generated in my index.php page to the gmap.php file on the server to build the array of locations based on a user defined ZIP code and radius... (the array I need to pass contains the distance & ZIP code pairs to query....)


    How would I do that in the "getAdress()" function?


    Russ

    ReplyDelete
  24. You can do this, in index.php echo your array in json_encode function inside a textbox. By default dont show this textbox, set its unique id. In jquery get the entire json values inside a variable. Var addr = $('#address').html();

    Thats it now you can pass this inside gmap.php using ajax function.

    ReplyDelete
  25. Hi, first of all thanks.
    I was performing the task using a manually generated array in js, but reaching the limit, even with a timeout (200ms) on the geocoder function. so I resolved myself to try the ajax solution, but the problem is still there. after 20 or so server-side requests google simply shut the communication down with annoying 620,0,0,0 responses...
    I'm aware of the 2500 req/day limit and sure I did not passed it.
    The problem seems to be in the req/sec limit, if I ask sleep(1) to my loop into the addresses, the problem disappears.
    so? nothing... work in progress... ideas?

    UPDATE: I also tried with usleep(100) and it works, for, let's say, some 40-50 requests, but it can not be a nice solutions, can it?

    UPDATE 2: I checked out your demo, you seem to have the same problem I have:
    the google response to your script:

    0: {Lat:19.0552290, Lng:72.8308290, Name:Bandra}
    1: {Lat:19.0707260, Lng:72.8361270, Name:Khar}
    2: {Lat:19.0799983, Lng:72.8545019, Name:Santacruz}
    3: {Lat:19.1154908, Lng:72.8726952, Name:Andheri}
    4: {Lat:19.1405116, Lng:72.8421555, Name:Jogeshwari}
    5: {Lat:19.1590077, Lng:72.8692711, Name:Goregaon}
    6: {Lat:19.1889733, Lng:72.8220064, Name:Malad}
    7: {Lat:19.2050017, Lng:72.8692711, Name:Kandivili}
    8: {Lat:19.2300880, Lng:72.8666480, Name:Borivali}
    9: {Lat:19.2539332, Lng:72.8672448, Name:Dahisar}
    10: {Lat:0, Lng:0, Name:Mira Road}
    11: {Lat:0, Lng:0, Name:Bhayander}
    12: {Lat:0, Lng:0, Name:Naigaon}
    13: {Lat:0, Lng:0, Name:Vasai}
    14: {Lat:19.4164084, Lng:72.8194579, Name:Nallasopara}
    15: {Lat:19.3926740, Lng:72.8616430, Name:Virar}
    16: {Lat:18.9322453, Lng:72.8264378, Name:Churchgate}
    17: {Lat:18.9629992, Lng:72.8175748, Name:Grant Road}
    18: {Lat:19.0214051, Lng:72.8426858, Name:Dadar}
    19: {Lat:19.0384380, Lng:72.8419909, Name:Mahim}
    20: {Lat:19.0268086, Lng:72.8559369, Name:King Circle}
    21: {Lat:19.0166667, Lng:72.8166667, Name:Worli}

    ReplyDelete
  26. There is some error in the UPDATE 3... but well, I've been reported as an abuse :(

    ReplyDelete
  27. How can I post multiple <div id="googlemaps" on one page?

    ReplyDelete
  28. Nice post, but it wont help, google randomly replies with correct lat/lang or just zero. Enter gmap.php as url and there you go, random result in the source. But thanks alot anyway.

    ReplyDelete
  29. go to that line where the error occurs and copy that part in a blank new editor window (i use notepad++). then you can see a "?"-sign.. delete it, copy the code back again and everything is fine..

    ReplyDelete
  30. Like Davide Giamboni said, i'm getting the 620 responses which is the same as OVER_QUERY_LIMIT. Do you have some source from Google which explicitly said "Client side geocoding has some limitation of 20 queries per minute or sec. Server side geocoding also has limitations but after 2500 queries." ?

    ReplyDelete
  31. Have you hosted your code somewhere? Cause mine code still works in demo, and how much queries are you sending to server?

    ReplyDelete
  32. shreekanta panigrahi21/2/13 6:27 PM

    vary good website

    ReplyDelete
  33. shreekanta panigrahi21/2/13 6:28 PM

    having same problem like siaminou...also want to use map ovarlay to show only the map of sweden country.

    ReplyDelete
  34. It doesn't seem to be working anymore... All points are located in 0,0 ...
    Any update please ?

    ReplyDelete