Update: 2026-08-07 01:06:09

This commit is contained in:
Hamza-Ayed
2026-08-07 01:06:09 +03:00
parent a1104a4695
commit 0cb1ab0ea3
5 changed files with 190 additions and 81 deletions
+47 -42
View File
@@ -52,21 +52,21 @@ try {
// ‏بمسح بيانات التطبيق أو إعادة تثبيته. هذه هي البوابة الحقيقية: سائق
// ‏موقوف لا يستطيع أن يفوز برحلة مهما فعل بتطبيقه.
// ═══════════════════════════════════════════════════════════
// ‏الفحص من Redis لا MySQL: هذا المسار يُستدعى على كل محاولة قبول من كل
// ‏سائق، والإيقاف حالة نادرة قصيرة العمر. مفتاح بـ TTL يجعل انتهاء
// ‏الإيقاف تلقائياً بلا كرون ولا استعلام تنظيف.
// ‏MySQL يبقى السجل الدائم للمراجعة الإدارية، ولا يُقرأ هنا.
try {
$stmtBlock = $con->prepare("SELECT blockedUntil FROM driver WHERE id = ?");
$stmtBlock->execute([$driverId]);
$blockedUntil = $stmtBlock->fetchColumn();
if (!empty($blockedUntil) && strtotime($blockedUntil) > time()) {
error_log("[accept_ride] DriverID=$driverId موقوف حتى $blockedUntil — رُفض القبول");
printFailure("Your account is temporarily suspended until $blockedUntil");
exit;
if (isset($redisLocation) && $redisLocation) {
$blockedUntil = $redisLocation->get("driver:$driverId:blocked");
if ($blockedUntil) {
error_log("[accept_ride] DriverID=$driverId موقوف حتى $blockedUntil — رُفض القبول");
printFailure("Your account is temporarily suspended until $blockedUntil");
exit;
}
}
} catch (PDOException $eBlock) {
// ‏العمود غير موجود بعد (قبل تشغيل ترحيل 2026_08_07) — لا نمنع القبول
// ‏بسبب فحصٍ لا يمكن إجراؤه، لكن نسجّله بوضوح.
error_log("[accept_ride] تعذّر فحص blockedUntil (شغّل"
. " migrations/2026_08_07_driver_cancel_compensation.sql): " . $eBlock->getMessage());
} catch (Throwable $eBlock) {
error_log("[accept_ride] تعذّر فحص الإيقاف: " . $eBlock->getMessage());
}
// ═══════════════════════════════════════════════════════════
@@ -111,44 +111,49 @@ try {
}
// ═══════════════════════════════════════════════════════════
// STEP B1 — تثبيت مسافة الاقتراب لحظة القبول
// ‏هذه هي المسافة التي سيقطعها السائق نحو الراكب، وهي أساس تعويض عدم
// ‏الحضور لاحقاً. تُقاس الآن حصراً: عند الإلغاء يكون السائق واقفاً عند
// ‏نقطة الالتقاط فتصير المسافة صفراً، فلا يمكن استنتاجها بأثر رجعي.
// ‏مصدر الموقع هو Redis لا الطلب — حتى لا يتحكم العميل بالمبلغ.
// STEP B1 — تثبيت مسافة الاقتراب لحظة القبول (في Redis لا MySQL)
//
// ‏هذه المسافة أساس تعويض عدم الحضور لاحقاً، ويجب أن تُقاس الآن حصراً:
// ‏عند الإلغاء يكون السائق واقفاً عند نقطة الالتقاط فتصير صفراً.
//
// ‏لكنها قيمة عابرة تُقرأ مرة واحدة عند نهاية الرحلة — فلا تستحق كتابتين
// ‏في MySQL على أسخن مسار في النظام. تُحفظ في نفس الهاش الذي يستخدمه
// ‏السوكِت لحالة الرحلة (ride:$id:state)، وتُثبَّت في MySQL كتابةً واحدة
// ‏مع تحديث الحالة النهائي عند الإلغاء.
//
// ‏hSet لا يمسح حقول السوكِت الأخرى في نفس الهاش، وTTL الـ24 ساعة الذي
// ‏يضبطه السوكِت يغطي هذه الحقول تلقائياً.
// ═══════════════════════════════════════════════════════════
try {
$stmtPickup = $con->prepare("SELECT start_location FROM ride WHERE id = ?");
$stmtPickup->execute([$rideId]);
$pickupRaw = (string) $stmtPickup->fetchColumn();
[$pickupLat, $pickupLng] = array_pad(
array_map('trim', explode(',', $pickupRaw, 2)), 2, null
);
$approachKm = 0.0;
if (isset($redisLocation) && $redisLocation
&& is_numeric($pickupLat) && is_numeric($pickupLng)) {
$loc = $redisLocation->hGetAll("driver:public:$driverId");
if (!empty($loc['lat']) && !empty($loc['lng'])) {
$approachKm = round(getDistanceBetweenPoints(
(float) $loc['lat'], (float) $loc['lng'],
(float) $pickupLat, (float) $pickupLng
), 3);
if (isset($redisLocation) && $redisLocation) {
$stmtPickup = $con->prepare("SELECT start_location FROM ride WHERE id = ?");
$stmtPickup->execute([$rideId]);
[$pickupLat, $pickupLng] = array_pad(
array_map('trim', explode(',', (string) $stmtPickup->fetchColumn(), 2)), 2, null
);
if (is_numeric($pickupLat) && is_numeric($pickupLng)) {
$loc = $redisLocation->hGetAll("driver:public:$driverId");
if (!empty($loc['lat']) && !empty($loc['lng'])) {
$approachKm = round(getDistanceBetweenPoints(
(float) $loc['lat'], (float) $loc['lng'],
(float) $pickupLat, (float) $pickupLng
), 3);
}
}
if ($approachKm > 0) {
$redisLocation->hSet("ride:$rideId:state", 'pickup_approach_km', $approachKm);
}
}
if ($approachKm > 0) {
$sqlApproach = "UPDATE ride SET pickupApproachKm = ? WHERE id = ?";
$con->prepare($sqlApproach)->execute([$approachKm, $rideId]);
try {
$con_ride->prepare($sqlApproach)->execute([$approachKm, $rideId]);
} catch (PDOException $e) { /* primary يكفي لحساب التعويض */ }
} else {
if ($approachKm <= 0) {
error_log("[accept_ride] تعذّر قياس مسافة الاقتراب RideID=$rideId"
. " — التعويض سيحتسب زمن الانتظار وحده");
}
} catch (PDOException $eApproach) {
} catch (Throwable $eApproach) {
// ‏قياس التعويض لا يُسقط قبول الرحلة أبداً.
error_log("[accept_ride] pickupApproachKm WARNING: " . $eApproach->getMessage());
}