first commit
This commit is contained in:
155
backend/ride/places_syria/reverse_geocode.php
Executable file
155
backend/ride/places_syria/reverse_geocode.php
Executable file
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
// ضبط الهيدر لإرجاع JSON بترميز UTF-8
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
// --- إعدادات الاتصال بقاعدة البيانات ---
|
||||
$servername = "localhost";
|
||||
$username = "routeuser"; // <== عدّل
|
||||
$password = "VETA9mX4tSZzm6AGouIM"; // <== عدّل
|
||||
$dbname = "routedb"; // <== عدّل
|
||||
|
||||
// --- استقبال الإحداثيات من الطلب ---
|
||||
$input_lat = isset($_GET['lat']) ? (float)$_GET['lat'] : null;
|
||||
$input_lon = isset($_GET['lon']) ? (float)$_GET['lon'] : null;
|
||||
|
||||
// التحقق من وجود الإحداثيات
|
||||
if ($input_lat === null || $input_lon === null) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Missing lat or lon parameters']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// --- الاتصال بقاعدة البيانات ---
|
||||
$conn = new mysqli($servername, $username, $password, $dbname);
|
||||
$conn->set_charset("utf8mb4");
|
||||
if ($conn->connect_error) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Database connection failed: ' . $conn->connect_error]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// --- دالة لتحليل other_tags (نفس الدالة من السكربت السابق) ---
|
||||
function parseHstoreValue($hstoreString, $keyToFind) {
|
||||
if (empty($hstoreString) || empty($keyToFind)) return null;
|
||||
if (preg_match('/"' . preg_quote($keyToFind, '/') . '"\s*=>\s*"([^"]+)"/', $hstoreString, $matches)) {
|
||||
$value = $matches[1];
|
||||
$decodedValue = urldecode($value);
|
||||
$decodedValue = urldecode($decodedValue);
|
||||
$cleanedValue = iconv('UTF-8', 'UTF-8//IGNORE', $decodedValue);
|
||||
return ($cleanedValue === false || trim($cleanedValue) === '') ? null : $cleanedValue;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// --- الاستعلام الرئيسي: البحث عن أقرب نقطة باستخدام الفهرس المكاني ---
|
||||
// نختار الأعمدة الأساسية + أعمدة المناطق المحسوبة مسبقاً + other_tags
|
||||
$sql = "
|
||||
SELECT
|
||||
p.name,
|
||||
p.neighbourhood_name,
|
||||
p.city_name,
|
||||
p.other_tags,
|
||||
ST_Distance_Sphere(
|
||||
p.geom,
|
||||
ST_PointFromText(CONCAT('POINT(', ?, ' ', ?, ')'), 4326)
|
||||
) AS distance_meters
|
||||
FROM
|
||||
osm_points_with_area p
|
||||
WHERE
|
||||
-- استخدام MBRContains للفلترة الأولية السريعة (باستخدام الفهرس المكاني)
|
||||
MBRContains(
|
||||
ST_Buffer(ST_PointFromText(CONCAT('POINT(', ?, ' ', ?, ')'), 4326), 0.01), -- مربع بحث ~ 1 كم
|
||||
p.geom
|
||||
)
|
||||
-- الترتيب الدقيق حسب المسافة الأقرب (يستخدم الفهرس المكاني بكفاءة)
|
||||
ORDER BY
|
||||
p.geom <-> ST_PointFromText(CONCAT('POINT(', ?, ' ', ?, ')'), 4326)
|
||||
LIMIT 1"; // نريد أقرب نقطة فقط
|
||||
|
||||
$stmt = $conn->prepare($sql);
|
||||
if ($stmt === false) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Failed to prepare statement: ' . $conn->error]);
|
||||
$conn->close();
|
||||
exit;
|
||||
}
|
||||
|
||||
// ربط المتغيرات (6 متغيرات: lon, lat مرتين للمربع ومرة للمسافة)
|
||||
$stmt->bind_param("dddddd", $input_lon, $input_lat, $input_lon, $input_lat, $input_lon, $input_lat);
|
||||
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
|
||||
// --- تنسيق وإرجاع النتيجة ---
|
||||
if ($result->num_rows > 0) {
|
||||
$row = $result->fetch_assoc();
|
||||
|
||||
// استخراج التفاصيل الإضافية من other_tags
|
||||
$name_ar = parseHstoreValue($row['other_tags'], 'name:ar');
|
||||
$addr_street = parseHstoreValue($row['other_tags'], 'addr:street');
|
||||
$amenity = parseHstoreValue($row['other_tags'], 'amenity');
|
||||
$shop = parseHstoreValue($row['other_tags'], 'shop');
|
||||
|
||||
// بناء اسم وصفي (الأولوية للعربي إن وجد)
|
||||
$primaryName = $name_ar ?? $row['name'] ?? $addr_street ?? null; // الاسم الأساسي للنقطة
|
||||
$displayName = $primaryName ?? 'موقع قريب'; // اسم افتراضي إذا لم يوجد اسم
|
||||
|
||||
// إضافة اسم الحي والمدينة (المحسوبة مسبقاً)
|
||||
$addressParts = array_filter([
|
||||
$row['neighbourhood_name'],
|
||||
$row['city_name']
|
||||
]);
|
||||
if (!empty($addressParts)) {
|
||||
// تجنب تكرار اسم المدينة إذا كان هو نفسه اسم النقطة
|
||||
if ($primaryName !== $row['city_name']) {
|
||||
$displayName .= '، ' . implode('، ', $addressParts);
|
||||
} elseif ($row['neighbourhood_name'] && $primaryName !== $row['neighbourhood_name']) {
|
||||
$displayName .= '، ' . $row['neighbourhood_name'];
|
||||
}
|
||||
}
|
||||
|
||||
// إرجاع النتيجة كـ JSON
|
||||
echo json_encode([
|
||||
'status' => 'ok',
|
||||
'display_name' => $displayName, // الاسم المنسق للعرض
|
||||
'name' => $row['name'], // الاسم الأصلي (إن وجد)
|
||||
'name_ar' => $name_ar, // الاسم العربي (إن وجد)
|
||||
'street' => $addr_street, // اسم الشارع (إن وجد)
|
||||
'neighbourhood' => $row['neighbourhood_name'], // اسم الحي (المحسوب مسبقاً)
|
||||
'city' => $row['city_name'], // اسم المدينة (المحسوب مسبقاً)
|
||||
'amenity' => $amenity, // نوع الخدمة (إن وجد)
|
||||
'shop' => $shop, // نوع المحل (إن وجد)
|
||||
'distance_meters' => round($row['distance_meters'], 1) // المسافة لأقرب POI
|
||||
], JSON_UNESCAPED_UNICODE); // مهم لعرض العربية بشكل صحيح
|
||||
|
||||
} else {
|
||||
// لم يتم العثور على نقطة قريبة، ابحث عن أقرب مدينة/حي كحل بديل
|
||||
$areaSqlFallback = "
|
||||
SELECT name, other_tags, place_type
|
||||
FROM osm_areas
|
||||
ORDER BY ST_Distance_Sphere(geom, ST_PointFromText(CONCAT('POINT(', ?, ' ', ?, ')'), 4326)) ASC
|
||||
LIMIT 1";
|
||||
$stmtFallback = $conn->prepare($areaSqlFallback);
|
||||
if ($stmtFallback) {
|
||||
$stmtFallback->bind_param("dd", $input_lon, $input_lat);
|
||||
$stmtFallback->execute();
|
||||
$fallbackResult = $stmtFallback->get_result()->fetch_assoc();
|
||||
$stmtFallback->close();
|
||||
|
||||
if ($fallbackResult) {
|
||||
$fallbackNameAr = parseHstoreValue($fallbackResult['other_tags'], 'name:ar');
|
||||
$fallbackDisplayName = $fallbackNameAr ?? $fallbackResult['name'] ?? 'منطقة غير معروفة';
|
||||
echo json_encode([
|
||||
'status' => 'ok',
|
||||
'display_name' => $fallbackDisplayName,
|
||||
($fallbackResult['place_type'] === 'city' || $fallbackResult['place_type'] === 'town' || $fallbackResult['place_type'] === 'village') ? 'city' : 'neighbourhood' => $fallbackDisplayName
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
} else {
|
||||
echo json_encode(['status' => 'not_found', 'message' => 'No nearby places or areas found']);
|
||||
}
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Fallback query failed: ' . $conn->error]);
|
||||
}
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
?>
|
||||
Reference in New Issue
Block a user