项目整体概述
项目的核心是一个数据库查询脚本,其主要功能是依据不同的服务类型,从多个数据库表(poi、user、team)中查询相关记录,并计算这些记录所代表的地点与指定城市之间的距离。最终,筛选出距离小于等于给定值的记录。该项目可用于在地理信息系统中查找特定范围内的兴趣点、用户或团队。
核心代码
// 定义计算距离的函数
function calculateDistance($city_lat, $lng1, $lat1) {
return "ROUND((6378.137 * acos(cos(radians($city_lat)) * cos(radians($lat1)) * cos(radians($lng1) - radians($city_lng)) + sin(radians($city_lat)) * sin(radians($lat1)))),2)";
}
// 检查必要变量是否定义
if (!isset($serviceType, $city_lat, $city_lng, $db, $listDistance)) {
die("必要变量未定义");
}
// 确保 $listDistance 是有效的数值
if (!is_numeric($listDistance)) {
die("listDistance 必须是一个有效的数值");
}
if (!$serviceType || $serviceType === "服务类型") {
$distance = calculateDistance($city_lat, 'poi_longitude', 'poi_latitude');
$innerSql = "
(SELECT
poi_token,
poi_type,
poi_longitude,
poi_latitude,
poi_amount,
$distance AS poi_distance,
'poi' AS type
FROM " . $db->table("poi") . "
)
UNION ALL
(
SELECT
poi_token,
'u' AS poi_type,
user_longitude AS poi_longitude,
user_latitude AS poi_latitude,
user_roles AS poi_amount,
".calculateDistance($city_lat, 'user_longitude', 'user_latitude')." AS poi_distance,
'user' AS type
FROM " . $db->table("user") . "
WHERE user_roles = 1
)
UNION ALL
(SELECT
poi_token,
't' AS poi_type,
team_longitude AS poi_longitude,
team_latitude AS poi_latitude,
team_grade AS poi_amount,
".calculateDistance($city_lat, 'team_longitude', 'team_latitude')." AS poi_distance,
'team' AS type
FROM " . $db->table("team") . "
)";
} else if ($serviceType === "追回类型") {
$distance = calculateDistance($city_lat, 'poi_longitude', 'poi_latitude');
$innerSql = "SELECT
poi_token,
poi_type,
poi_longitude,
poi_latitude,
poi_amount,
$distance AS poi_distance,
'poi' AS type
FROM " . $db->table("poi") . " LIMIT 200";
} else if ($serviceType === "追回团队") {
$distance = calculateDistance($city_lat, 'team_longitude', 'team_latitude');
$innerSql = "SELECT
poi_token,
't' AS poi_type,
team_longitude AS poi_longitude,
team_latitude AS poi_latitude,
team_grade AS poi_amount,
$distance AS poi_distance,
'team' AS type
FROM " . $db->table("team") . "
LIMIT 200";
} else {
$distance = calculateDistance($city_lat, 'user_longitude', 'user_latitude');
$innerSql = "SELECT
poi_token,
'u' AS poi_type,
user_longitude AS poi_longitude,
user_latitude AS poi_latitude,
user_roles AS poi_amount,
$distance AS poi_distance,
'user' AS type
FROM " . $db->table("user") . "
WHERE user_roles = 1
LIMIT 200";
}
// 把内部查询作为子查询,并添加 HAVING 子句
$sql = "SELECT * FROM ($innerSql) AS subquery HAVING poi_distance <= $listDistance";
// 执行查询并处理错误
$row = $db->queryall($sql);
if (!$row) {
// 处理查询错误
echo "查询出错: ". $db->error;
}优势
- 灵活性高
通过 $serviceType 变量,可以灵活切换不同的查询逻辑,满足多种业务需求。例如,既可以进行多表联合查询,也可以单独查询某个表。 - 可扩展性强
定义了 calculateDistance 函数来计算距离,方便代码的复用和扩展。如果后续需要修改距离计算方式,只需修改该函数即可。 - 错误处理完善
在代码中对必要变量进行了检查,确保变量已定义且类型正确。同时,在执行查询时对可能出现的错误进行了处理,方便调试和排查问题。
劣势
- SQL 注入风险
虽然对 $listDistance 进行了数值检查,但直接将变量嵌入 SQL 语句,仍然存在 SQL 注入的潜在风险。攻击者可能通过构造特殊的输入值来改变 SQL 语句的原意,从而获取或篡改数据库中的数据。 - 性能问题
多表联合查询:使用 UNION ALL 合并多个查询结果,当数据量较大时,会增加数据库的处理负担,导致查询性能下降。
距离计算:在 SQL 查询中使用复杂的距离计算公式,每次查询都需要进行大量的三角函数运算,也会影响查询性能。 - 代码复杂度高
由于需要根据不同的服务类型构建不同的查询语句,代码中存在较多的条件判断和重复代码,增加了代码的维护难度。 - 缺乏缓存机制
每次执行查询时都会直接访问数据库,没有使用缓存机制。如果相同的查询条件频繁出现,会造成不必要的数据库开销。
@漏刻有时
















