Files
Siro/backend/ride/rides/arrive_ride.php
T

150 lines
7.0 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// arrive_ride.php
require_once __DIR__ . '/../../connect.php';
try {
$con_ride = Database::get('ride');
} catch (Exception $e) {
error_log("[arrive_ride] Failed to connect to Ride Database: " . $e->getMessage());
}
$rideId = filterRequest("ride_id");
$driverId = filterRequest("driver_id");
$passengerToken = filterRequest("passengerToken");
if (!$rideId || !$driverId) {
jsonError("Missing required parameters.");
exit;
}
// ‏نصف قطر قبول ختم الوصول. أوسع من فحص الـ100م في التطبيق بهامش يستوعب
// ‏ضعف الـGPS بين المباني، وأضيق من أن يسمح بالختم من حي آخر.
const ARRIVAL_STAMP_RADIUS_KM = 0.30;
try {
// 1. تحديث الحالة في السيرفر البعيد (Remote DB - con_ride)
$stmtRemote = $con_ride->prepare("UPDATE ride SET status = 'arrived', updated_at = NOW() WHERE id = ? AND driver_id = ? AND status = 'Apply'");
$stmtRemote->execute([$rideId, $driverId]);
// 2. تحديث الحالة في السيرفر المحلي (Local DB - con)
if (isset($con)) {
$stmtLocal = $con->prepare("UPDATE ride SET status = 'arrived', updated_at = NOW() WHERE id = ? AND driver_id = ? AND status = 'Apply'");
$stmtLocal->execute([$rideId, $driverId]);
}
// ─────────────────────────────────────────────────────────────
// 2.1 ختم لحظة الوصول — أساس تعويض عدم حضور الراكب
//
// ‏فحص المسافة في التطبيق (100م) على العميل، فيمكن تجاوزه بموقع مزيَّف
// ‏ثم انتظار خمس دقائق وقبض تعويض بلا وجود حقيقي. لذلك يتحقق الخادم
// ‏هنا بنفسه من موقع السائق في Redis قبل أن يختم الوقت.
//
// ‏إن تعذّر التحقق (Redis غير متاح أو الموقع مفقود) لا نمنع الوصول —
// ‏الحالة تُحدَّث والراكب يُشعَر كالمعتاد — لكن لا نختم وقتاً يترتب عليه
// ‏مال لا نستطيع إثباته. النتيجة: لا تعويض لهذه الرحلة، وسجلّ واضح.
// ─────────────────────────────────────────────────────────────
try {
$stmtRide = $con->prepare("SELECT * FROM ride WHERE id = ? AND driver_id = ?");
$stmtRide->execute([$rideId, $driverId]);
$rideRow = $stmtRide->fetch(PDO::FETCH_ASSOC);
if (is_array($rideRow)
&& array_key_exists('driverArrivedAt', $rideRow)
&& empty($rideRow['driverArrivedAt'])) {
[$pLat, $pLng] = array_pad(
array_map('trim', explode(',', (string) $rideRow['start_location'], 2)), 2, null
);
$canStamp = false;
if (isset($redisLocation) && $redisLocation
&& is_numeric($pLat) && is_numeric($pLng)) {
$loc = $redisLocation->hGetAll("driver:public:$driverId");
if (!empty($loc['lat']) && !empty($loc['lng'])) {
$gap = getDistanceBetweenPoints(
(float) $loc['lat'], (float) $loc['lng'],
(float) $pLat, (float) $pLng
);
$canStamp = ($gap <= ARRIVAL_STAMP_RADIUS_KM);
if (!$canStamp) {
error_log("[arrive_ride] ختم الوصول مرفوض — السائق $driverId"
. " يبعد " . round($gap, 3) . "كم عن نقطة الالتقاط (ride=$rideId)");
}
}
}
if ($canStamp) {
// ‏WHERE driverArrivedAt IS NULL يجعله ذرّياً: نداء ثانٍ لا
// ‏يعيد ضبط عدّاد الانتظار.
$sqlStamp = "UPDATE ride SET driverArrivedAt = NOW()
WHERE id = ? AND driver_id = ? AND driverArrivedAt IS NULL";
$con->prepare($sqlStamp)->execute([$rideId, $driverId]);
try {
$con_ride->prepare($sqlStamp)->execute([$rideId, $driverId]);
} catch (PDOException $e) { /* primary هو المرجع لهذا الحقل */ }
} else {
error_log("[arrive_ride] تعذّر إثبات الوصول — لا تعويض لهذه"
. " الرحلة (ride=$rideId driver=$driverId)");
}
}
} catch (PDOException $eStamp) {
// ‏العمود غير مُرحَّل بعد — الوصول يعمل، التعويض معطّل.
error_log("[arrive_ride] تعذّر ختم driverArrivedAt (شغّل"
. " migrations/2026_08_07_driver_cancel_compensation.sql): " . $eStamp->getMessage());
}
// 3. جلب بيانات الراكب للإرسال
// نستخدم con_ride لضمان الدقة
$stmtPas = $con_ride->prepare("SELECT passenger_id FROM ride WHERE id = ?");
$stmtPas->execute([$rideId]);
$passenger_id = $stmtPas->fetchColumn();
if ($passenger_id) {
// أ) إرسال Socket (الأسرع)
$payload = [
'status' => 'arrived',
'ride_id' => $rideId,
'msg' => 'السائق وصل إلى موقعك 🚖'
];
if (function_exists('notifyPassengerOnRideServer')) {
notifyPassengerOnRideServer($passenger_id, $payload);
}
// ب) إرسال FCM (باستخدام الدالة الجديدة)
if (!empty($passengerToken)) {
$fcmData = [
'category' => 'Arrive Ride', // نفس الاسم القديم لضمان عمل التطبيق
'ride_id' => (string)$rideId,
'status' => 'arrived'
];
// 🔥 استخدام sendFCM_Internal كرسالة صامتة
sendFCM_Internal(
$passengerToken, // الهدف
"", // تفريغ العنوان
"", // تفريغ النص
$fcmData, // البيانات
"Arrive Ride", // التصنيف
false // ليس Topic
);
}
}
// 🆕 Cache ride state in Redis
sendToLocationServer('update_ride_state', [
'ride_id' => $rideId,
'status' => 'arrived',
'driver_id' => $driverId,
'passenger_id' => $passenger_id ?? '',
]);
jsonSuccess(null, "Arrival notified successfully");
} catch (Exception $e) {
error_log("[arrive_ride] " . $e->getMessage());
jsonError("Error notifying arrival");
}
?>