php实现lbs实现商品筛选
使用 PHP 实现 LBS(基于位置的服务)商品筛选
数据库设计
确保商品表包含经纬度字段(如 latitude 和 longitude),用于存储商品的地理位置信息。示例表结构:
CREATE TABLE `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`latitude` decimal(10,8) NOT NULL,
`longitude` decimal(11,8) NOT NULL,
PRIMARY KEY (`id`)
);
计算距离的公式
使用 Haversine 公式计算两点之间的球面距离。公式如下: $$ a = \sin²(\Deltaφ/2) + \cos φ_1 \cdot \cos φ_2 \cdot \sin²(\Deltaλ/2) \ c = 2 \cdot \text{atan2}(\sqrt{a}, \sqrt{1-a}) \ d = R \cdot c $$ 其中:
- $φ$ 是纬度,$λ$ 是经度
- $R$ 是地球半径(约 6371 km)
- $\Deltaφ = φ_2 - φ_1$,$\Deltaλ = λ_2 - λ_1$
PHP 实现距离计算
在 PHP 中封装距离计算函数:
function calculateDistance($lat1, $lon1, $lat2, $lon2) {
$earthRadius = 6371; // km
$dLat = deg2rad($lat2 - $lat1);
$dLon = deg2rad($lon2 - $lon1);
$a = sin($dLat/2) * sin($dLat/2) +
cos(deg2rad($lat1)) * cos(deg2rad($lat2)) *
sin($dLon/2) * sin($dLon/2);
$c = 2 * atan2(sqrt($a), sqrt(1-$a));
return $earthRadius * $c;
}
SQL 查询优化
直接使用 SQL 计算距离并筛选附近商品:
SELECT
id,
name,
(6371 * acos(cos(radians(:user_lat)) * cos(radians(latitude)) *
cos(radians(longitude) - radians(:user_lng)) + sin(radians(:user_lat)) *
sin(radians(latitude)))) AS distance
FROM
products
HAVING
distance < :radius
ORDER BY
distance;
完整 PHP 实现示例
function getNearbyProducts($userLat, $userLng, $radiusKm) {
$db = new PDO('mysql:host=localhost;dbname=your_db', 'username', 'password');
$stmt = $db->prepare("
SELECT
id,
name,
(6371 * acos(cos(radians(:lat)) * cos(radians(latitude)) *
cos(radians(longitude) - radians(:lng)) + sin(radians(:lat)) *
sin(radians(latitude)))) AS distance
FROM
products
HAVING
distance < :radius
ORDER BY
distance
");
$stmt->execute([
':lat' => $userLat,
':lng' => $userLng,
':radius' => $radiusKm
]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// 示例用法
$nearbyProducts = getNearbyProducts(31.2304, 121.4737, 5); // 上海5公里内的商品
性能优化建议
对于大规模数据,考虑以下优化方案:
- 使用 MySQL 的空间扩展(SPATIAL INDEX)和
POINT数据类型 - 预先计算地理哈希(GeoHash)并建立索引
- 使用 Redis 的 GEO 命令集实现高效地理位置查询
- 分区查询:先按大致范围筛选,再精确计算距离
前端集成
将用户位置通过浏览器 Geolocation API 获取后传递给后端:
navigator.geolocation.getCurrentPosition(
(position) => {
const lat = position.coords.latitude;
const lng = position.coords.longitude;
// AJAX请求发送到PHP后端
},
(error) => console.error(error)
);
这种方法实现了完整的 LBS 商品筛选功能,从数据库设计到前后端交互,可根据实际需求调整查询半径和性能优化策略。







