php/mysql zip code proximity search

前端 未结 7 1953
南笙
南笙 2020-12-02 15:08

I\'m just looking for suggestions on the best way to do this...

I need to create a search function that searches for \"users\" within a 50 mile radius of a zip code

相关标签:
7条回答
  • 2020-12-02 15:10

    I would first do a search for all the zipcodes in the radius of the target. Then compare all the returned zipcodes to your user table zipcodes. Pull out the matching users.

    It find the zipcodes in a radius, found this MySQL call:

    $query = 'SELECT zzip FROM ' . table . 
                ' WHERE (POW((69.1*(zlongitude-"' . 
                $long . '")*cos(' . $long . 
                '/57.3)),"2")+POW((69.1*(zlatitude-"' . 
                $lat . '")),"2"))<(' . $radius . 
                '*' . $radius . ')';
    

    MySQL does all the math for you.

    I found a class that uses this here: http://www.nucleusdevelopment.com/code/do/zipcode

    Hope that helps.

    0 讨论(0)
  • 2020-12-02 15:16

    The lat/long you have for each zip code is a geographic center for that zip, right? So if you first find zip codes with geographic centers within 50 miles, then users in those zip codes, you could easily be returning users more than 50 miles away. So you'd sacrifice some accuracy doing it that way.

    But if you have a lot of users (more than the number of zip codes), this would be faster, since you'd query against the smaller zip codes table first. And you could index zip codes in the users table, so finding users with a particular zip code would be fast.

    Just some thoughts! So, if you are expecting a lot of users and the radius of 50 miles doesn't need to be exact, I would find zip codes within 50 miles, then users within those zip codes.

    0 讨论(0)
  • 2020-12-02 15:19

    Start here but note that the solution isn't very fast:

    PHP Zip Code Range and Distance Calculation

    Now to make it fast - we are going to replace the lookup to use a spatial index :)

    1. Use MySQL

    2. Add a column to the database called location and make it type POINT

    3. Make sure it accepts nulls right now

    4. Run the following SQL Query

      UPDATE zip_code SET location = PointFromText(CONCAT('POINT(',lon,' ',lat,')'));

    5. Now, make the column not accept nulls

    6. Add a spatial index to the location column

    7. In the code from the above project replace the function 'get_zips_in_range' with the following:

      function get_zips_in_range($zip, $range, $sort=1, $include_base) 
           {
      
      
          // returns an array of the zip codes within $range of $zip. Returns
          // an array with keys as zip codes and values as the distance from
          // the zipcode defined in $zip.
      
          $this->chronometer();                     // start the clock
      
          $details = $this->get_zip_point($zip);  // base zip details
          if ($details == false) return false;
      
          // This portion of the routine  calculates the minimum and maximum lat and
          // long within a given range.  This portion of the code was written
          // by Jeff Bearer (http://www.jeffbearer.com). This significanly decreases
          // the time it takes to execute a query.  My demo took 3.2 seconds in
          // v1.0.0 and now executes in 0.4 seconds!  Greate job Jeff!
      
          // Find Max - Min Lat / Long for Radius and zero point and query
          // only zips in that range.
          $lat = $details[0];
          $lon = $details[1];
      
          $return = array();    // declared here for scope
      
          $first = true;
          $radius = $range/69.172;
          $boundary = "POLYGON((";
          for($i=0; $i <= 360; $i += 360/24)
          {
              if($first)
              {
                  $first = false;
              }
              else
              {
                  $boundary .= ', ';
              }
      
              $clon = $radius*cos(deg2rad($i)) + $lon;
              $clat = $radius*sin(deg2rad($i)) + $lat;
              $boundary .= "$clon $clat" ;
          }
      
          $boundary  .= '))';
      
          $sql = "SELECT zip_code, city, county, state_name, state_prefix, area_code, time_zone, lat, lon FROM zip_code WHERE MBRContains(GeomFromText('$boundary'), location);";
      
          //echo $sql;
          $r = mysql_query($sql);
      
          if (!$r) {    // sql error
      
              $this->last_error = mysql_error();
              return false;
      
          } else {
      
              while ($row = mysql_fetch_row($r)) {
      
                  // loop through the results to get the milage from src
                  $dist = $this->calculate_mileage($details[0],$row[7],$details[1],$row[8]);
                  if ($this->units == _UNIT_KILOMETERS) $dist = $dist * _M2KM_FACTOR;
                  $return[str_pad($row[0].', '.$row[1], 5, "0", STR_PAD_LEFT)] = round($dist, $this->decimals);
      
              }
              mysql_free_result($r);
          }
      
          // sort array
          switch($sort)
          {
              case _ZIPS_SORT_BY_DISTANCE_ASC:
                  asort($return);
                  break;
      
              case _ZIPS_SORT_BY_DISTANCE_DESC:
                  arsort($return);
                  break;
      
              case _ZIPS_SORT_BY_ZIP_ASC:
                  ksort($return);
                  break;
      
              case _ZIPS_SORT_BY_ZIP_DESC:
                  krsort($return);
                  break;
          }
      
          $this->last_time = $this->chronometer();
      
          if (empty($return)) return false;
          return $return;
         }
      
    0 讨论(0)
  • 2020-12-02 15:19

    Check out the proximity search featured here:

    Using PHP/MySQL with Google Maps

    If your data is in the same notation / projection / format (whatever that's called), it may work for you.

    0 讨论(0)
  • 2020-12-02 15:23

    http://www.micahcarrick.com/04-19-2005/php-zip-code-range-and-distance-calculation.html

    I found this very awesome.

    "query the zip codes table for all the zip codes that fall within the radius then query the users table for all the users with the results(zip codes)"

    I found this is the best way to do it unless you need to put the users on a google map. If you're just listing the users in the mileage range it should be pretty easy to query the database (using the class) for a list of zips then select all users in those zipcodes.

    Select * from Users where zip_code IN (19125,19081,19107.........);
    

    That should do it.

    0 讨论(0)
  • 2020-12-02 15:30

    Here is the best way I have found. Of course it will require that you have all of your zipcodes lat/lon encoded in the database.

    // get all the zipcodes within the specified radius - default 20
    function zipcodeRadius($lat, $lon, $radius)
    {
        $radius = $radius ? $radius : 20;
        $sql = 'SELECT distinct(ZipCode) FROM zipcode  WHERE (3958*3.1415926*sqrt((Latitude-'.$lat.')*(Latitude-'.$lat.') + cos(Latitude/57.29578)*cos('.$lat.'/57.29578)*(Longitude-'.$lon.')*(Longitude-'.$lon.'))/180) <= '.$radius.';';
        $result = $this->db->query($sql);
        // get each result
        $zipcodeList = array();
        while($row = $this->db->fetch_array($result))
        {
            array_push($zipcodeList, $row['ZipCode']);
        }
        return $zipcodeList;
    }
    

    You should be able to just drop in this function. Pass it the $lat and $lon of the zipcode you want the radius for, include the optional radius, and get a list of zipcodes back.

    You could very easily modify this to get all users where zipcode IN (radius_sql) and get your list users back.

    Happy Coding!

    0 讨论(0)
提交回复
热议问题