老早就想总结这篇《PHP+MySQL基于地理位置信息的附近好友交友的实现》的文章了,受限于工作时间问题,今天把它写出来,起个抛砖引玉的作用。我们都知道,基于地理位置信息的APP有很多,例如微信、陌陌等等,本文以小白的视野来探究其功能用PHP+MySQL是怎么实现的?
在开始这个功能实现过程前,本人对微信、陌陌的附近好友功能也进行了一翻研究,其基本原理大致如下:
图1 基于地理位置信息的附近交友的实现原理图
从上图可以看出,用户要获取附近用户列表,需要先获取自生的GPS信息,再把GPS信息提交给WEB服务器,WEB服务器到数据库中查询附近的人,再返回用户列表给用户,这是基本原理。至于如何数据库查询实现基于地理位置信息的附近交友,下面重点讲解。
首先,建议数据库,结构如下:
CREATE TABLE IF NOT EXISTS `nearby` ( `id` int(11) unsigned NOT NULL, `name` varchar(40) NOT NULL COMMENT '用户名', `longitude` varchar(10) NOT NULL COMMENT '经度', `latitude` varchar(10) NOT NULL COMMENT '纬度' ) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; -- -- 转存表中的数据 `nearby` -- INSERT INTO `nearby` (`id`, `name`, `longitude`, `latitude`) VALUES (1, 'demo', '12.2222544', '65.54451'), (2, 'demo1', '12.2222844', '65.54751'), (3, 'demo2', '12.5222844', '65.55751'), (4, 'demo3', '12.5226844', '65.58751'); -- -- Indexes for dumped tables -- -- -- Indexes for table `nearby` -- ALTER TABLE `nearby` ADD PRIMARY KEY (`id`); -- -- AUTO_INCREMENT for dumped tables -- -- -- AUTO_INCREMENT for table `nearby` -- ALTER TABLE `nearby` MODIFY `id` int(11) unsigned NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=5;
为方便说明,本文以轻量级的PHP数据库框架Medoo为数据库链接,安装如下:
composer require catfan/Medoo
安装完成后就开始以PHP编写API了,代码如下:
<?php require 'vendor/autoload.php'; use Medoo\Medoo; $database = new Medoo([ 'type' => 'mysql', 'host' => 'localhost', 'database' => 'data', 'username' => 'root', 'password' => 'password' ]); //为方便编写,用户ID直接前台传来,实际开发过程中建议使用session或cookie或其它用户验证 $id =isset($_GET['id'])?$_GET['id']:0; //获取经纬度 $longitude = isset($_GET['longitude'])?$_GET['longitude']:0; $latitude = isset($_GET['latitude'])?$_GET['latitude']:0; //更新户自己的GPS信息 $database->update("nearby", [ "longitude" => $longitude, "latitude" => $latitude ], [ "id" =>$id ]); //访问以下地址获取附近用户 http://xxx.com/?id=1&longitude=12.2222544&latitude=65.54451 $longitudeAndLatitude = getAround($longitude, $latitude, '100'); $datas = $database->select("account", [ "user_name", "email" ], [ "user_id[>]" => 100 ]); $list = $database->query("SELECT *,(st_distance(point(longitude,latitude),point('{$longitude}','{$latitude}'))*95000/1000) as distance FROM nearby WHERE id != '{$id}' AND longitude >= '{$longitudeAndLatitude['minLng']}' AND longitude <= '{$longitudeAndLatitude['maxLng']}' AND latitude >= '{$longitudeAndLatitude['minLat']}' AND latitude <= '{$longitudeAndLatitude['maxLat']}' ORDER BY distance ASC limit 10") ->fetchAll(); print_r($database->log()); print_r($list); /** * * 函数:根据经纬度及半径范围(单位:千米)返回坐标 * @param string $longitude 经度 * @param string $latitude 纬度 * @param string $raidus 范围,千米 * **/ function getAround($longitude, $latitude, $raidus) { $PI = pi(); $raidus = $raidus*1000; $degree = (24901*1609)/360.0; $dpmLat = 1/$degree; $radiusLat = $dpmLat*$raidus; $minLat = $latitude - $radiusLat; $maxLat = $latitude + $radiusLat; $mpdLng = $degree*cos($latitude * ($PI/180)); $dpmLng = 1 / $mpdLng; $radiusLng = $dpmLng*$raidus; $minLng = $longitude - $radiusLng; $maxLng = $longitude + $radiusLng; return ['minLat'=>$minLat, 'maxLat'=>$maxLat, 'minLng'=>$minLng, 'maxLng'=>$maxLng]; }