$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['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) { if (!empty($d['cached']) && !empty($d['first_name'])) { // ✅ Cache hit — بيانات السائق كاملة من Redis, نستخدمها مباشرة $d['serverNow'] = $serverNow; $final_result[] = $d; } else { // ❌ Cache miss — نحتاج نجيب البيانات من MySQL $mysqlIds[] = $d['id']; $driversMap[$d['id']] = $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) AND COALESCE(cr.year, 0) > 2000 "; $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']; foreach ($drivers_db as $row) { $did = $row['driver_id']; 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 { $row[$field] = $encryptionHelper->decryptData($row[$field]); } catch (Exception $e) { $row[$field] = null; } } } 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() ]), ]); } } // إرجاع النتيجة 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."); } ?>