How to Code a Simple Zip Code Locator in PHP
That’s all there is to it. I hope this has shown you how easy it is to code a simple zip code locator. Below is the code in it’s entirety, and you can see an example here. ![]()
<html>
<head>
<script type="text/javascript"
src="http://maps.yahooapis.com/v3.5/fl/javascript/apiloader.js?&appid=PASTE YOUR API KEY HERE">
</script>
<style type="text/css">
#mapContainer{
height: 400px;
width: 400px;
border:1px solid #333;
}
</style>
</head>
<body>
<p>Enter your 5 digit zip code:</p>
<form name="locate" method="POST"
action="<?=$_SERVER['PHP_SELF']?>">
<input name="zip" maxlength="5" size="6" type="text" />
<input type="submit" value="Find" />
</form>
<?php
// see if our zip code has been posted, and if it is a 5 digit #
if (isset($_POST['zip'])) {
// remember to sanitize your inputs
// this removes whitespace around the data and the next line makes sure its a 5 digit number
$findzip = trim($_POST['zip']);
if (preg_match("#^\d{5}$#",$findzip)) {
// if we have the right kind of data, connect to the database
$conn = mysql_connect('[[localhost]]','[[databse-user]]','[[database-password]]');
// select the database with the tables we created in step 3
mysql_select_db('[[database-name]]',$conn);
// create a query that will select the zip code (if we can't find the user entered zip, we return an error)
$query = "SELECT latitude,longitude,state,city FROM zip_codes WHERE zip=".$findzip." LIMIT 1";
$result = mysql_query($query);
if (mysql_num_rows($result) > 0) {
// grab the latitude, longitude,state and city from our result
list($flat,$flon,$fstate,$fcity) = mysql_fetch_row($result);
// now get all stores in the same state, or all stores if no states match
// we want to reduce the amount of work the database has to do so we see if a state matches
$query = "SELECT * FROM stores WHERE state='".$fstate."'";
$result = mysql_query($query);
if (mysql_num_rows($result) < 1) {
$query = "SELECT * FROM stores";
$result = mysql_query($query);
}
// now we process the stores to gather their data,
//this result should not be empty, so I was lazy and didn't write an else case
if (mysql_num_rows($result) > 0) {
while($row = mysql_fetch_assoc($result)) {
// first put all of the data for this store into an array, with the store id as the key
$storeinfo[$row['id']] = $row;
// get the store zip
$dzip = $row['zip'];
// query for the store's latitude and longitude
$query = "SELECT latitude,longitude FROM zip_codes WHERE zip=".$dzip." LIMIT 1";
$result2 = mysql_query($query);
if (mysql_num_rows($result2) > 0) {
list($dlat,$dlon) = mysql_fetch_row($result2);
// now get the distance from the user entered zip
// this function can be found on the same site as the one where you downloaded the zip codes from
$stores[$row['id']] = calcDist($flat,$flon,$dlat,$dlon);
}
}
}
// compare the distances (by sorting them least to greatest) to find the least
asort($stores);
// now we can display closest store
// optionally you could loop over this to list multiple stores
$store = $storeinfo[key($stores)];
// here is the lazy way to print out the data - I leave the pretty printing up to you
print_r($store);
// we'll need this variable for the Yahoo Maps integration
$maploc = $store['address1'] .", ".$store['city']." ".$store['state']." ".$store['zip'];
?>
<div id="mapContainer"></div>
<script>
// this is the address we want to map (you can list several and it will mark each one)
var addresses = new Array("<?=$maploc?>");
// Create and display Map object at the address with zoom level 3
// Include your application ID.
var map = new Map("mapContainer", "PASTE YOUR API KEY HERE", "<?=$maploc?>", 3);
map.addEventListener(Map.EVENT_INITIALIZE, onMapInit);
map.addEventListener(Map.EVENT_MARKER_GEOCODE_SUCCESS,onMarkerGeocode);
function onMapInit(eventObj) {
map.addTool( new PanTool(), true );
for(var i=0; i<addresses .length; i++) {
// if you did do multiple addresses, then this would have to change some (because it would be the same store each iteration)
var marker = new CustomPOIMarker('<?php echo str_replace("'","\'",$store['company']); ?>', '', '<?=$store['address1']?><br /><?=$store['city']?> <?=$store['state']?>, <?=$store['zip']?>', '0x000000', '0xFFFFFF');
map.addMarkerByAddress( marker, addresses[i] );
}
map.addWidget( new ZoomBarWidget() );
}
function onMarkerGeocode(eventObj) {
var geocodeResponse = eventObj.response;
}
</script>
<?php
}
//if can't find zip return error
else {
printError("The zip code you entered was not found in our database. Please try another one.");
}
} else {
printError("The zip code must be a 5 digit number. Please try again.");
}
} else {
//do nothing
}
// functions
function printError($e)
{
echo "<p class='error'>$e";
}
function calcDist($lat_A, $long_A, $lat_B, $long_B)
{
$distance = sin(deg2rad($lat_A))
* sin(deg2rad($lat_B))
+ cos(deg2rad($lat_A))
* cos(deg2rad($lat_B))
* cos(deg2rad($long_A - $long_B));
$distance = (rad2deg(acos($distance))) * 69.09;
return $distance;
}
?>
</body>
</html>

Comment by James Ehly
on 22 Oct 2007 at 9:42 am #
Well I just figured out a logical error in the script. If you find by state first then that might not actually be the closest location to you (since there might be a closer location in the state next to you). Just comment out the lines about querying the state first and you should be fine. However, I assume doing this will slow the code down quite a bit if you have a ton of locations to search against. Maybe caching the queries somehow would be in order.
James
Pingback by October 2007 Recap and Traffic Report | DEVTRENCH: Web Development from the Front Lines
on 02 Nov 2007 at 7:57 am #
[...] spam and web stats: Usi…How to Code a Simple Zip Code Loc…WPA Can also be Cracked!!…Out sick: Preparing for a regular…Getting Technorati Authority [...]
Comment by Internet Television
on 24 Jan 2008 at 4:16 pm #
That’s absolutely beautiful, great work.
Comment by josh
on 01 May 2008 at 8:17 am #
What do i have to do to show more stores?
Comment by James Ehly
on 01 May 2008 at 8:44 am #
A few people have asked me this, so here is the looping code you’ll need.
Find this line and add some code like this…
// now we can display closest store// optionally you could loop over this to list multiple stores
$store = $storeinfo[key($stores)];
print "<p>The web developers closest to: $findzip</p><br>\n";
$maploc = "’You are here’,'$findzip’,";
foreach($stores as $k=>$v) {
$output .= "<h3 style=’margin:0;padding:0′><b>".$info[$k]['company']."</b><br>(approx ".round($v)." miles)</h3>";
$output .= "<p style=’margin:0 0 10px 0;padding:0′><a href=’".$info[$k]['url']."’>".$info[$k]['url']."</a><br>";
$output .= $info[$k]['city']." ".$info[$k]['state'].", ".$info[$k]['zip']."</p>";
$maploc .= "’".$info[$k]['company']."’,'".$info[$k]['address1']." ".$info[$k]['city']." ".$info[$k]['state']." ".$info[$k]['zip']."’,";
}
$maploc = substr($maploc,0,-1);
And here are the changes to the javascript:
<script>// this is the address we want to map (you can list several and it will mark each one)
var addresses = new Array(<?=$maploc?>);
// Create and display Map object at the address with zoom level 3
// Include your application ID.
var map = new Map("mapContainer", "[your api key here]", "<?=$maploc?>",20);
map.addEventListener(Map.EVENT_INITIALIZE, onMapInit);
map.addEventListener(Map.EVENT_MARKER_GEOCODE_SUCCESS,onMarkerGeocode);
function onMapInit(eventObj) {
map.addTool( new PanTool(), true );
for(var i=0; i<addresses.length; i=i+2) {
//alert(addresses[i]);
//alert(addresses[i+1]);
// if you did do multiple addresses, then this would have to change some (because it would be the same store each iteration)
var marker = new CustomPOIMarker(addresses[i], ”, addresses[i+1], ‘0×000000′, ‘0xFFFFFF’);
map.addMarkerByAddress( marker, addresses[i+1] );
}
map.addWidget( new ZoomBarWidget() );
}
function onMarkerGeocode(eventObj) {
var geocodeResponse = eventObj.response;
}
</script>
Basically what you are doing is building an array of results and looping over then with the javascript.
Hope this helps. James