Sunday, April 29, 2012

How to search within a defined radius using MySql and PHP

Hey guys, today my manager assigned me a task to search property listing withing a specific radius like within 10 km or 10 miles. I did it very easily because I have done this already in one of my project. But first time this task was very hard to do and I did a lot of research and goggled the internet to find out the solution. Well that is an old and long story. Today after doing my task I thought why not I post my work in the form of an article on my blog. So here is the article...


I will consider example of searching properties within a defined radius. This example needs a MySQL table with some records already inserted in that. Each record represents an individual property and reach property has its own latitude and longitude. These latitude and longitude are very important and playing a role of back bone of this article. My property listings table contains title, address, description, lat, long, and some attributes of property like number of bedrooms and bathrooms etc. But for simplicity i removed unnecessary fields. Now simple table will have title, address, latitude, longitude. So just run following query in your mysql server.

 CREATE TABLE IF NOT EXISTS `my_listings` (  
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,  
  `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,  
  `address` varchar(555) COLLATE utf8_unicode_ci NOT NULL,  
  `latitude` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,  
  `longitude` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,  
  PRIMARY KEY (`id`)  
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Listing of property' AUTO_INCREMENT=7 ;


 INSERT INTO `my_listings` (`id`, `title`, `address`, `latitude`, `longitude`) VALUES  
 (2, 'Property #1', 'address 1', '33.7133348', '73.0619261'),  
 (3, 'Property #2', 'address 2', '33.6676974', '73.0752068'),  
 (4, 'Property #3', 'address 3', '34.1764355', '73.2278335'),  
 (5, 'Property #4', 'address 4', '34.1764355', '73.2278335');  

 You are done with database design and now time comes to do some programming and make the script alive. In order to do so we need an html form which sends request to php server to search the properties. Here is that form's html,
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
 <html xmlns="http://www.w3.org/1999/xhtml">  
 <head>  
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
 <title>Untitled Document</title>  
 </head>  
 <body>  
 <form action="" method="get" name="searchform" id="searchform">  
 <input type="text" name="address" />  
 <input type="text" name="radius" />  
 <input type="submit" name="submit" value="Search" />  
 </form>  
 </body>  
 </html>  

Ok you are done with html form. Now add some php code in it. Put the following code at the tope of above code,
 <?php  
 $con = mysql_connect("localhost","myusername","mypassword");  
 mysql_select_db('mydatabse');  
 if (!$con)  
 {  
  die('Could not connect: ' . mysql_error());  
 }  
 mysql_close($con);  
 ?>  

This code connects you to database server. In my case my database server name is localhost, username is myusername, password is mypassword and database name is mydatabase. You can change this to any name you want.

Now add some more code which will find out the minimum and maximum latitudes and longitudes, and on the bases of those latitude and longitude fetch records from database which lies within that radius,
 <?php  
 function getlatlang($location)  
 {  
      $geocode = file_get_contents('http://maps.google.com/maps/api/geocode/json?address='. urlencode($location) .'&sensor=false');  
        
      $output= json_decode($geocode);  
   
      return $output->results[0]->geometry->location;  
 }  
   
 if( isset($_POST ) )  
 {  
      $con = mysql_connect("localhost","myusername","mypassword");  
      mysql_select_db('mydatabse');  
      if (!$con)  
      {  
       die('Could not connect: ' . mysql_error());  
      }  
        
      mysql_close($con);  
        
      $objlocation = getlatlang($_POS['address']);  
      $latitude = $objlocation->lat;  
      $longitude = $objlocation->lng;  
        
      $range = $_POST['radius'];  
             
      if($latitude != "" && $longitude != "")  
      {  
           // Find Max - Min Lat / Long for Radius and zero point and query  
           $lat_range = $range/69.172;  
           $lon_range = abs($range/(cos($latitude) * 69.172));  
           $min_lat = number_format($latitude - $lat_range, "4", ".", "");  
           $max_lat = number_format($latitude + $lat_range, "4", ".", "");  
           $min_lon = number_format($longitude - $lon_range, "4", ".", "");  
           $max_lon = number_format($longitude + $lon_range, "4", ".", "");  
             
           $sqlstr = mysql_query("SELECT * FROM my_listings  
           latitude BETWEEN '".$min_lat."' AND '".$max_lat."' AND  
           longitude BETWEEN '".$min_lon."' AND '".$max_lon."' ");  
                                 
           if (mysql_numrows($sqlstr) != 0) {  
                while ($row = mysql_fetch_array($sqlstr)) {  
                  
                ?>  
       <p><?= $row['title'] ?></p>  
       <p><?= $row['address'] ?></p>  
       <?php  
                  
                }  
           }  
             
             
      }  
 }  
 ?>   

That's it. This script is just displaying the records in the form of list for simplicity of article. You can extend this script and can add more code to make it working with google map and can show the records on google map. Whole script file looks like this,
 <?php  
 function getlatlang($location)  
 {  
      $geocode = file_get_contents('http://maps.google.com/maps/api/geocode/json?address='. urlencode($location) .'&sensor=false');  
      $output= json_decode($geocode);  
      return $output->results[0]->geometry->location;  
 }  
 if( isset($_POST ) )  
 {  
      $con = mysql_connect("localhost","myusername","mypassword");  
      mysql_select_db('mydatabse');  
      if (!$con)  
      {  
       die('Could not connect: ' . mysql_error());  
      }  
      mysql_close($con);  
      $objlocation = getlatlang($_POS['address']);  
      $latitude = $objlocation->lat;  
      $longitude = $objlocation->lng;  
      $range = $_POST['radius'];  
      if($latitude != "" && $longitude != "")  
      {  
           // Find Max - Min Lat / Long for Radius and zero point and query  
           $lat_range = $range/69.172;  
           $lon_range = abs($range/(cos($latitude) * 69.172));  
           $min_lat = number_format($latitude - $lat_range, "4", ".", "");  
           $max_lat = number_format($latitude + $lat_range, "4", ".", "");  
           $min_lon = number_format($longitude - $lon_range, "4", ".", "");  
           $max_lon = number_format($longitude + $lon_range, "4", ".", "");  
           $sqlstr = mysql_query("SELECT * FROM my_listings  
           latitude BETWEEN '".$min_lat."' AND '".$max_lat."' AND  
           longitude BETWEEN '".$min_lon."' AND '".$max_lon."' ");  
           if (mysql_numrows($sqlstr) != 0) {  
                while ($row = mysql_fetch_array($sqlstr)) {  
                ?>  
       <p><?= $row['title'] ?></p>  
       <p><?= $row['address'] ?></p>  
       <?php  
                }  
           }  
      }  
 }  
 ?>   
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
 <html xmlns="http://www.w3.org/1999/xhtml">  
 <head>  
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
 <title>Untitled Document</title>  
 </head>  
 <body>  
 <form action="" method="get" name="searchform" id="searchform">  
 <input type="text" name="address" />  
 <input type="text" name="radius" />  
 <input type="submit" name="submit" value="Search" />  
 </form>  
 </body>  
 </html>  

please feel free to post your comments,

15 comments:

  1. Hello Asad:

    I am trying to develop a php/mysql hospital locator functionality for my website. I have a mysql database of hospital listings but dont have a latitude/longitude data for each listing. I read your comments above but not sure how i can proceed with this.

    Thanks
    Syed Aman
    eagleford2@gmail.com

    ReplyDelete
    Replies
    1. Hi Syed

      For finding latitude/logitude you must have addresses with each hospital record in your database. Then you can write a php script which will get addresses from db and using google api you can find lat/long and update that in database by simple MySql update query. You can use following php function for finding lat/long

      private function getlatlang($location)
      {
      $geocode = file_get_contents('http://maps.google.com/maps/api/geocode/json?address='. urlencode($location) .'&sensor=false');

      $output= json_decode($geocode);
      }

      where $location is the address for which you want to find lat/long

      Thanks

      Delete
  2. What distance is the radius based off of?You never mention it or suggest any dummy values>?

    ReplyDelete
    Replies
    1. distance is based on Kilometers. like you want to search listings around a specific address or point within 10 Km radius circle.

      Delete
    2. This is not KILOMETERS!!! This is miles!!!! Please change this, caused me quiete some trouble.

      Delete
  3. In this example what would be a value for range? When I enter 10, it does not give me any results even when I enter a zipcode that I know is within a 10km range. Also, what numbers would I use for miles?

    ReplyDelete
  4. Hello, thanks for this awesome example of code. I read this code carefully, tried to understand, and found that place:

    $lat_range = $range/69.172;
    $lon_range = abs($range/(cos($latitude) * 69.172));

    As I learned so far, 1 dg of longitude is always 69 miles. And 1 dg of latitude is changing in case of angle to equator.

    So do your code supposed to be like that (just switch values):

    $lat_range = abs($range/(cos($latitude) * 69.172));
    $lon_range = $range/69.172;

    Thanks!

    ReplyDelete
  5. Asad Mehmood how can we get longitudes and latitudes across 2KM around a specific latitude , longitude

    ReplyDelete
  6. Asad Mehmood Please Help me. HOw can we get longitudes , latitudes across 2 KM around a specific Latitude and langitude .... :)

    ReplyDelete
  7. Hello,

    thanks for this.
    I have a problem json_decode() is not working proper for me. In one place in my code it works and at another place the exact code returns nothing and no error code.

    Do you have an idea what can be wrong?

    Kind regards,
    Rupam

    ReplyDelete
    Replies
    1. this may be because of php version you are using

      Delete
    2. Does the code yet?
      I get the following error message:

      Warning: file_get_contents () [function.file-get-contents]: http:// wrapper is disabled in the server configuration by allow_url_fopen = 0 in / xx / xxx / searching.php on line 4

      Warning: file_get_contents (http://maps.google.com/maps/api/geocode/json?address=&sensor=false) [function.file-get-contents]: failed to open stream: no suitable wrapper Could be found in / xx / xxx / searching.php on line 4

      Thanks in advance

      Delete
  8. Sir would u help me out with that .Just retrieve longitude and latitude value from MySQL db and simply show on Google map.i didn't do much php programming. actually I'm developing android project that send send latitude and longitude to server mean store in MySQL db . Any help will be really appreciated

    ReplyDelete

Please feel free to post your comments. If anyone has a good article or good thing to share, just send me that with your name to asadmehmoodstar@gmail.com. and if anyone want so receive updates regarding my blog, he can subscribe to my weekly newsletter on "Subscribe to our mailing list" section.

Thanks