I was working with Chris Veness' scripts from http://www.movable-type.co.uk I was trying to run a query against a MySQL database to return only rows that fall within a given radius, using his Bounding Circle script. As follows:
<?php
require 'inc/dbparams.inc.php'; // defines $dsn, $username, $password
$db = new PDO($dsn, $username, $password);
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$lat = $_GET['lat']; // latitude of centre of bounding circle in degrees
$lon = $_GET['lon']; // longitude of centre of bounding circle in degrees
$rad = $_GET['rad']; // radius of bounding circle in kilometers
$R = 6371; // earth's mean radius, km
// first-cut bounding box (in degrees)
$maxLat = $lat + rad2deg($rad/$R);
$minLat = $lat - rad2deg($rad/$R);
// compensate for degrees longitude getting smaller with increasing latitude
$maxLon = $lon + rad2deg($rad/$R/cos(deg2rad($lat)));
$minLon = $lon - rad2deg($rad/$R/cos(deg2rad($lat)));
$sql = "Select Id, Postcode, Lat, Lon,
acos(sin(:lat)*sin(radians(Lat)) + cos(:lat)*cos(radians(Lat))*cos(radians(Lon)-:lon)) * :R As D
From (
Select Id, Postcode, Lat, Lon
From MyTable
Where Lat Between :minLat And :maxLat
And Lon Between :minLon And :maxLon
) As FirstCut
Where acos(sin(:lat)*sin(radians(Lat)) + cos(:lat)*cos(radians(Lat))*cos(radians(Lon)-:lon)) * :R < :rad
Order by D";
$params = array(
'lat' => deg2rad($lat),
'lon' => deg2rad($lon),
'minLat' => $minLat,
'minLon' => $minLon,
'maxLat' => $maxLat,
'maxLon' => $maxLon,
'rad' => $rad,
'R' => $R,
);
$points = $db->prepare($sql);
$points->execute($params);
?>
<html>
<table>
<? foreach ($points as $point): ?>
<tr>
<td><?= $point->Postcode ?></td>
<td><?= number_format($point->D,1) ?></td>
<td><?= number_format($point->Lat,3) ?></td>
<td><?= number_format($point->Lon,3) ?></td>
</tr>
<? endforeach ?>
</table>
</html>
I renamed my existing columns in my database to match what Chris Veness used - and instead of using a $_GET value, I entered some static values of
- $lat = 51.552971553688500;
- $lon = -3.028690575475280;
- $rad = 25;
This did not work... And moreover, I could not find a solution as to why it wasn't working, exactly... Although I think @dan08 was very much onto something with his answer below. He knows a lot more about this stuff than I do.
Despite all that - I do [finally] have a working solution! Please see my answer below.
Those folks over at Google Devs are clever bunch!
So here's the link I followed to find my solution: Creating a Store Locator with PHP, MySQL & Google Maps
Despite the fact that this tutorial is geared toward using Google Maps API, the first half of the tutorial focuses on using PHP to query a database and create a bounding circle in order to search for matches within a given radius and return only those results that match.
In the tutorial, the query is super-fast and outputs the results in XML which is exceptionally useful for integrating into API. I didn't need that functionality, so I simplified mine a little.
Here's what I have - and it works perfectly for what I need:
Create a page called: phpsqlsearch_dbinfo.php
Create a new page called: phpsqlsearch_genxml.php
When visiting this page, We pass some values to it, as we're using $_GET to collect the 'lat','lng' and 'radius' values.
Eg.phpsqlsearch_genxml.php?lat=37&lng=-122&radius=25
Finally, to get this example working, you need to have your database set up. If you don't have access to phpMyAdmin or prefer using SQL commands instead, here's the SQL statement that creates the table:
Now for the example data to populate the table: Click Here - This example data set contains 169 rows in total. If you follow the link above, you can copy the full data set in the following format:
I hope this helps anyone who has struggled as much as I have. With just basic understanding of PHP and MySQL, you'll have this up and running in no time.
Good Luck!
Correct. But it's not what you are thinking.
You main problem is that your are using placeholder lie
:lat
in your select clause. This comment explains the problem well. But the bottom line is that you cant bind params in the SELECT and FROM clause because they are parsed before parameters are added.Using PDO or MySQLi won't change that. So to add those variable into the SELECT clause, sanitize them properly and insert them as string in the query.
You're making use of one of my favorite features of PDO, the named placeholders. So I would suggest sticking with PDO.
To have any luck debugging a 500 error you need to check your server logs. Maybe
/var/log/apache2/error.log
if you have a typical LAMP stack.