php实现lbs实现商品筛选
PHP 实现 LBS 商品筛选
LBS(Location-Based Service)商品筛选通常涉及根据用户地理位置筛选附近商品。以下是实现方法:
数据库设计
商品表需包含经纬度字段,例如:

CREATE TABLE `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`latitude` decimal(10,6) NOT NULL,
`longitude` decimal(10,6) NOT NULL,
PRIMARY KEY (`id`)
);
计算距离
使用 Haversine 公式计算两点间距离(单位:公里):
function calculateDistance($lat1, $lon1, $lat2, $lon2) {
$earthRadius = 6371;
$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 * asin(sqrt($a));
return $earthRadius * $c;
}
MySQL 查询优化
直接使用 SQL 计算距离并筛选:

SELECT
id,
name,
(6371 * acos(cos(radians(?)) * cos(radians(latitude)) * cos(radians(longitude) - radians(?)) + sin(radians(?)) * sin(radians(latitude)))) AS distance
FROM
products
HAVING
distance < ?
ORDER BY
distance
LIMIT 20
Redis GEO 优化
对于高性能场景,可使用 Redis GEO 命令:
$redis->geoadd('products:geo', $longitude, $latitude, $productId);
$results = $redis->georadius('products:geo', $userLon, $userLat, $radius, 'km', ['WITHDIST']);
前端集成
获取用户位置后通过 AJAX 提交:
navigator.geolocation.getCurrentPosition(function(position) {
$.post('/api/nearby-products', {
lat: position.coords.latitude,
lng: position.coords.longitude,
radius: 5 // 5公里范围
});
});
性能优化建议
- 为经纬度字段创建复合索引:
INDEX(latitude, longitude) - 使用存储过程预处理距离计算
- 对静态商品数据可预先计算网格分区
- 考虑使用 MongoDB 等支持地理查询的数据库
完整示例代码
// 接收前端参数
$userLat = $_POST['lat'];
$userLon = $_POST['lng'];
$radius = $_POST['radius'] ?? 5;
// 查询数据库
$stmt = $pdo->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' => $userLon,
':radius' => $radius
]);
$products = $stmt->fetchAll(PDO::FETCH_ASSOC);
header('Content-Type: application/json');
echo json_encode($products);






