Using the Google Maps API in PHP

AID: 3350
  • Status: Published

21166 points

  • ByRay_Paseur
  • TypeGeneral
  • Posted on2010-06-30 at 08:09:33
Awards
  • Experts Exchange Approved

You can use the Google Maps API to easily draw "static" maps.  This lets you present location-aware information to your web and mobile clients.  Static Maps have a great advantage - they are rendered as a standard image.  There is no Javascript or CSS needed.  This means they are immediately useful on almost any browser and on almost any device.

Don't let the term "static" fool you -- this is a powerful mapping system.  You can add markers, icons, paths, polygons and more to the maps.  The maps are easy to draw because Google does all the heavy lifting.  Your only requirement is to prepare a standard HTML <img /> tag that sends the data to the Google API.  Google returns a PNG image (other image types are available, too) containing the map, markers and other characteristics that you have requested.  The width and height of the map are completely under your control (up to the Google limits, currently 640px), so your page design is easily accommodated.  And there are special features for mobile customers.

To get started, you might want to look over the Google man pages here:
http://code.google.com/apis/maps/documentation/staticmaps/

Once you have read that, you know everything that will be demonstrated in this article, and more.

The usefulness of your map and markers will depend on three principal components.  These are the zoom level, center point, and the size of the map image.  In Google Maps, zoom level numbers increase as you get closer to the earth.  A map that has too low a zoom level number may show too much area to give needed detail.  A map with too high a zoom level number may not be big enough to show all the markers you have placed.  There is no error message; out-of-bounds markers are simply off the chart.

Let's start with a simple example -- a class that will return the HTML <img /> tag.  We will create an object with some default settings, and we have setters to change the most important properties of the object.  You might want to add your own twist to this class, including your custom icons, or setting your preferred default location for the center of the map.  You might also want to extend the class to add more methods.  Here are a couple of the most important functions.

The setCenter() method establishes the geographic center point for the map.  You might or might not place a marker here.  If you are creating a map that shows a client's home location and nearby stores, you might want to use setCenter() to center the map as close as possible to the client location.  If all you have for the client location is a ZIP code, it might be best to omit the marker, since it is unlikely that the ZIP code is an exact pointer to the client address.

The setMarker() and setIcon() methods place visual cues on the map.  You can set the marker locations by a variety of data types.  If you know the "geocode" (latitude, longitude) you can use these numbers to place the marker.  You can also place the marker by naming a famous spot ("The White House") or by a landmark in a city ("Landon School, Bethesda MD") or by a street address and ZIP code.

Or even just a ZIP code.  ZIP codes are not exact locations (they are postal carrier routes) but often a ZIP code is good enough to get an approximate location.  ZIP codes are often used to answer the question, "Where are the nearest stores?"

If you use anything other than the geocode, you need to be aware that Google may be "creative" in the way it interprets place names.  For example, try using "THE US CAPITOL" as a center point.  You may find that you really want, "THE US CAPITOL, WASHINGTON DC" instead.  Generally more detail is better when you are giving a text description of a location to Google Maps.

Custom icons provide us with a cool way to decorate our maps.  Your icons can be up to 64x64 pixels (which is relatively large since the largest map is 640x640) and you can have up to five different icons on each map (you can have more than 5 icons just no more than 5 different icons).  To use a custom icon, you provide the Google Maps API with the fully qualified urlencoded URL of the icon file.

The code snippet shows a class that will call the Google Static Map API.  A couple of examples are there to help you get started using the API.

Note the use of the urlencode(urldecode()) functions in the setter methods.  The intent of this decode-encode construct is to allow the geocodes or addresses or place names to be set without regard to the state of their encoding.  These values become part of the URL sent to the Google Static Map API, so they must be urlencode() strings.  In my test cases this double function never caused any problems, but it is one of those "interesting" programming steps that merits a moment of thought before it is put into use, especially if your script feeds external data to this class.

<?php // RAY_google_static_map_class.php
error_reporting(E_ALL);

// DEMONSTRATE HOW TO USE THE GOOGLE MAPS API
// FOR A STATIC MAP OF SPECIFIC SIZE
// OPTIONAL CENTERED PUSHPIN
// OPTIONAL OTHER PUSHPIN(S) OR ICONS
// MAN PAGE: http://code.google.com/apis/maps/documentation/staticmaps/

// DEFINE THE GOOGLE STATIC MAPPING CLASS
class GSM
{
    // THE MAP CENTER GEOCODE, ADDRESS OR LANDMARK
    protected $center;

    // MARKER DATA ARRAY
    protected $markers;
    protected $default_icon;

    // OUR VARIABLES FOR THE MAP DISPLAY
    protected $maptype;
    protected $width;
    protected $height;
    protected $zoom;
    protected $format;

    // OUR VARIABLES FOR THE GOOGLE URL AND IMAGE TAG
    protected $alt;
    protected $title;
    protected $class;
    protected $id;
    protected $usemap;
    protected $sensor;
    protected $url;
    private $img;

    // A CONSTRUCTOR TO SET THE DEFAULT VALUES
    public function __construct()
    {
        // THE URL AND IMG TAG PARAMETERS
        $this->alt    = FALSE;
        $this->class  = FALSE;
        $this->id     = FALSE;
        $this->usemap = FALSE;
        $this->sensor = FALSE;
        $this->title  = TRUE;
        $this->url    = '';
        $this->img    = '';

        // THE CENTER AND ZOOM SCALE OF THE MAP (IF OMITTED, GOOGLE WILL CALCULATE)
        $this->center  = NULL;
        $this->zoom    = NULL;

        // THE CHARACTERISTICS OF THE MAP IMAGE
        $this->maptype = 'hybrid';    // CHOOSE
        $this->maptype = 'terrain';   // AMONG
        $this->maptype = 'satellite'; // THESE
        $this->maptype = 'roadmap';   // OPTIONS
        $this->width   = '640';
        $this->height  = '640';
        $this->format  = 'png';

        // THE DEFAULT ICON
        $this->default_icon = 'http://maps.google.com/mapfiles/ms/micons/question.png';

        // AN ARRAY OF MARKER ARRAYS
        $this->clearMarkers();

    } // END CONSTRUCTOR

    // A METHOD TO CLEAR THE MARKERS
    public function clearMarkers()
    {
        $this->markers = array();
    }

    // A SETTER TO ADD MARKERS TO THE MAP
    public function setMarker($geocode, $color='blue', $label='X')
    {
        // NOTE THAT THIS WILL WORK CORRECTLY MOST OF THE TIME
        $geocode = urlencode(urldecode($geocode));
        $this->markers[]
        = array
        ( 'color'   => $color
        , 'label'   => $label
        , 'geocode' => $geocode
        , 'icon'    => FALSE
        )
        ;
    }

    // A SETTER TO ADD ICONS TO THE MAP - VIEW SOURCE HERE: http://www.visual-case.it/cgi-bin/vc/GMapsIcons.pl
    public function setIcon($geocode, $icon=FALSE)
    {
        // NOTE THAT THIS WILL WORK CORRECTLY MOST OF THE TIME
	    $geocode = urlencode(urldecode($geocode));
        if (!$icon) $icon = $this->default_icon;
        $this->markers[]
        = array
        ( 'color'   => FALSE
        , 'label'   => FALSE
        , 'geocode' => $geocode
        , 'icon'    => $icon
        )
        ;
    }

    // A SETTER TO OVERRIDE EACH OF THE DEFAULT VALUES
    public function setCenter($geocode=NULL)
    {
        // NOTE THAT THIS WILL WORK CORRECTLY MOST OF THE TIME
	    $geocode = urlencode(urldecode($geocode));
        $this->center = $geocode;
    }
    public function setMaptype($x)
    {
        $this->maptype = $x;
    }
    public function setFormat($x)
    {
        $this->format = $x;
    }
    public function setWidth($x)
    {
        $this->width = $x;
    }
    public function setHeight($x)
    {
        $this->height = $x;
    }
    public function setZoom($x=NULL)
    {
        $this->zoom = $x;
    }
    public function setAlt($x=FALSE)
    {
        $this->alt = $x;
    }
    public function setTitle($x=TRUE)
    {
        $this->title = $x;
    }
    public function setClass($x=FALSE)
    {
        $this->class = $x;
    }
    public function setId($x=FALSE)
    {
        $this->id = $x;
    }
    public function setUsemap($x=FALSE)
    {
        $this->usemap = $x;
    }
    public function setSensor($x=FALSE)
    {
        $this->sensor = $x;
    }

    // A METHOD TO PREPARE AND RETRIEVE THE MAPPING URL
    public function asURL()
    {
        $s = 'false'; // SEE http://code.google.com/apis/maps/documentation/staticmaps/#Sensor
        if ($this->sensor) $s = 'true';

        // IF ICONS OR MARKERS ARE ON THE MAP, 'IMPLODE' THE DATA INTO THE URL
        $marker_string = '';
        foreach ($this->markers as $marker)
        {
            // PROCESS FOR CUSTOM ICONS
            if ($marker['icon'])
            {
                $marker_string
                = $marker_string
                . '&markers='
                . 'icon:'
                . urlencode($marker['icon'])
                . '|'
                . $marker['geocode']
                ;
                continue;
            }
            // PROCESS FOR STANDARD MARKERS
            $marker_string
            = $marker_string
            . '&markers='
            . 'color:'
            . $marker['color']
            . '|'
            . 'label:'
            . $marker['label']
            . '|'
            . $marker['geocode']
            ;
        }

        // SET CENTER AND ZOOM, IF PRESENT
        $c = '';
        if ($this->center) $c = "&center=$this->center";
        $z = '';
        if ($this->zoom)   $z = "&zoom=$this->zoom";

        // MAKE THE URL
        $this->url
        = "http://maps.google.com/maps/api/staticmap?sensor=$s"
        . $c
        . $z
        . "&size=$this->width" . 'x' . "$this->height"
        . "&format=$this->format"
        . "&maptype=$this->maptype"
        . "$marker_string"
        ;
        return $this->url;
    }

    // A METHOD TO PREPARE AND RETRIEVE THE HTML IMAGE TAG
    public function asIMG()
    {
        // GET THE URL
        if (!$this->url) $this->url = $this->asURL();

        // GET THE ALT TEXT
        $a = "$this->maptype" . ' centered ' . "$this->center";
        if ($this->alt !== FALSE) $a = $this->alt;

        // REQUIRED FIELDS
        $this->img = '<img src="' . $this->url . '" alt="' . $a . '"';

        // OPTIONAL FIELDS - PROVIDE A DEFAULT TITLE
        $t = "$this->maptype" . ' centered ' . "$this->center";
        if     ($this->title  === TRUE ) { $this->img .= ' title="' . $t .           '"'; }
        elseif ($this->title !== FALSE)  { $this->img .= ' title="' . $this->title . '"'; }

        // OPTIONAL FIELDS MAY BE OMITTED
        if ($this->class  !== FALSE) { $this->img .= ' class="'  . $this->class  . '"'; }
        if ($this->id     !== FALSE) { $this->img .= ' id="'     . $this->id     . '"'; }
        if ($this->usemap !== FALSE) { $this->img .= ' usemap="' . $this->usemap . '"'; }

        // CLOSE THE IMAGE TAG AND CLEAR THE CONSUMED URL
        $this->img .= ' />';
        $this->url = FALSE;
        return $this->img;
    }
} // END CLASS



// MAKE A GOOGLE STATIC MAP OBJECT AND TEST IT OUT
$x = new GSM;
$x->setWidth(620);
$x->setHeight(620);
$x->setZoom(12);

// SET A CENTER POINT (BUT NO MARKER) BY LANDMARK NAME ALONE
// $x->setCenter("THE WHITE HOUSE");

// SET A MARKER BY GEOCODE (LAT/LON PAIR)
$x->setMarker("38.930387,-77.147777", 'green', 'H');

// SET A MARKER BY PLACE NAME, CITY, STATE
$x->setMarker("Landon School, Bethesda, MD", 'brown', 'L');

// SET A MARKER BY STREET ADDRESS AND ZIP CODE
$x->setMarker("6327 Everglades Drive 22312", 'orange', 'P');

// ECHO THE <img /> TAG INTO OUR HTML TO DRAW THE MAP
echo $x->asIMG();
echo PHP_EOL . '<br clear="all" />';

// SHOW THE OBJECT
echo "<pre>" . PHP_EOL;
print_rr($x);
echo"</pre>" . PHP_EOL;

// USE THE GSM OBJECT TO DRAW ANOTHER MAP WITH A SWIMMER IN THE TIDAL BASIN
$x->clearMarkers();
$x->setZoom();
$x->setWidth(500);
$x->setHeight(400);
$x->setCenter("THE US CAPITOL, WASHINGTON DC");
$x->setMarker("THE WHITE HOUSE", 'red', 'W');
$x->setMarker("THE US CAPITOL, WASHINGTON DC", 'blue', 'C');
$x->setIcon("THE TIDAL BASIN, WASHINGTON DC", 'http://maps.google.com/mapfiles/ms/micons/swimming.png', 'false'); // NO SHADOW
echo $x->asIMG();

// SHOW THE OBJECT
echo "<pre>" . PHP_EOL;
print_rr($x);
echo"</pre>" . PHP_EOL;



// UNRELATED FUNCTION TO MAKE THE OUTPUT OMIT THE PRIVATE PROPERTIES
function print_rr($thing)
{
    $str = print_r($thing, TRUE);
    $arr = explode(PHP_EOL, $str);
    $num = count($arr) - 1;
    foreach ($arr as $ptr => $txt)
    {
        if (preg_match('/:private]/', $txt))
        {
            unset($arr[$ptr]);
        }
    }
    echo implode(PHP_EOL, $arr);
}
                                  
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
305:
306:
307:

Select allOpen in new window

Asked On
2010-06-30 at 08:09:33ID3350
Tags

GIS

,

GPS

,

Geocode

,

Map

,

Location

,

Mobile

,

Proximity

,

PHP

Topic

PHP Scripting Language

Views
4197

Comments

Expert Comment

by: b0lsc0tt on 2010-07-02 at 17:30:34ID: 16557

Great article and thanks for the excellent code.  I have really enjoyed Google Maps and it is good to have such a useful thing pointed out and explained so well.  Thanks for the contribution and time writing it!

I am curious, do you find you use the Javascript Maps version at all anymore?  If so, for what?  It seems the static can provide most of what I use to do with the Javascript.  Did you notice a change in your pages if you changed the code from Javascript to just static?

bol

Author Comment

by: Ray_Paseur on 2010-07-02 at 19:00:23ID: 16562

Hi, B0L.  Yes, I still use the javascript-driven "active" maps when I am fairly sure the browser supports JS and when I need interactivity, like zoom and the ability to move pointers with drag-and-drop.  The JS maps are not as fast as the static maps.  It is a good and interesting compromise.  Best, ~Ray

Expert Comment

by: b0lsc0tt on 2010-07-02 at 22:18:44ID: 16564

Ray,

Good point about the features that would be left out with the static image.  I had forgotten about them even though I am sure they would be something a developer may not want to omit.  As you said, a "compromise".

Sort of nice to know there is an option that could be a quick way to provide a map.  Without the need to get a key this may be something perfect for someone who just wants a simple map.

bol

Expert Comment

by: rAfridi on 2010-10-27 at 07:18:37ID: 20886

Hello Sir
This is not usefull for me .Every expert is giving same code but this is not my requirement .In this code no infoWindow display.
I want to this type functionality :

see here : http://www.ifc.org/ifcext/spiwebsite1.nsf/$$MapView?openform
Thanks and Regards
Aasim Afridi

Author Comment

by: Ray_Paseur on 2010-10-27 at 08:12:03ID: 20891

@rAfridi: I think you may want to hire a professional developer to write the code for you.  About all we can do here at EE is answer questions and post examples.  There are hundreds of lines of JavaScript in the World Bank site.  If you do "view source" and do not immediately understand the code, you should not waste your time trying to learn JavaScript on such an advanced project.  Instead, contact the World Bank and find out who developed this application.  Hire them to build your application.  You will get quick results that way.  Best of luck with it, ~Ray

Add your Comment

Please Sign up or Log in to comment on this article.

Loading Advertisement...

Top PHP Experts

  1. Ray_Paseur

    317,680

    Wizard

    3,870 points yesterday

    Profile
    Rank: Savant
  2. Roads_Roads

    77,334

    Master

    2,000 points yesterday

    Profile
    Rank: Genius
  3. maeltar

    69,800

    Master

    4,200 points yesterday

    Profile
    Rank: Guru
  4. StingRaY

    67,254

    Master

    800 points yesterday

    Profile
    Rank: Wizard
  5. DaveBaldwin

    61,691

    Master

    2,000 points yesterday

    Profile
    Rank: Genius
  6. jason1178

    37,050

    0 points yesterday

    Profile
    Rank: Genius
  7. xterm

    28,850

    0 points yesterday

    Profile
    Rank: Sage
  8. COBOLdinosaur

    27,732

    0 points yesterday

    Profile
    Rank: Genius
  9. eriksmtka

    27,641

    2,000 points yesterday

    Profile
    Rank: Master
  10. smadeira

    26,150

    2,000 points yesterday

    Profile
    Rank: Guru
  11. webmatrixpune

    23,436

    2,000 points yesterday

    Profile
    Rank: Guru
  12. logudotcom

    19,588

    1,010 points yesterday

    Profile
    Rank: Genius
  13. bportlock

    17,470

    10 points yesterday

    Profile
    Rank: Genius
  14. Derokorian

    17,368

    0 points yesterday

    Profile
    Rank: Guru
  15. maestropsm

    16,698

    3,000 points yesterday

    Profile
    Rank: Master
  16. leakim971

    16,600

    0 points yesterday

    Profile
    Rank: Genius
  17. alex_code

    16,402

    0 points yesterday

    Profile
    Rank: Guru
  18. hernst42

    14,332

    0 points yesterday

    Profile
    Rank: Genius
  19. pratima_mcs

    14,200

    0 points yesterday

    Profile
    Rank: Genius
  20. Slick812

    13,900

    0 points yesterday

    Profile
    Rank: Sage
  21. elvin66

    12,628

    0 points yesterday

    Profile
    Rank: Wizard
  22. mwvisa1

    12,400

    0 points yesterday

    Profile
    Rank: Genius
  23. zappafan2k2

    12,200

    0 points yesterday

    Profile
    Rank: Guru
  24. TerryAtOpus

    11,600

    0 points yesterday

    Profile
    Rank: Genius
  25. amar_bardoliwala

    11,500

    0 points yesterday

    Profile
    Rank: Master

Hall Of Fame