$lat, 'lng' => $lng, 'radius' => 5, 'limit' => 50 ])); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 3); curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-internal-key: $INTERNAL_KEY"]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $redisDrivers = []; if ($httpCode == 200 && $response) { $json = json_decode($response, true); if (isset($json['status']) && $json['status'] === true) { $redisDrivers = $json['drivers'] ?? $json['data'] ?? []; } } if (empty($redisDrivers)) { jsonSuccess([]); exit; } // تقسيم: cache hits → نستخدمها فوراً، cache misses → نحتاج MySQL $final_result = []; $mysqlIds = []; $driversMap = []; $serverNow = date('Y-m-d H:i:s'); foreach ($redisDrivers as $d) { $driverId = $d['driver_id'] ?? $d['id'] ?? null; if (!$driverId) continue; if (!empty($d['cached']) && !empty($d['first_name'])) { // ✅ Cache hit — بيانات السائق كاملة من Redis, نستخدمها مباشرة $d['serverNow'] = $serverNow; $final_result[] = $d; } else { // ❌ Cache miss — نحتاج نجيب البيانات من MySQL $mysqlIds[] = $driverId; $driversMap[$driverId] = $d; } } // ========================================== // 3. فقط للسائقين اللي ما فيهم Cache: MySQL // ========================================== if (!empty($mysqlIds)) { $placeholders = implode(',', array_fill(0, count($mysqlIds), '?')); $sql_drivers_info = " SELECT d.id AS driver_id, d.phone, d.email, d.birthdate, d.first_name, d.last_name, d.gender, d.maritalStatus, cr.make, cr.car_plate, cr.model, cr.color, cr.vin, cr.color_hex, cr.year, cr.vehicle_category_id, dt.token, COALESCE(rdAvg.ratingDriver, 0) AS ratingDriver FROM driver d LEFT JOIN CarRegistration cr ON cr.driverID = d.id LEFT JOIN driverToken dt ON dt.captain_id = d.id LEFT JOIN ( SELECT driver_id, AVG(rating) AS ratingDriver FROM ratingDriver GROUP BY driver_id ) rdAvg ON rdAvg.driver_id = d.id WHERE d.id IN ($placeholders) "; $stmt = $con->prepare($sql_drivers_info); $stmt->execute($mysqlIds); $drivers_db = $stmt->fetchAll(PDO::FETCH_ASSOC); $fieldsToDecrypt = ['phone','email','gender','birthdate','first_name','last_name','token','car_plate','vin']; $foundIds = []; foreach ($drivers_db as $row) { $did = $row['driver_id']; $foundIds[] = $did; if (isset($driversMap[$did])) { $redisInfo = $driversMap[$did]; $row['latitude'] = $redisInfo['latitude'] ?? $redisInfo['lat'] ?? ''; $row['longitude'] = $redisInfo['longitude'] ?? $redisInfo['lng'] ?? ''; $row['heading'] = $redisInfo['heading'] ?? '0'; $row['speed'] = $redisInfo['speed'] ?? '0'; } else { continue; } $row['serverNow'] = $serverNow; foreach ($fieldsToDecrypt as $field) { if (isset($row[$field]) && $row[$field] !== null && $row[$field] !== '') { try { $decrypted = $encryptionHelper->decryptData($row[$field]); if ($decrypted !== false && $decrypted !== null) { $row[$field] = $decrypted; } } catch (Throwable $e) { // Keep original value if decryption fails } } } if (!empty($row['birthdate'])) { try { $birthdate = new DateTime($row['birthdate']); $today = new DateTime(); $row['age'] = $today->diff($birthdate)->y; } catch (Exception $e) { $row['age'] = null; } } else { $row['age'] = null; } $final_result[] = $row; // 🆕 Fill driver:public cache for next time (async, fire-and-forget) sendToLocationServer('cache_driver_public', [ 'driver_id' => $did, 'data' => json_encode([ 'first_name' => $row['first_name'] ?? '', 'last_name' => $row['last_name'] ?? '', 'gender' => $row['gender'] ?? '', 'make' => $row['make'] ?? '', 'model' => $row['model'] ?? '', 'color' => $row['color'] ?? '', 'color_hex' => $row['color_hex'] ?? '', 'year' => $row['year'] ?? '', 'car_plate' => $row['car_plate'] ?? '', 'ratingDriver'=> $row['ratingDriver'] ?? '0', 'latitude' => $row['latitude'] ?? '', 'longitude' => $row['longitude'] ?? '', 'heading' => $row['heading'] ?? '0', 'speed' => $row['speed'] ?? '0', 'updated_at' => time() ]), ]); } // 🚀 Fallback: إذا كان السائق نشط في Redis لكن بيانت السيارة في MySQL مفقودة/قديمة، أظهر موقعه للراكب $missingIds = array_diff($mysqlIds, $foundIds); foreach ($missingIds as $mid) { if (isset($driversMap[$mid])) { $d = $driversMap[$mid]; $final_result[] = [ 'driver_id' => $mid, 'id' => $mid, 'first_name'=> 'Driver', 'last_name' => '', 'latitude' => $d['latitude'] ?? $d['lat'] ?? '', 'longitude' => $d['longitude'] ?? $d['lng'] ?? '', 'heading' => $d['heading'] ?? '0', 'speed' => $d['speed'] ?? '0', 'make' => '', 'model' => '', 'serverNow' => $serverNow, ]; } } } // إرجاع النتيجة jsonSuccess($final_result); } catch (PDOException $e) { error_log("[get.php] " . $e->getMessage()); jsonError("An internal error occurred. Please try again later."); } catch (Throwable $e) { error_log("[get.php] " . $e->getMessage()); jsonError("An internal error occurred. Please try again later."); } ?>