Archive

Archive for May, 2008

Converting US State names into their Abbreviations (and back!)

May 24th, 2008

I’ve just had to find a way to convert a number of US state names into their abbreviations to make a clients life much easier so I thought I might share so that others wouldn’t have to go through the hassle I did.

First things first, here’s some PHP code…

function convert_state($name, $to='name') {
	$states = array(
	array('name'=>'Alabama', 'apprev'=>'AL'),
	array('name'=>'Alaska', 'apprev'=>'AK'),
	array('name'=>'Arizona', 'apprev'=>'AZ'),
	array('name'=>'Arkansas', 'apprev'=>'AR'),
	array('name'=>'California', 'apprev'=>'CA'),
	array('name'=>'Colorado', 'apprev'=>'CO'),
	array('name'=>'Connecticut', 'apprev'=>'CT'),
	array('name'=>'Delaware', 'apprev'=>'DE'),
	array('name'=>'Florida', 'apprev'=>'FL'),
	array('name'=>'Georgia', 'apprev'=>'GA'),
	array('name'=>'Hawaii', 'apprev'=>'HI'),
	array('name'=>'Idaho', 'apprev'=>'ID'),
	array('name'=>'Illinois', 'apprev'=>'IL'),
	array('name'=>'Indiana', 'apprev'=>'IN'),
	array('name'=>'Iowa', 'apprev'=>'IA'),
	array('name'=>'Kansas', 'apprev'=>'KS'),
	array('name'=>'Kentucky', 'apprev'=>'KY'),
	array('name'=>'Louisiana', 'apprev'=>'LA'),
	array('name'=>'Maine', 'apprev'=>'ME'),
	array('name'=>'Maryland', 'apprev'=>'MD'),
	array('name'=>'Massachusetts', 'apprev'=>'MA'),
	array('name'=>'Michigan', 'apprev'=>'MI'),
	array('name'=>'Minnesota', 'apprev'=>'MN'),
	array('name'=>'Mississippi', 'apprev'=>'MS'),
	array('name'=>'Missouri', 'apprev'=>'MO'),
	array('name'=>'Montana', 'apprev'=>'MT'),
	array('name'=>'Nebraska', 'apprev'=>'NE'),
	array('name'=>'Nevada', 'apprev'=>'NV'),
	array('name'=>'New Hampshire', 'apprev'=>'NH'),
	array('name'=>'New Jersey', 'apprev'=>'NJ'),
	array('name'=>'New Mexico', 'apprev'=>'NM'),
	array('name'=>'New York', 'apprev'=>'NY'),
	array('name'=>'North Carolina', 'apprev'=>'NC'),
	array('name'=>'North Dakota', 'apprev'=>'ND'),
	array('name'=>'Ohio', 'apprev'=>'OH'),
	array('name'=>'Oklahoma', 'apprev'=>'OK'),
	array('name'=>'Oregon', 'apprev'=>'OR'),
	array('name'=>'Pennsylvania', 'apprev'=>'PA'),
	array('name'=>'Rhode Island', 'apprev'=>'RI'),
	array('name'=>'South Carolina', 'apprev'=>'SC'),
	array('name'=>'South Dakota', 'apprev'=>'SD'),
	array('name'=>'Tennessee', 'apprev'=>'TN'),
	array('name'=>'Texas', 'apprev'=>'TX'),
	array('name'=>'Utah', 'apprev'=>'UT'),
	array('name'=>'Vermont', 'apprev'=>'VT'),
	array('name'=>'Virginia', 'apprev'=>'VA'),
	array('name'=>'Washington', 'apprev'=>'WA'),
	array('name'=>'West Virginia', 'apprev'=>'WV'),
	array('name'=>'Wisconsin', 'apprev'=>'WI'),
	array('name'=>'Wyoming', 'apprev'=>'WY')
	);

	$return = false;
	foreach ($states as $state) {
		if ($to == 'name') {
			if (strtolower($state['abbrev']) == strtolower($name)){
				$return = $state['name'];
				break;
			}
		} else if ($to == 'apprev') {
			if (strtolower($state['name']) == strtolower($name)){
				$return = strtoupper($state['apprev']);
				break;
			}
		}
	}
	return $return;
}

The function basically accepts a string of text ($name) and a keyword which can either be the ‘name’ or ‘abbrev’. This tells the function what you want from it (ie: if you told it Florida and then ‘abbrev’ for the argument it would return FL).

What if I dont know what data I have but know what data I want out?

This problem will come up quite frequently if, for example, you are compiling data from various sources and you are parsing mixed input. To make the function a little less stupid we need to modify the foreach loop at the bottom a little.

foreach ($states as $state) {
	foreach ($state as $title=>$value) {
		if (strtolower($value) == strtolower(trim($name))) {
			if ($to == 'name') {
				$return = $state['name'];
			} else {
				$return = $state['abbrev'];
			}
			break;
		}
	}
}

This code, instead of checking the specific field for each state, check the whole state array for the text we passed it. This way it doesn’t care if your passing it a state name or abbreviation as it can match on both. As before the second function argument is what response you want.

Whats next?

The next thing to do with this would be to just chuck the State details into a database and query them which would be much faster. The advantage about my way is that you can use it when writing code for others or systems that are unknown to you.

hope that has saved you a little time!

Time Savers ,

Geocoding Addresses using Google Maps

May 19th, 2008

In my previous post I showed you how to create a beautiful Google Map for your site with controls showing Google headquarters. Some might say that this isn’t very useful, I don’t know why they think that but for those that agree here is how to get it to show any postcode or address you like.

I strongly suggest you read my other post first if you don’t know much about the Google Map API (read it here)

So…

The process of turning an address into latitude and longitude coordinates is called Geocoding and Google’s API makes it very easy to do so using a simple request to their server. We will go into the legal side later on in this post but for now lets just say that Geocoding is a server intensive process for Google and they recommend client side caching of added coordinates to avoid re-requesting coordinates if you already have them.

Getting the coordinates is actually very easy. Use the following URL in your browser (making sure to replace your API key and an address)

http://maps.google.com/maps/geo?q= ## ADDRESS OR POSTCODE ## &output=xml&key= ## YOUR API KEY ##

This URL will return some XML (if you have done it correctly) which will contain three pieces of useful information

  • Latitude
  • Longitude
  • Geocode Accuracy

If you know what country your going to be searching in then you can add another argument to the URL telling it the TLD or Top Level Domain (com, uk, etc..) to make it a little easier for Googles Geocoder:

gl=uk

We can use the returned data to create a Google map of that location but first we need to extract the coordinates. Yes we could use Javascript but where’s the fun in that (or the point)? Using PHP means all the processing is done server side so the client doesn’t need to do any sort of processing (useful for slower client computers).

Here’s how you get PHP to send the request:

$ch = curl_init();
$url = "http://maps.google.com/maps/geo?q=" . urlencode($address) . "&output=xml&key=" . $api_key;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$return = curl_exec($ch);
curl_close($ch);

Why why why are you using CURL you ask? (what is CURL anyway?) Well..

A fair few server administrators are blocking the use for file handling functions to URLs (fopen, file, file_get_contents, etc..); This is sensible because there are exploits that malicious programmers can use to gain access to your site and start causing trouble. CURL is a little slower (I’m told) but safer (apparently).

The querystring we sent to Google passes the type of return we want (XML, KML, CSV, JSON), the address or postcode (urlencoded string) and of course our API key.

The curl options (specifically CURLOPT_RETURNTRANSFER) mean that whatever comes back from your CURL request can be stored in a variable and worked on (as opposed to echoing to the screen).

Although XML parsing in PHP is really easy (xml_parse_into_struct if your interested), it’s a bit overkill for what we need; Instead specify the output as CSV which returns a simple string that is incredibly easy to use. Something like:

200,6,42.730070,-73.690570

This breaks down into the following:

  • Request status code (success is 200, anything else means it’s broken)
  • Accuracy of search result (5 is postcode level, higher is better as far as 9 which is premise level)
  • Latitude
  • Longitude

The easiest way to get split the returned CSV string is the PHP explode function:

$array = explode(',', $csv_string);

This returns an array of values split on the delimiter specified (in this case the comma). Now the latitude and longitude can be accessed at positions 2 and 3 respectively ($array[2] and $array[3]).

So whats next?: Use the code I gave in my previous example to generate a map for an address we actually want by passing the latitude and longitude into my render_map function ($map->render_map($array[2], $array[3]);).

Some things to bear in mind:

The next step in theory would be to build up a database of geocoded coordinates next to addresses and use Google maps literally everywhere. Unfortunately (to my understanding (May 2008)) the Post Office have licensed their data and Google have to follow through on this. Basically it means that in every country except the UK you can save the coordinates wherever you like whereas here you have to geocode Google’s data on the fly EVERY page load.

If you decide this is unacceptable but don’t want to break the Terms & Conditions of Google’s API you can use a geocoding service and pay per postcode. It costs about 5 pence per geocode (Postcodeanywhere May 2008) and they allow you to store the data wherever you like.

Coming next: A find my nearest … search using google maps

If you want more information on the geocoding process then Googles explanation is here

Google Maps , ,

Google Map basics

May 15th, 2008

I have been toying with Google maps for a week or so now and have found them tricky if you don’t immediately understand what the hell is going on.

First things first, you need to register an API key (here) so that you can send requests off to their server and get a response that doesn’t read something like ‘Invalid API Key’. Google map API keys are domain specific but you can always register localhost or your internal domain ip which will still work.

The most logical thing to want to do when you have the key is display a map (Really?). Google offer a nice piece of JS to get you started so ill start with that:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <title>Google Maps JavaScript API Example</title>
    <script src="http://maps.google.com/maps?file=api&v=2&key=##YOUR-KEY-HERE##"
      type="text/javascript"></script>
    <script type="text/javascript">

    //<![CDATA[

    function load() {
      if (GBrowserIsCompatible()) {
        var map = new GMap2(document.getElementById("map"));
        map.setCenter(new GLatLng(37.4419, -122.1419), 13);
      }
    }

    //]]>
    </script>
  </head>
  <body onload="load()" onunload="GUnload()">
    <div id="map" style="width: 500px; height: 300px"></div>
  </body>
</html>

Simple eh? of course this code is great if you only ever want one map per page in a div called ‘map’ but this isn’t really very dynamic now is it. Once you get it running you’ll find out its just displaying a map of google headquarters somewhere in america with no map controls or anything useful (unless of course you wanted to know where google headquarters was).

So… to make this map usable we can do a number of things:

  1. Make the div name dynamic
  2. De-fluff the code and put it into a php template
  3. Sort out the &’s in their script call
  4. Pass the coordinates as a function argument to make it easier to use usable

Following my above points we are left with the following:

<?php
class map_test {
	function __construct($google_api_key) {
		$js = "<script src=\"http://maps.google.com/maps?file=api&v=2&key=" . $google_api_key . "\" />";
		$js .= "<script type=\"text/javascript\">
		function load() {
			if (GBrowserIsCompatible(mapName, latitude, longitude)) {
				var map = new GMap2(document.getElementById(\"mapName\"));
				map.setCenter(new GLatLng(latitude, longitude), 13);
			}
		}
    		</script>";
		echo $js;
	}
	function render_map($latitude, $longitude) {
		$div_id = 'map' . mt_rand(1000,9999);
		$html = "<div id=\"" . $div_id . "\" style=\"width: 500px; height: 300px\"></div>";
		$html .= "	<script>
					load(" . $div_id . ", " . $latitude . ", " . $longitude . ");
				</script>";
		echo $html;
	}
}
$google_api_key = "##YOUR-KEY-HERE##";
$latitude = 37.4419;
$longitude = -122.1419;
$map = new map_test($google_api_key);
$map->render_map($latitude, $longitude);
?>

Ok, so what we have here is just a longer way of rendering to the screen yet another map of Google’s headquarters. Look a little closer at the code and you will see that I have extracted the hard coded parts of the JS into variables that something like PHP can manipulate to display a map of pretty much anywhere you want to see. Just change the API key to yours and toy with the coordinates to see a map of anywhere you like.

The render_map function can be called as many times as you like, each time displaying another map of the coordinates you pass it.

The next logical addition to this script is to add controls for zoom and pan. These are surprisingly easy to integrate. Simply add the following lines to the JS ‘load’ function just after the line that defines the new GMap2:

map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());

These will work assuming of course that you haven’t renamed the ‘map’ variable.

Next you will probably want to add a marker (for Google headquarters) to show the thing you are looking at in more detail. These are done in the form of those pushpin things you usually see or as Google calls them, ‘markers’. The followng JS function will add a marker at the coordinates passed:

function addMarker(map, latitude, longitude, description) {
    var point = new GLatLng(latitude, longitude);
    var marker = new GMarker(point);
    if (description.length > 0) {
        GEvent.addListener(marker, "click", function() {
            marker.openInfoWindowHtml(description);
        });
    }
    map.addOverlay(marker);
}

You may want to put your JS code into a .js file and store it appropriately at this point because really large functions written in different languages can be confusing… Either way, put the above code below your ‘load’ function and call it using this line:

addMarker(map, latitude, longitude, desc);

Simple enough to understand really but it passes the map object we created earlier, the longitude, latitude and a description to the function to add a marker. If you don’t want a description for the marker then just pass an empty string or null.

You now know how to show visitors to your site where google headquarters is. Handy I know! See my future post for ‘Geocoding’ an address to get those all important coordinates for any location on the globe onto a google map.

Sean

For more Google map API help, who better than to ask than Google themselves: API Page

Google Maps , ,

Welcome to my blog

May 14th, 2008

I’ll start by saying that everything I post is something I have used which means that you get to skip all those silly mistakes that are inevitable when writing a piece of code. I’ll try to give an example of the working product with code snippets and pointers on where I went wrong so you don’t have to. I generally work in PHP / MYSQL but I will probably try out new languages (as i learn them!).

All i can say is, feedback appreciated.

Sean

Uncategorized