php實現搜尋附近的人的方法:首先聲明一個函數,用作計算經緯度的範圍;然後從資料庫中查找所有在這個經緯度範圍內符合條件的記錄;最後查詢經緯度在「$radius ”範圍內的電站的詳細地址即可。
#推薦:《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。因此,要注意單位變化。
我仍在努力求證,尋求有關專業的協助,獲得更精確的計算結果。
以上是php如何實現搜尋附近的人的詳細內容。更多資訊請關注PHP中文網其他相關文章!