老早就想总结这篇《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];
}