This is a step by step guide for building a find nearest/store locator for free in PHP just like Postcode Anywhere.

It requires PHP and a mySQL database. That's all.

You don't need Google Maps, but it helped me populating the database, so I've included it for completeness. The example I'm using is UK based, but provided Google have a postcode/zipcode to lat/long convertor for your country, it should work nicely.

Background Maths

Before we start, it's time to go back to school with some background maths.

Don't be tempted into Pythagorean territory here, because the world isn't flat and the distance between lines of longitude gets smaller as we get closer to the poles. Also with the curvature of the earth for distances over say 15 miles, the sides of the triangle go from straight into an arc - not good.

Trying a little harder, we get to the Great Circle Distance method.

The Great Circle Distance Formula using radians:

r * acos[sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(lon2 - lon1)]

Where r is the radius of the earth e.g. r = 3963.0 miles

or
Great Circle Distance arccos formula

As I'm lazy, I want to add this directly into a SQL query that checks against lat/long values for my stores in my database.

Converted to (my)SQL syntax using lat/long in degrees becomes:
[source language="sql"]SELECT 3963.0 * ACOS( SIN( lat1*PI()/180 ) * SIN( lat2*PI()/180 ) + COS( lat1*PI()/180 ) * COS( lat2*PI()/180 ) * COS( (lon2*PI()/180) - (lon1*PI()/180) ) ) AS distance;[/source]

Assuming mySQL uses double precision, we can be assured that the calculation is reasonably accurate. Although the arcos formula can suffer from rounding errors at small distances. But in my experience, it works well when compared to other distance calculators (e.g.GMap Pedometer and Daft Logic Google Maps Distance Calculator).

Building the scripts

This example is unashamedly simplifed. The PHP is procedural and basic. It is for demonstration only - apply you own favourite MVC framework when working this up.

Create a simple mySQL database table for stores

CREATE TABLE `stores` (
`id` bigint(20) NOT NULL auto_increment,
`store_name` varchar(300) NOT NULL,
`postcode` varchar(10) NOT NULL,
`latitude` double NOT NULL,
`longitude` double NOT NULL,
`postal_address` text NOT NULL
PRIMARY KEY (`id`)
);

In reality, you'd probably want to add columns for phone no, web address, email etc.

Add some data to the table

I'm using real locations of Apple computer stores in the UK...

INSERT INTO `stores` (`id`, `store_name`, `postcode`, `latitude`, `longitude`, `postal_address`,)
VALUES
(
(1, 'KRCS Mac computer store', 'NG1 7QQ', 52.952493, -1.140725, 'Victoria Centre, Nottingham'),
(2, 'Apple Store', 'M4 3AJ', 51.51277, -2.14308, 'U23, New Cannon Street Mall, Manchester'),
(3, 'Apple Store', 'S9 1EA', 53.41442, -1.41089, '80 High Street, Meadowhell, Sheffield')
);

The lat/long values can be populated manually (e.g. go get them from Google Maps) or automatically using a function similar to this:

/**
* Get LatLong From Postcode
*
* @access public
* @param string $postcode
* @param string $country
* @param string $gmapApiKey
* @return array(statusCode, accuracy, latitude, longitude);
*/

function getLatLongFromPostcode($postcode, $country, $gmapApiKey)
{
/* remove spaces from postcode */
$postcode = urlencode(trim($postcode));
/* connect to the google geocode service */
$file = "http://maps.google.com/maps/geo?q=$postcode,$country&output=csv&key=$gmapApiKey";
$contents = file_get_contents($file);
return explode(',', $contents);
}

...but you'll need a Google Maps API key

Example for the Apple Store in Regent Street:

$geocode = getLatLongFromPostcode ('W1B 2EL', 'uk', 'ABQIAAAA2xzlSb6lvuy1qNdW6D87dBSX4wCNHpcq6aPi4BCCV9JuIkX6UhQgj9ZmrEF5FYpCKxFE5wNmrj');

Build the search/results page

&lt;form class=&quot;center&quot; action=&quot;./find-a-store.php&quot; method=&quot;get&quot;&gt;<br />
&lt;label for=&quot;postcode&quot;&gt;Postcode or Town&lt;/label&gt;<br />
&lt;input id=&quot;postcode&quot; name=&quot;postcode&quot; type=&quot;text&quot; value=&quot;&quot; /&gt;<br />
&lt;input name=&quot;submit&quot; type=&quot;submit&quot; value=&quot;Search »&quot; /&gt;<br />
&lt;/form&gt;
&lt;?php
if (isset($_REQUEST['postcode']))
{
$geocode = getLatLongFromPostcode($_REQUEST['postcode'], $country, $gmapApiKey);
$storeResults = array();
if ($geocode[0] == '200')
{
$latitude = $geocode[2];
$longitude = $geocode[3];

// Print heading
$htmlOutput .= &quot;
&lt;div class=&quot;results&quot;&gt;
&lt;h2&gt;Nearest stores to &lt;em&gt;$postcode&lt;/em&gt;&lt;/h2&gt;
&lt;ol&gt;&quot;;

// Build the spherical geometry SQL string
$earthRadius = '3963.0'; // In miles

$sql = &quot;
SELECT
ROUND(
$earthRadius * ACOS(
SIN( $latitude*PI()/180 ) * SIN( latitude*PI()/180 )
+ COS( $latitude*PI()/180 ) * COS( latitude*PI()/180 ) * COS( (longitude*PI()/180) - ($longitude*PI()/180) ) )
, 1)
AS distance,
store_name,
postcode,
postal_address,
latitude,
longitude
FROM
stores
ORDER BY
distance ASC
LIMIT 0, 10&quot;;

// Search the database for the nearest agents
$result = db_query($sql);
while ($row = mysql_fetch_array($result))
{
array_push($storeResults, $row);
}

foreach ($storeResults as $store)
{
// Print listings as an unordered list (structured: ol &gt; li &gt; h3 + div)
$htmlOutput .= &quot;
&lt;li&gt;
&lt;h3&gt;&lt;em&gt;{$store[store_name]} &lt;em&gt;{$store[distance]} miles.&lt;/em&gt;&lt;/em&gt;&lt;/h3&gt;
&lt;div&gt;&lt;em&gt;&quot; . str_replace(&quot;n&quot;, ', ', $store['postal_address']) .&quot;&lt;/em&gt;&lt;/div&gt;&lt;/li&gt;&quot;;<br />
}
$htmlOutput .= '
&lt;/ol&gt;&lt;/div&gt;'
;

echo $htmlOutput;
}
else
{
echo &quot;Problem with postcode.&quot;
}
} // if isset()
?>

By the way, properly cleanse $_REQUEST['postcode'] to prevent XSS attacks. The code above is for demo only.

Reference

Update

If you find this useful, but are still having trouble, here's an excellent article — Creating a Store Locator with PHP, MySQL & Google Maps from Google.