溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

php怎么實(shí)現(xiàn)搜索附近的人

發(fā)布時(shí)間:2020-10-23 14:09:30 來(lái)源:億速云 閱讀:141 作者:小新 欄目:編程語(yǔ)言

php怎么實(shí)現(xiàn)搜索附近的人?這個(gè)問(wèn)題可能是我們?nèi)粘W(xué)習(xí)或工作經(jīng)常見到的。希望通過(guò)這個(gè)問(wèn)題能讓你收獲頗深。下面是小編給大家?guī)?lái)的參考內(nèi)容,讓我們一起來(lái)看看吧!

php實(shí)現(xiàn)搜索附近的人的方法:首先聲明一個(gè)函數(shù),用作計(jì)算經(jīng)緯度的范圍;然后從數(shù)據(jù)庫(kù)中查找所有在這個(gè)經(jīng)緯度范圍內(nèi)符合條件的記錄;最后查詢經(jīng)緯度在“$radius”范圍內(nèi)的電站的詳細(xì)地址即可。

最近的一個(gè)項(xiàng)目要求根據(jù)用戶當(dāng)前位置的經(jīng)緯度來(lái)查詢?cè)撚脩舴綀A十公里以內(nèi)的人,這個(gè)功能并不是什么很有技術(shù)含量的實(shí)現(xiàn)(當(dāng)然,我們僅僅指的是該功能本身和數(shù)據(jù)量較小的時(shí)候,并不包括長(zhǎng)期以來(lái)其派生出來(lái)的其他問(wèn)題 ),但由于種種考慮,我還是決定將其記錄下來(lái)。
以后不管我們從事APP服務(wù)端開發(fā),還是做WEB開發(fā),可能經(jīng)常會(huì)有客戶要求實(shí)現(xiàn)這樣的功能,所以我們還是要掌握其原理。

【問(wèn)題的提出】

我們?cè)撊绾嗡伎歼@個(gè)問(wèn)題 ? 可能有的小伙伴要說(shuō)了:“ 既然我們已經(jīng)知道了當(dāng)前用戶的經(jīng)緯度,我們從數(shù)據(jù)庫(kù)里面查詢用戶的經(jīng)緯度,然后一一計(jì)算,篩選出所有符合條件的用戶?!?/p>

我也曾想當(dāng)然的這樣認(rèn)為,并沒(méi)有考慮到數(shù)據(jù)庫(kù)的感受,當(dāng)你操作的是一個(gè)十萬(wàn),百萬(wàn)級(jí)別的數(shù)據(jù)庫(kù)時(shí),這樣的做法帶來(lái)的問(wèn)題將是災(zāi)難性的,那么我們到底該如何做呢 ?

【實(shí)現(xiàn)思路】

首先,我們應(yīng)該這樣想: 既然我們知道了用戶當(dāng)前位置的經(jīng)緯度,又知道我們將要搜索的范圍,我們可不可以計(jì)算出一個(gè)范圍 ?也就是說(shuō),根據(jù)一個(gè)中心點(diǎn)和半徑,計(jì)算出符合條件的經(jīng)緯度的最大值和最小值 。

【具體實(shí)現(xiàn)】

那么到此,想要獨(dú)立思考完成的小伙伴可以不要繼續(xù)往下看了。

上面我們提到該功能的一個(gè)實(shí)現(xiàn)原理,接下來(lái)我們就講解一下具體的實(shí)現(xiàn)步驟。

我們先聲明一個(gè)函數(shù),用作計(jì)算經(jīng)緯度的范圍:

/**
 * 根據(jù)經(jīng)緯度和半徑計(jì)算出范圍
 * @param string $lat 緯度
 * @param String $lng 經(jīng)度
 * @param float $radius 半徑
 * @return Array 范圍數(shù)組
 */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;      // 最小經(jīng)度
    $maxLng = $lng + $radiusLng;      // 最大經(jīng)度

    /** 返回范圍數(shù)組 */
    $scope = array(        'minLat'    =>  $minLat,        'maxLat'    =>  $maxLat,        'minLng'    =>  $minLng,        'maxLng'    =>  $maxLng
        );    return $scope;
}

返回的數(shù)組中包含了在 $radius 范圍內(nèi),符合條件的最大最小經(jīng)緯度。

既然我們已經(jīng)獲取到了范圍,那么我們就可以開始從數(shù)據(jù)庫(kù)中查找所有在這個(gè)經(jīng)緯度范圍內(nèi)符合條件的記錄:

/**
 * 根據(jù)經(jīng)緯度和半徑查詢?cè)诖朔秶鷥?nèi)的所有的
 * @param  String $lat    緯度
 * @param  String $lng    經(jīng)度
 * @param  float $radius 半徑
 * @return Array         計(jì)算出來(lái)的結(jié)果
 */public function searchByLatAndLng($lat, $lng, $radius) {
    $scope = $this->calcScope($lat, $lng, $radius);     // 調(diào)用范圍計(jì)算函數(shù),獲取最大最小經(jīng)緯度
    /** 查詢經(jīng)緯度在 $radius 范圍內(nèi)的電站的詳細(xì)地址 */
    $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);       // 獲取查詢結(jié)果并返回
    return $res;
}

【擴(kuò)展】

直到現(xiàn)在,我們已經(jīng)知道了如何計(jì)算出附近的人,但在實(shí)際需求中,我們往往需要計(jì)算出每一個(gè)人與當(dāng)前中心點(diǎn)的實(shí)際距離。

接著,我們?cè)賮?lái)看一個(gè)方法:

/**
 * 獲取兩個(gè)經(jīng)緯度之間的距離
 * @param  string $lat1 緯一
 * @param  String $lng1 經(jīng)一
 * @param  String $lat2 緯二
 * @param  String $lng2 經(jīng)二
 * @return float  返回兩點(diǎn)之間的距離 */public function calcDistance($lat1, $lng1, $lat2, $lng2) {    /** 轉(zhuǎn)換數(shù)據(jù)類型為 double */
    $lat1 = doubleval($lat1);    $lng1 = doubleval($lng1);    $lat2 = doubleval($lat2);    $lng2 = doubleval($lng2);    /** 以下算法是 Google 出來(lái)的,與大多數(shù)經(jīng)緯度計(jì)算工具結(jié)果一致 */
    $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);
}

我們?cè)谥耙呀?jīng)計(jì)算出了附近符合條件的所有人的經(jīng)緯度,那么我們可以將每一個(gè)人的經(jīng)緯度和當(dāng)前中心點(diǎn)的經(jīng)緯度作為參數(shù)傳入該函數(shù),最終計(jì)算出每個(gè)人符合條件的人與該中心點(diǎn)的距離。

為了保證程序的嚴(yán)謹(jǐn)性,我必須做出以下說(shuō)明:

經(jīng)緯度范圍的計(jì)算方法是在百度上查找的,目前尚沒(méi)有找到標(biāo)準(zhǔn)的計(jì)算工具,因此該算法無(wú)法求證,但大多數(shù)帖子基本上采用的這種計(jì)算方式。
經(jīng)緯度距離的計(jì)算方式是在 Google 上查找的,計(jì)算結(jié)果與大多數(shù)計(jì)算工具結(jié)果相近。之所以在 Google 中查找,是因?yàn)槲以诎俣壬喜檎疫^(guò)多種計(jì)算方式,結(jié)果都不盡人意。
通過(guò)半徑和經(jīng)緯度計(jì)算范圍時(shí),半徑的單位是m;計(jì)算距離時(shí),得到的結(jié)果是km。因此,要注意單位變化。
我依然在努力求證,尋求有關(guān)專業(yè)的幫助,獲得更精確的計(jì)算結(jié)果。

感謝各位的閱讀!看完上述內(nèi)容,你們對(duì)php怎么實(shí)現(xiàn)搜索附近的人大概了解了嗎?希望文章內(nèi)容對(duì)大家有所幫助。如果想了解更多相關(guān)文章內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

php
AI