<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>David Simpson &#187; mysql</title>
	<atom:link href="http://davidsimpson.me/tag/mysql/feed/" rel="self" type="application/rss+xml" />
	<link>http://davidsimpson.me</link>
	<description>Developing the web, one page at a time.</description>
	<lastBuildDate>Wed, 16 May 2012 20:14:56 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>Find nearest store page using PHP, mySQL and Google Maps</title>
		<link>http://davidsimpson.me/2008/09/28/find-nearest-store-page-using-php-mysql-and-google-maps/</link>
		<comments>http://davidsimpson.me/2008/09/28/find-nearest-store-page-using-php-mysql-and-google-maps/#comments</comments>
		<pubDate>Sun, 28 Sep 2008 22:38:17 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Uncategorised]]></category>
		<category><![CDATA[find nearest]]></category>
		<category><![CDATA[google maps]]></category>
		<category><![CDATA[mapping]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[spherical geometry]]></category>

		<guid isPermaLink="false">http://davidsimpson.me/?p=6</guid>
		<description><![CDATA[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&#8217;s all. You don&#8217;t need Google Maps, but it helped me populating the database, so I&#8217;ve included it for completeness. The example I&#8217;m using is UK based, [...]]]></description>
			<content:encoded><![CDATA[<div id="tweetbutton6" class="tw_button" style=""><a href="http://twitter.com/share?url=http%3A%2F%2Fdavidsimpson.me%2F2008%2F09%2F28%2Ffind-nearest-store-page-using-php-mysql-and-google-maps%2F&amp;text=Find%20nearest%20store%20page%20using%20PHP%2C%20mySQL%20and%20Google%20Maps&amp;related=&amp;lang=en&amp;count=horizontal&amp;counturl=http%3A%2F%2Fdavidsimpson.me%2F2008%2F09%2F28%2Ffind-nearest-store-page-using-php-mysql-and-google-maps%2F" class="twitter-share-button"  style="width:55px;height:22px;background:transparent url('http://davidsimpson.me/wp-content/plugins/wp-tweet-button/tweetn.png') no-repeat  0 0;text-align:left;text-indent:-9999px;display:block;"></a></div><p>This is a step by step guide for building a find nearest/store locator <strong><em>for free</em></strong> in PHP just like <a href="http://www.postcodeanywhere.co.uk/products/store_locater/demos.aspx">Postcode Anywhere</a>.</p>
<p>It requires PHP and a mySQL database. That&#8217;s all.</p>
<p>You don&#8217;t <em>need</em> Google Maps, but it helped me populating the database, so I&#8217;ve included it for completeness.  The example I&#8217;m using is UK based, but provided Google have a postcode/zipcode to lat/long convertor for your country, it should work nicely.</p>
<p><span id="more-6"></span></p>
<h2>Background Maths</h2>
<p>Before we start, it&#8217;s time to go back to school with some background maths.</p>
<p>Don&#8217;t be tempted into Pythagorean territory here, because the world isn&#8217;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 &#8211; not good.</p>
<p>Trying a little harder, we get to the <a href="http://en.wikipedia.org/wiki/Great-circle_distance">Great Circle Distance method</a>.</p>
<p>The <strong>Great Circle Distance Formula</strong> using radians:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;">r <span style="color: #66cc66;">*</span> acos<span style="color: #66cc66;">&#91;</span>sin<span style="color: #66cc66;">&#40;</span>lat1<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">*</span> sin<span style="color: #66cc66;">&#40;</span>lat2<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">+</span> cos<span style="color: #66cc66;">&#40;</span>lat1<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">*</span> cos<span style="color: #66cc66;">&#40;</span>lat2<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">*</span> cos<span style="color: #66cc66;">&#40;</span>lon2 <span style="color: #66cc66;">-</span> lon1<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span></pre></div></div>

<p>Where r is the radius of the earth <em>e.g. r = 3963.0 miles</em></p>
<p>or<br />
<img src="http://upload.wikimedia.org/math/9/c/5/9c57640515e58765b63ffc12dc2a8950.png" alt="Great Circle Distance arccos formula" /></p>
<p>As I&#8217;m lazy, I want to add this directly into a SQL query that checks against lat/long values for my stores in my database.</p>
<p>Converted to (my)SQL syntax using lat/long in <em>degrees</em> becomes:</p>
<pre class="brush: sql; title: ;">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;</pre>
<p>Assuming <a href="http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html">mySQL uses double precision</a>, 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.<a href="http://www.gmap-pedometer.com/">GMap Pedometer</a> and <a href="http://www.daftlogic.com/projects-google-maps-distance-calculator.htm">Daft Logic Google Maps Distance Calculator</a>).</p>
<h2>Building the scripts</h2>
<p>This example is unashamedly simplifed.  The PHP is procedural and basic.  It is for demonstration only &#8211; apply you own favourite MVC framework when working this up.</p>
<h3>Create a simple mySQL database table for stores</h3>
<pre class="brush: sql; title: ;">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`)
);</pre>
<p>In reality, you&#8217;d probably want to add columns for phone no, web address, email etc.</p>
<h3>Add some data to the table</h3>
<p>I&#8217;m using real locations of Apple computer stores in the UK&#8230;</p>
<pre class="brush: sql; title: ;">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')
);</pre>
<p>The lat/long values can be populated manually (e.g. go get them from Google Maps) or automatically using a function similar to this:</p>
<pre class="brush: php; title: ;">/*
 * 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 = &quot;http://maps.google.com/maps/geo?q=$postcode,$country&amp;amp;amp;output=csv&amp;amp;amp;key=$gmapApiKey&quot;;

	$contents = file_get_contents($file);
	return explode(',', $contents);
}</pre>
<p>&#8230;but you&#8217;ll need a <a href="http://code.google.com/apis/maps/signup.html">Google Maps API key</a></p>
<p>Example for the Apple Store in Regent Street:</p>
<pre class="brush: php; title: ;">$geocode = getLatLongFromPostcode ('W1B 2EL', 'uk', 'ABQIAAAA2xzlSb6lvuy1qNdW6D87dBSX4wCNHpcq6aPi4BCCV9JuIkX6UhQgj9ZmrEF5FYpCKxFE5wNmrj');</pre>
<h3>Build the search/results page</h3>
<pre class="brush: php; title: ;">&lt;form class=&quot;center&quot; action=&quot;./find-a-store.php&quot; method=&quot;get&quot;&gt;
	&lt;label for=&quot;postcode&quot;&gt;Postcode or Town&lt;/label&gt;
	&lt;input id=&quot;postcode&quot; name=&quot;postcode&quot; type=&quot;text&quot; value=&quot;&quot; /&gt;
	&lt;input name=&quot;submit&quot; type=&quot;submit&quot; value=&quot;Search »&quot; /&gt;
&lt;/form&gt;

&lt;?php
	if (isset($_REQUEST['postcode']))
	{
		$geocode = geocodePostcode ($_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;;
			}
			$htmlOutput .= '
			&lt;/ol&gt;&lt;/div&gt;';

			echo $htmlOutput;
		}
		else
		{
			echo &quot;Problem with postcode.&quot;
		}

	} // if isset()
?&gt;
</pre>
<p>By the way, properly cleanse <code>$_REQUEST['postcode']</code> to prevent XSS attacks.  The code above is for demo only.</p>
<h3>Reference</h3>
<ul>
<li><a href="http://en.wikipedia.org/wiki/Great-circle_distance">Great Circle Distance &#8211; Wikipedia</a></li>
<li><a href="http://www.meridianworlddata.com/Distance-Calculation.asp">Original source for this calculation</a></li>
</ul>
<h3>Update</h3>
<p>If you find this useful, but are still having trouble, here&#8217;s an excellent article &mdash; <a href="http://code.google.com/apis/maps/articles/phpsqlsearch.html">Creating a Store Locator with PHP, MySQL &#038; Google Maps</a> from Google.</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://davidsimpson.me/2008/09/28/find-nearest-store-page-using-php-mysql-and-google-maps/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
	</channel>
</rss>

