本文目录导读:

在PHP中计算两点经纬度之间的直线距离,最常用的方法是Haversine公式,以下是几种实现的示例:
Haversine公式(最常用,精度较高)
function haversineDistance($lat1, $lon1, $lat2, $lon2) {
$earthRadius = 6371; // 地球半径,单位:公里
// 如果希望得到英里,使用 3959
// 将角度转换为弧度
$latFrom = deg2rad($lat1);
$lonFrom = deg2rad($lon1);
$latTo = deg2rad($lat2);
$lonTo = deg2rad($lon2);
// 计算纬度和经度的差值
$latDelta = $latTo - $latFrom;
$lonDelta = $lonTo - $lonFrom;
// Haversine公式
$a = sin($latDelta / 2) * sin($latDelta / 2) +
cos($latFrom) * cos($latTo) *
sin($lonDelta / 2) * sin($lonDelta / 2);
$c = 2 * asin(sqrt($a));
// 最终距离
$distance = $earthRadius * $c;
return $distance;
}
// 使用示例
$lat1 = 39.9042; // 北京纬度
$lon1 = 116.4074; // 北京经度
$lat2 = 31.2304; // 上海纬度
$lon2 = 121.4737; // 上海经度
$distance = haversineDistance($lat1, $lon1, $lat2, $lon2);
echo "北京到上海的直线距离约为:" . round($distance, 2) . " 公里";
使用PHP的atan2版本(更精确)
function getDistance($lat1, $lon1, $lat2, $lon2) {
$earthRadius = 6371; // 公里
$latFrom = deg2rad($lat1);
$lonFrom = deg2rad($lon1);
$latTo = deg2rad($lat2);
$lonTo = deg2rad($lon2);
$lonDelta = $lonTo - $lonFrom;
$a = pow(cos($latTo) * sin($lonDelta), 2) +
pow(cos($latFrom) * sin($latTo) - sin($latFrom) * cos($latTo) * cos($lonDelta), 2);
$b = sin($latFrom) * sin($latTo) + cos($latFrom) * cos($latTo) * cos($lonDelta);
$angle = atan2(sqrt($a), $b);
return $angle * $earthRadius;
}
返回多种单位的版本
function calculateDistance($lat1, $lon1, $lat2, $lon2, $unit = 'km') {
$earthRadius = [
'km' => 6371,
'mi' => 3959,
'm' => 6371000,
'nm' => 3440.065 // 海里
];
if (!isset($earthRadius[$unit])) {
$unit = 'km';
}
$latFrom = deg2rad($lat1);
$lonFrom = deg2rad($lon1);
$latTo = deg2rad($lat2);
$lonTo = deg2rad($lon2);
$latDelta = $latTo - $latFrom;
$lonDelta = $lonTo - $lonFrom;
$angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) +
cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)));
return $earthRadius[$unit] * $angle;
}
// 使用示例
echo calculateDistance(39.9042, 116.4074, 31.2304, 121.4737, 'km'); // 公里
echo calculateDistance(39.9042, 116.4074, 31.2304, 121.4737, 'mi'); // 英里
批量计算距离(适合数据库查询)
function getDistanceSQL($lat, $lng, $tableName = 'locations') {
// 这个SQL可以用于MySQL数据库查询附近的地点
$sql = "SELECT *,
(6371 * acos(
cos(radians($lat)) *
cos(radians(latitude)) *
cos(radians(longitude) - radians($lng)) +
sin(radians($lat)) *
sin(radians(latitude))
)) AS distance
FROM $tableName
HAVING distance < 50
ORDER BY distance";
return $sql;
}
使用geotools库(推荐用于复杂项目)
如果项目需要更复杂的地理计算,可以使用Composer安装geotools:
composer require league/geotools
use League\Geotools\Coordinate\Coordinate;
use League\Geotools\Distance\Vincenty;
function geotoolsDistance($lat1, $lon1, $lat2, $lon2) {
$coordA = new Coordinate([$lat1, $lon1]);
$coordB = new Coordinate([$lat2, $lon2]);
$calculator = new Vincenty();
$distance = $calculator->setFrom($coordA)->setTo($coordB)->calculate();
return $distance->get(); // 返回米
}
精度对比
- Haversine公式:精度约0.5%,适合大多数应用场景
- Vincenty公式:精度更高(<0.5mm),但计算更复杂
- 球面余弦定律:适合短距离计算,对长距离精度会下降
注意事项
- 经纬度格式:确保使用十进制度数,而非度分秒格式
- 地球模型:上述计算假设地球是完美球体,实际为椭球体,但误差通常可接受
- 性能考虑:如果需要大量计算,建议在数据库层直接使用SQL计算
推荐在实际项目中使用第一种Haversine公式,兼顾了精度和性能。