prepare($sqlRide); $stmtRide->execute($params); $rideRow = $stmtRide->fetch(PDO::FETCH_ASSOC); } catch (Exception $eRideDb) { error_log("[getRideOrderID] ride DB unavailable: " . $eRideDb->getMessage()); } if (!$rideRow) { $stmtRide = $con->prepare($sqlRide); $stmtRide->execute($params); $rideRow = $stmtRide->fetch(PDO::FETCH_ASSOC); } if (!$rideRow) { printFailure("No ride found"); exit; } $driverId = $rideRow['driver_id'] ?? ''; if (empty($driverId)) { // رحلة لم يقبلها سائق بعد — ليست حالة خطأ echo json_encode([ "status" => "success", "message" => "No driver assigned yet", "data" => ["ride_id" => (string)$rideRow['id'], "status" => $rideRow['status']], ]); exit; } // ── 2. بيانات السائق — نفس استعلام acceptRide.php ────────────── $stmtDriver = $con->prepare(" SELECT d.id AS driver_id, d.first_name, d.last_name, d.gender, d.phone, c.make, c.model, c.car_plate, c.year, c.color, c.color_hex, (SELECT ROUND(AVG(rating), 2) FROM ratingDriver WHERE driver_id = d.id) AS ratingDriver, (SELECT COUNT(*) FROM ratingDriver WHERE driver_id = d.id) AS ratingCount, (SELECT COUNT(*) FROM ride WHERE driver_id = d.id AND status IN ('Finished', 'finished')) AS completedRides, dt.token FROM driver d LEFT JOIN CarRegistration c ON c.driverID = d.id LEFT JOIN driverToken dt ON dt.captain_id = d.id WHERE d.id = ? LIMIT 1 "); $stmtDriver->execute([$driverId]); $driverRaw = $stmtDriver->fetch(PDO::FETCH_ASSOC); if (!$driverRaw) { printFailure("Driver not found"); exit; } // جدول driverToken يخزّن التوكن مشفّراً — بلا فك تشفير يصل التطبيق // blob يستخدمه كـ FCM target فيرفضه FCM بـ 400 ولا تصل رسائل الراكب. $driverInfo = []; $encryptedFields = ['first_name', 'last_name', 'gender', 'phone', 'car_plate', 'token']; foreach ($driverRaw as $key => $value) { if (in_array($key, $encryptedFields, true) && !empty($value)) { $decrypted = false; try { $decrypted = $encryptionHelper->decryptData($value); } catch (\Throwable $e) { $decrypted = false; } $driverInfo[$key] = ($decrypted !== false && $decrypted !== null && $decrypted !== '') ? $decrypted : $value; } else { $driverInfo[$key] = $value; } } $driverInfo['driverName'] = trim(($driverInfo['first_name'] ?? '') . ' ' . ($driverInfo['last_name'] ?? '')); if (empty($driverInfo['driverName']) && !empty($driverInfo['phone'])) { $driverInfo['driverName'] = $driverInfo['phone']; } $driverInfo['ratingDriver'] = !empty($driverInfo['ratingDriver']) ? (string)$driverInfo['ratingDriver'] : "5.0"; $ratingValue = (float) $driverInfo['ratingDriver']; $ratingCount = (int) ($driverInfo['ratingCount'] ?? 0); $completedRides = (int) ($driverInfo['completedRides'] ?? 0); if ($ratingValue >= 4.8 && $ratingCount >= 50 && $completedRides >= 100) { $driverInfo['driverTier'] = 'Professional driver'; } elseif ($ratingValue >= 4.5 && $ratingCount >= 15 && $completedRides >= 30) { $driverInfo['driverTier'] = 'Trusted driver'; } else { $driverInfo['driverTier'] = 'Verified driver'; } // ── 3. آخر موقع للسائق من Redis (اختياري) ────────────────────── if (isset($redisLocation) && $redisLocation) { try { // ‏المفتاح driver:public هو ما يكتبه driver_socket.php فعلاً // ‏(driver:location لا وجود له — كان خطأً منسوخاً من acceptRide.php). $driverLoc = $redisLocation->hGetAll("driver:public:$driverId"); if (!empty($driverLoc)) { $driverInfo['lat'] = (float)($driverLoc['lat'] ?? 0); $driverInfo['lng'] = (float)($driverLoc['lng'] ?? 0); $driverInfo['heading'] = (float)($driverLoc['heading'] ?? 0); } } catch (Exception $eLoc) { // تجاهل — الموقع يصل بالسوكيت أصلاً } } // ⚠️ تصادم مفاتيح: getUpdatedRideForDriverApply يقرأ passengerName + last_name // كاسم **الراكب**. لو تركنا last_name للسائق يظهر لقب السائق كاسم الراكب. // ننقل لقب السائق إلى driver_last_name (وهو مفتاح يفهمه // _fillDriverDataLocally أصلاً) ونرجّع اسم الراكب الحقيقي في مكانه. $driverInfo['driver_last_name'] = $driverInfo['last_name'] ?? ''; unset($driverInfo['last_name']); try { $stmtPas = $con->prepare("SELECT first_name, last_name FROM passengers WHERE id = ? LIMIT 1"); $stmtPas->execute([$passengerId]); $pasRow = $stmtPas->fetch(PDO::FETCH_ASSOC); if ($pasRow) { foreach (['first_name' => 'passengerName', 'last_name' => 'last_name'] as $src => $dst) { $val = $pasRow[$src] ?? ''; if ($val === '' || $val === null) { $driverInfo[$dst] = ''; continue; } $dec = false; try { $dec = $encryptionHelper->decryptData($val); } catch (\Throwable $e) { $dec = false; } $driverInfo[$dst] = ($dec !== false && $dec !== null && $dec !== '') ? $dec : $val; } } } catch (PDOException $ePas) { error_log("[getRideOrderID] passenger name lookup WARNING: " . $ePas->getMessage()); } $driverInfo['ride_id'] = (string)$rideRow['id']; $driverInfo['status'] = $rideRow['status']; echo json_encode([ "status" => "success", "message" => "Driver info", "data" => $driverInfo, ]); } catch (PDOException $e) { error_log("[getRideOrderID] CRITICAL: " . $e->getMessage()); printFailure("Server error"); }