PHP实现搜索附近的人

简介: 最近的一个项目要求根据用户当前位置的经纬度来查询该用户方圆十公里以内的人,这个功能并不是什么很有技术含量的实现(当然,我们仅仅指的是该功能本身和数据量较小的时候,并不包括长期以来其派生出来的其他问题 ),但由于种种考虑,我还是决定将其记录下来。

最近的一个项目要求根据用户当前位置的经纬度来查询该用户方圆十公里以内的人,这个功能并不是什么很有技术含量的实现(当然,我们仅仅指的是该功能本身和数据量较小的时候,并不包括长期以来其派生出来的其他问题 ),但由于种种考虑,我还是决定将其记录下来。
以后不管我们从事APP服务端开发,还是做WEB开发,可能经常会有客户要求实现这样的功能,所以我们还是要掌握其原理。

【问题的提出】

我们该如何思考这个问题 ? 可能有的小伙伴要说了:“ 既然我们已经知道了当前用户的经纬度,我们从数据库里面查询用户的经纬度,然后一一计算,筛选出所有符合条件的用户。”

我也曾想当然的这样认为,并没有考虑到数据库的感受,当你操作的是一个十万,百万级别的数据库时,这样的做法带来的问题将是灾难性的,那么我们到底该如何做呢 ?

【实现思路】

首先,我们应该这样想: 既然我们知道了用户当前位置的经纬度,又知道我们将要搜索的范围,我们可不可以计算出一个范围 ?也就是说,根据一个中心点和半径,计算出符合条件的经纬度的最大值和最小值 。

【具体实现】

那么到此,想要独立思考完成的小伙伴可以不要继续往下看了。

上面我们提到该功能的一个实现原理,接下来我们就讲解一下具体的实现步骤。

我们先声明一个函数,用作计算经纬度的范围:

/**
 * 根据经纬度和半径计算出范围
 * @param string $lat 纬度
 * @param String $lng 经度
 * @param float $radius 半径
 * @return Array 范围数组
 */
private function calcScope($lat, $lng, $radius) {
    $degree = (24901*1609)/360.0;
    $dpmLat = 1/$degree;

    $radiusLat = $dpmLat*$radius;
    $minLat = $lat - $radiusLat;       // 最小纬度
    $maxLat = $lat + $radiusLat;       // 最大纬度

    $mpdLng = $degree*cos($lat * (PI/180));
    $dpmLng = 1 / $mpdLng;
    $radiusLng = $dpmLng*$radius;
    $minLng = $lng - $radiusLng;      // 最小经度
    $maxLng = $lng + $radiusLng;      // 最大经度

    /** 返回范围数组 */
    $scope = array(
        'minLat'    =>  $minLat,
        'maxLat'    =>  $maxLat,
        'minLng'    =>  $minLng,
        'maxLng'    =>  $maxLng
        );
    return $scope;
}

返回的数组中包含了在 $radius 范围内,符合条件的最大最小经纬度。

既然我们已经获取到了范围,那么我们就可以开始从数据库中查找所有在这个经纬度范围内符合条件的记录:

/**
 * 根据经纬度和半径查询在此范围内的所有的
 * @param  String $lat    纬度
 * @param  String $lng    经度
 * @param  float $radius 半径
 * @return Array         计算出来的结果
 */
public function searchByLatAndLng($lat, $lng, $radius) {
    $scope = $this->calcScope($lat, $lng, $radius);     // 调用范围计算函数,获取最大最小经纬度
    /** 查询经纬度在 $radius 范围内的电站的详细地址 */
    $sql = 'SELECT `字段` FROM `表名` WHERE `Latitude` < '.$scope['maxLat'].' and `Latitude` > '.$scope['minLat'].' and `Longitude` < '.$scope['maxLng'].' and `Longitude` > '.$scope['minLng'];

    $stmt = self::$db->query($sql);
    $res = $stmt->fetchAll(PDO::FETCH_ASSOC);       // 获取查询结果并返回
    return $res;
}

【扩展】

直到现在,我们已经知道了如何计算出附近的人,但在实际需求中,我们往往需要计算出每一个人与当前中心点的实际距离。

接着,我们再来看一个方法:


/**
 * 获取两个经纬度之间的距离
 * @param  string $lat1 纬一
 * @param  String $lng1 经一
 * @param  String $lat2 纬二
 * @param  String $lng2 经二
 * @return float  返回两点之间的距离
 */
public function calcDistance($lat1, $lng1, $lat2, $lng2) {
    /** 转换数据类型为 double */
    $lat1 = doubleval($lat1);
    $lng1 = doubleval($lng1);
    $lat2 = doubleval($lat2);
    $lng2 = doubleval($lng2);
    /** 以下算法是 Google 出来的,与大多数经纬度计算工具结果一致 */
    $theta = $lng1 - $lng2;
    $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
    $dist = acos($dist);
    $dist = rad2deg($dist);
    $miles = $dist * 60 * 1.1515;
    return ($miles * 1.609344);
}

我们在之前已经计算出了附近符合条件的所有人的经纬度,那么我们可以将每一个人的经纬度和当前中心点的经纬度作为参数传入该函数,最终计算出每个人符合条件的人与该中心点的距离。

为了保证程序的严谨性,我必须做出以下说明:

经纬度范围的计算方法是在百度上查找的,目前尚没有找到标准的计算工具,因此该算法无法求证,但大多数帖子基本上采用的这种计算方式。
经纬度距离的计算方式是在 Google 上查找的,计算结果与大多数计算工具结果相近。之所以在 Google 中查找,是因为我曾在百度上查找过多种计算方式,结果都不尽人意。
通过半径和经纬度计算范围时,半径的单位是m;计算距离时,得到的结果是km。因此,要注意单位变化。
我依然在努力求证,寻求有关专业的帮助,获得更精确的计算结果。

作者:Elvis_Li
链接:http://www.jianshu.com/p/d2080a9b87eb
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

相关文章
|
5月前
|
安全 关系型数据库 PHP
百度搜索:蓝易云【php适合做erp吗?】
虽然PHP在ERP开发中具有很多优势,但在实际开发中还需要根据项目的具体需求和规模来选择合适的技术栈和架构。ERP系统通常是复杂的,需要综合考虑数据库设计、安全性、性能等因素。因此,在开发ERP系统时,建议仔细规划和设计,充分了解业务需求,并选择适合的技术和开发工具来实现一个稳定、高效、安全的ERP系统。
51 0
|
5月前
|
存储 算法 安全
百度搜索:蓝易云【php几种常用的加密解密算法】
请注意,以上算法都有各自的特点和用途,选择合适的加密解密算法应根据具体需求和安全性要求。此外,加密只是数据保护的一部分,安全实现还应考虑其他因素,如密钥管理、访问控制和安全传输等。
75 0
|
11月前
|
PHP 开发者
百度搜索:蓝易云【PHP trait的使用方法】
通过以上方法,我们可以充分利用PHP trait来实现代码复用和组合,提高代码的灵活性和可维护性。
107 3
|
5月前
|
关系型数据库 MySQL
web简易开发(二){html5+php实现文件上传及通过关键字搜索已上传图片)}
web简易开发(二){html5+php实现文件上传及通过关键字搜索已上传图片)}
|
4月前
|
SQL 监控 安全
代码审计-PHP原生开发篇&SQL注入&数据库监控&正则搜索&文件定位&静态分析
代码审计-PHP原生开发篇&SQL注入&数据库监控&正则搜索&文件定位&静态分析
|
关系型数据库 MySQL Linux
百度搜索:蓝易云【Centos8 stream系统编译安装PHP教程。】
以上是在CentOS 8 Stream系统上编译安装PHP的基本教程。请注意,具体的配置和参数可能因您的需求而有所不同,您可以根据自己的情况进行调整。同时,请确保在执行任何操作之前备份重要的文件和配置。
255 0
|
5月前
|
缓存 NoSQL PHP
百度搜索:蓝易云【如何使用PHP进行数据库索引优化?】
通过以上方法,你可以使用PHP进行数据库索引优化,提高数据库查询性能和整体应用性能。同时,定期维护数据库和优化查询语句也是保持数据库高性能的关键。
70 11
|
5月前
|
SQL PHP 数据库
php实现搜索功能(不加任何修饰,提供全部)
php实现搜索功能(不加任何修饰,提供全部)
php实现搜索功能(不加任何修饰,提供全部)
|
5月前
|
搜索推荐 小程序 Linux
分享88个搜索链接PHP源码,总有一款适合你
分享88个搜索链接PHP源码,总有一款适合你
233 0