?
Solved

Looking for Kick Ass Zip Code Locator!!!

Posted on 2008-11-14
6
Medium Priority
?
559 Views
Last Modified: 2012-06-27
Hi,

I'm looking for a link to a kick ass zip code locator that comes highly recommended, preferably free/cheap,  that will function much like the 1800Dentist version  - front end here:

http://www.1800dentist.com/

Basically, the user needs to be able to search by location (zip code) AND speciaty

thanks!!!!
0
Comment
Question by:phillystyle123
  • 4
6 Comments
 
LVL 8

Expert Comment

by:biztiger
ID: 22966059
Full US Zip Code Free
http://geocoder.ibegin.com/downloads.php

Postal Code for another country:
http://www.maxmind.com/app/postalcode

All are free. Available in csv format.
0
 
LVL 111

Accepted Solution

by:
Ray Paseur earned 2000 total points
ID: 22968282
@phillystyle123: you need two things to do this task.  You need the geocode for the zip code (a latitude/longitude pair) and you need a proximity computer to find other zip codes that are nearby.  I've been working a similar project for a while and here is what I can tell you.

There are about 34,000 zip codes you need to be concerned with.  The others are APO, PO Box only, etc.  You can dump them.  A zip code is NOT a geographic location - it is a postal carrier's route.  It may overlap other zip codes, cross state lines, etc.  In other words, it's not very precise.  In a major metro area, zip codes are somewhat useful for proximity determination.  In rural areas, they are not very good at all, and you would want to geocode the street or route address.

An attempt to geocode a ZIP+4 code results in no greater accuracy than a 5-digit zip code.  You must have a street name to get better location information.  Street and number gets "address" precision - usually within a few hundred feet of what you're looking for.

You can obtain free geocoding services from Yahoo and Google.  You must get an API key.  Yahoo allows you 5,000 calls per day. Google allows you 15,000.  So don't pay for the service from ibegin unless you expect to need more than 20,000 geocode calls per day.

I have never seen a zip code data base that has 100% accuracy in the geocode information.  Be aware that you want to scrub the data, no matter where you get it!

Yahoo's geocoder returns XML.  Google can return XML (actually KML) or a very simple CSV.  

Here is a script that teaches how to call the services.  

In a moment I will post a way to compute the distance between two lat/lon pairs.
<?php // demo_geocoders.php
//
// DEMONSTRATE CALLING THE YAHOO AND GOOGLE GEOCODER SERVICES TO GET THE LAT/LON PAIR FOR AN ADDRESS OR PART OF AN ADDRESS
//
// OCTOBER 27, 2008 NOTES
//
// EXECUTIVE SUMMARY - INPUT DATA IN ORDER OF PREFERENCE
//   STREET ADDRESS, CITY, STATE, ZIP+4 LIKE 1446 COLLEEN LN, MCLEAN, VA 22101-3104 = ADDRESS PRECISION
//   STREET ADDRESS, ZIP or ZIP+4 = ADDRESS PRECISION
//   STREET NAME AND ZIP OR ZIP+4 = STREET PRECISION
//   ZIP+4 LIKE 22101-3104 OR JUST ZIP LIKE 20852 = ZIP PRECISION
//
// GOTCHAS
//   YOU MUST PRESENT ZIP+4 LIKE 20016-2375.  IF YOU USE 200162375 YAHOO CANNOT HANDLE IT
//
//
// YAHOO WILL TELL YOU IF THE STATE AND ZIP DO NOT MATCH, BUT WILL MAKE STUFF UP IF THEY ARE BOTH BLANK (4101 NEBRASKA AVE)
// GOOGLE _MAY_ RETURN CODE 602 IF STATE AND ZIP DO NOT MATCH AND NO REASONABLE MATCH ON STREET NAME
// GOOGLE WILL TRY SOUND-ALIKE MATCHING ON CITY OR STATE NAMES ("ASSTON, TX" == "AWSTWIN, TX" == "AUSTIN, TX") (STATE=XX GIVES BUDAPEST)
//
// KEY ACCURACY EQUIVALENTS
//  YAHOO!    GOOGLE
//  state       2
//  city        3
//  city        4
//  zip         5
//  street      6
//  address     8
//
 
// LOCAL FUNCTIONS
require_once('_config.php');
 
// GET A FREEFORM LOCATION STATEMENT
$loc = '';
foreach ($_GET as $k => $v) { $$k = get_clean_text_string($v); }
if ($a != '') { $loc .= $a . ', '; }
if ($c != '') { $loc .= $c . ', '; }
if ($s != '') { $loc .= $s . ', '; }
if ($z != '') { $loc .= $z . ', '; }
$loc = trim(substr($loc, 0, -2));
 
?>
<html><head><title><?=$a?> <?=$c?> <?=$s?> <?=$z?> Yahoo/Google Geocoder Query</title></head>
<body>
<form method="get">
Addr: <input type="text" name="a" autocomplete="off" value="<?=$a?>" />
City: <input type="text" name="c" autocomplete="off" value="<?=$c?>" />
ST:   <input type="text" name="s" autocomplete="off" value="<?=$s?>" size="2" />
Zip:  <input type="text" name="z" autocomplete="off" value="<?=$z?>" size="8" />
<input type="submit" name="_go" value="go" />
</form>
</body>
</html>
<?php
 
 
if (empty($_GET)) { die(); }
 
 
// YAHOO CALL
$yahoo_url	= "http://local.yahooapis.com/MapsService/V1/geocode?appid=" . YAHOO_API;
 
/* YOU CAN ASK FOR INDIVIDUAL PIECES OF AN ADDRESS
$yahoo_url	.= "&street=" .	urlencode($a);
$yahoo_url	.= "&city=" .	urlencode($c);
$yahoo_url	.= "&state=" .	urlencode($s);
$yahoo_url	.= "&zip=" .	urlencode($z);
*/
 
// YOU CAN MAKE A FREEFORM QUERY FROM THE PARTS OF AN ADDRESS
$yahoo_url	.= "&location=" . urlencode($loc);
 
// SHOW THE QUERY - DO NOT DISPLAY THE API KEY
$yahoo_no_api_url	= str_replace(YAHOO_API, "[YahooAPI]", $yahoo_url);
echo "<h2>Yahoo! Geocoder Query Returns XML</h2>\n";
echo "<h4>ManPage here: <a target=\"_ymp\" href=\"http://developer.yahoo.com/maps/rest/V1/geocode.html\">http://developer.yahoo.com/maps/rest/V1/geocode.html</a><br />\n";
echo "Accuracy Constants here: <a target=\"_ymp\" href=\"http://developer.yahoo.com/maps/rest/V1/geocode.html\">http://developer.yahoo.com/maps/rest/V1/geocode.html</a> (see Response Fields)</h4>\n";
echo "Query String: $yahoo_no_api_url <br />\n";
 
// EXECUTE YAHOO GEOCODER QUERY
// NOTE - USE ERROR SUPPRESSION OR IT WILL BARF UP THE YAHOO API - ON FAILURE RETURNS HTTP 400 BAD REQUEST
if ($fp = @fopen($yahoo_url, 'r')) {
	while (!feof($fp)) { $y_buf .= fgets($fp); }
	fclose($fp);
} else {
	echo "<br />Yahoo Query Failed\n";
}
 
// EXAMINE THE RESULT
if ($y_buf != '') { // NOT EMPTY, WE GOT DATA
	$ydata	= new SimpleXMLElement($y_buf);
 
// CHECK FOR ANY ERROR MESSAGE
	$y_err	= $ydata->Message;
	if ($y_err == '') {
		$y_qual	= $ydata->Result["precision"];
		$y_warn	= $ydata->Result["warning"];
		$y_lat	= $ydata->Result->Latitude;
		$y_lon	= $ydata->Result->Longitude;
		$y_state= $ydata->Result->State;
		$y_zip	= $ydata->Result->Zip;
 
// NO ERROR MESSAGE, SHOW THE RESULT
		echo "<br />Yahoo Geocoder Result: \n";
		echo "<a target=\"geo_Y\" href=\"http://www.google.com/maps?f=q&hl=en&geocode=&q=" . $y_lat .','. $y_lon . "&ie=UTF8&z=15&iwloc=addr\">$y_lat $y_lon</a><br />Precision=$y_qual \n";
		if ($y_warn != '') {
			echo "<br />Warning: $y_warn \n";
			if ($y_state != $s) {
				echo "<br />Input State $s does not match Yahoo State $y_state.  Google Data may be better. \n";
			}
		}
	} else {
		echo "<br />Yahoo Geocoder Error: \n";
		echo "$y_err \n";
	}
// NO RESULT - SOMETHING IS SICK AT YAHOO
} else {
	echo "<br />Yahoo! Fubar $y_buf \n";
}
 
// SHOW THE XML FROM YAHOO
$y_buf_p	= ereg_replace('>', ">\n", $y_buf);
echo "<pre>";
echo htmlentities($y_buf_p);
echo "</pre>\n";
 
 
 
// GOOGLE CALL - USE FREEFORM QUERY
$google_url	= "http://maps.google.com/maps/geo?key=" . GOOGLE_API . "&output=csv&q=";
$google_url	.= urlencode($loc);
$google_no_api_url	= str_replace(GOOGLE_API, "[GoogleAPI]", $google_url);
echo "<h2>Google Geocoder Query Returns CSV</h2>\n";
echo "<h4>ManPage here: <a target=\"_gmp\" href=\"http://code.google.com/apis/maps/documentation/services.html#Geocoding_Direct\">http://code.google.com/apis/maps/documentation/services.html#Geocoding_Direct</a> (see CSV)<br />\n";
echo "Accuracy Constants here: <a target=\"_gmp\" href=\"http://code.google.com/apis/maps/documentation/reference.html#GGeoAddressAccuracy\">http://code.google.com/apis/maps/documentation/reference.html#GGeoAddressAccuracy</a></h4>\n";
echo "Query String: $google_no_api_url <br />\n";
 
// EXECUTE THE GOOGLE GEOCODER QUERY
if ($fp = fopen($google_url, 'r')) {
	while (!feof($fp)) { $g_buf .= fgets($fp); }
	fclose($fp);
}
 
// EXTRACT THE DATA
$gdata	= explode(',',$g_buf);
$g_resp	= $gdata[0]; // RESPONSE CODE SHOULD BE '200' -- IF 602 - BAD ZIP CODE OR UNUSABLE ADDRESS
$g_qual	= $gdata[1]; // GEOCODE ACCURACY - ZIP CODE = 5, HIGHER NUMBERS ARE BETTER
$g_lat	= $gdata[2];
$g_lon	= $gdata[3];
 
if ($g_resp == '200') { // RESPONSE CODE 200, WE GOT DATA
	echo "<br />Google Geocoder Result: \n";
	echo "<a target=\"geo_G\" href=\"http://www.google.com/maps?f=q&hl=en&geocode=&q=" . $g_lat .','. $g_lon . "&ie=UTF8&z=15&iwloc=addr\">$g_lat $g_lon</a> Precision=$g_qual\n";
	echo "<pre>$g_buf</pre>\n";
 
// BAD QUERY OR SOMETHING IS SICK AT GOOGLE
} else {
	echo "<br />Google Fubar $g_buf \n";
}
 
?>

Open in new window

0
 
LVL 111

Assisted Solution

by:Ray Paseur
Ray Paseur earned 2000 total points
ID: 22968288
When you have selected the latitude and longitude pairs for point "a" and point "b" you can use this function to find the great-circle distance.  Not the same as driving distance but usually proportional and good enough.
function compute_distance($from_lat, $from_lon, $to_lat, $to_lon) {
 
	$from_lat	= floatval($from_lat);
	$from_lon	= floatval($from_lon);
	$to_lat		= floatval($to_lat);
	$to_lon		= floatval($to_lon);
 
	$dist	= acos( sin(deg2rad($from_lat))
              * sin(deg2rad($to_lat))
              + cos(deg2rad($from_lat))
              * cos(deg2rad($to_lat))
              * cos(deg2rad($from_lon - $to_lon)) );
 
	$dist	= rad2deg($dist);
	$miles	= (float) $dist * 69.0;
return round($miles,1);
// To get kilometers, multiply miles by 1.61
// $km		= (float) $miles * 1.61;
// return round($km,2);
}

Open in new window

0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 111

Assisted Solution

by:Ray Paseur
Ray Paseur earned 2000 total points
ID: 22968292
You will probably want to find out which zip codes are close to one another.  That's a new, separate question.  If you post a question about it, I'll show you the general algorithm for zip-proximity determination.

best regards, ~Ray
0
 

Author Closing Comment

by:phillystyle123
ID: 31516894
thanks Ray!
0
 
LVL 111

Expert Comment

by:Ray Paseur
ID: 23214801
Thanks for the points - it's a great question.  Good luck with your project, ~Ray
0

Featured Post

Important Lessons on Recovering from Petya

In their most recent webinar, Skyport Systems explores ways to isolate and protect critical databases to keep the core of your company safe from harm.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Build an array called $myWeek which will hold the array elements Today, Yesterday and then builds up the rest of the week by the name of the day going back 1 week.   (CODE) (CODE) Then you just need to pass your date to the function. If i…
This article discusses four methods for overlaying images in a container on a web page
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
The viewer will learn how to count occurrences of each item in an array.
Suggested Courses
Course of the Month17 days, 5 hours left to enroll

862 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question