How to Code a Simple Zip Code Locator in PHP
4. Write some code already
First we need a form to collect the zip code:
<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>
Below our form we create the code that connects to the database and finds the closest store. This example will show how to return only one store, but that can easily be changed. I’ll let the comments speak for themselves (remember to replace the items in double square brackets with your information):
<?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'];
?>
// Paste Yahoo Maps API code from next section here.
<?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;
}
?>

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