Files
tripz-llc/backend/ride/notificationCaptain/getRideWaiting.php
T
Hamza-AyedandClaude Opus 5 4d8414c96b feat: استيراد كود سيرو إلى تريبز (سيرو @ecfe7568) — بلا تعديل
قرار المالك 2026-07-27: باك إند سيرو PHP هو المعتمد، وتطبيقاته المجرّبة
ميدانياً تحل محل إعادة البناء المؤرشفة. سيرو نفسه لم يُمسّ.

الخريطة:
  backend · payment_server · loction_server · ride_server ·
  passenger_server · docker · dashboard · stress_test  → الجذر
  siro_rider  → apps/rider          siro_driver  → apps/driver
  siro_admin  → dashboards/admin    siro_service → dashboards/service
  android_bot → apps/android_bot    socialBot    → apps/socialBot

نُسخ المتعقَّب في git سيرو فقط عبر `git archive` (3,198 ملفاً / ~169 م.ب)
لا `cp -r` — فاستُثنيت مخلفات البناء تلقائياً. بلا أي تعديل محتوى عمداً:
كل ما يلي يصير فرقاً مقروءاً مقابل المصدر.

لم يُستورد وسببه: siromove.com (الموقع التسويقي يبقى marketing/ في تريبز،
سيرو فيه 8 ملفات) · docs و planning (تريبز له docs/ الخاص) · deploy.sh
(ليس نشراً على سيرفر بل `git add . && git push origin --all` — فخّ في
مستودع آخر) · transit_dashboard (بانتظار قرار مصير backend-transit و
dashboards/transit-web).

⚠️ لا يبني بعد — ثلاثة نواقص متوقعة ومقصودة:
1. `.env` و `lib/env/env.g.dart` غير متعقَّبين في سيرو (أسرار لكل مستأجر):
   كل تطبيق فلاتر يحتاج .env خاصاً ثم توليد env.g.dart بـ build_runner.
2. إعدادات Firebase (9 ملفات google-services.json و GoogleService-Info.plist)
   يستبعدها .gitignore تريبز — ولكل مستأجر مشروع Firebase خاص أصلاً.
3. apps/driver في سيرو يشير إلى `../../Intaleq/packages/get` خارج المستودع →
   يجب ضمّ الحزم داخله أسوة بـ apps/rider.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 05:14:13 +03:00

177 lines
6.9 KiB
PHP

<?php
// getRideWaiting.php
require_once __DIR__ . '/../../connect.php';
$lat = filterRequest("lat");
$lng = filterRequest("lng");
$radius = filterRequest("radius");
if (empty($lat) || empty($lng)) {
jsonSuccess([]);
exit;
}
if (empty($radius)) {
$radius = 50;
}
$finalRides = [];
$rideIds = [];
$redisResultsMap = [];
// 1. محاولة البحث عبر Redis
try {
$locationServerUrl = getenv('LOCATION_SOCKET_URL') ?: 'http://socket_driver:2021';
if (strpos($locationServerUrl, 'localhost') !== false || strpos($locationServerUrl, '127.0.0.1') !== false) {
if (file_exists('/.dockerenv')) {
$locationServerUrl = str_replace(['localhost', '127.0.0.1'], 'socket_driver', $locationServerUrl);
}
}
$INTERNAL_KEY = function_exists('getInternalSocketKey') ? getInternalSocketKey() : '';
$postData = [
'action' => 'get_nearby_ride_ids',
'lat' => $lat,
'lng' => $lng,
'radius' => $radius
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $locationServerUrl);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 500);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-internal-key: $INTERNAL_KEY"]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode == 200 && $response) {
$jsonResults = json_decode($response, true);
if (is_array($jsonResults) && !empty($jsonResults)) {
foreach ($jsonResults as $res) {
$rideIds[] = $res[0];
$redisResultsMap[$res[0]] = $res[1];
}
}
}
} catch (Exception $e) {
// نتابع للخطة ب
}
// 2. جلب البيانات (إما عبر IDs أو بحث مباشر)
try {
if (!empty($rideIds)) {
// --- الحالة أ: الريدز وجد رحلات ---
$placeholders = implode(',', array_fill(0, count($rideIds), '?'));
$sql = "
SELECT
wr.id, wr.start_location AS startName, wr.end_location AS endName,
wr.date, wr.time, wr.price, wr.passenger_id, wr.status, wr.carType,
wr.passengerRate, wr.created_at, wr.price_for_passenger,
wr.distance, wr.duration, wr.start_lat, wr.start_lng,
wr.end_lat, wr.end_lng, wr.payment_method, wr.passenger_wallet,
p.email, p.first_name, p.phone, p.id AS passengerId, t.token AS passengerToken
FROM waitingRides wr
INNER JOIN passengers p ON p.id = wr.passenger_id
LEFT JOIN tokens t ON t.passengerID = wr.passenger_id
WHERE wr.id IN ($placeholders) AND wr.status IN ('wait', 'waiting')
";
$stmt = $con->prepare($sql);
$stmt->execute($rideIds);
$waitingRides = $stmt->fetchAll(PDO::FETCH_ASSOC);
} else {
// --- الحالة ب: بحث مباشر MySQL (Fallback) ---
// 🔥 التصحيح هنا: استخدام أسماء فريدة (:lat1, :lat2) لتجنب خطأ التكرار
$haversine = "( 6371 * acos( cos( radians(:lat1) ) * cos( radians( wr.start_lat ) ) * cos( radians( wr.start_lng ) - radians(:lng) ) + sin( radians(:lat2) ) * sin( radians( wr.start_lat ) ) ) )";
$sql = "
SELECT
wr.id, wr.start_location AS startName, wr.end_location AS endName,
wr.date, wr.time, wr.price, wr.passenger_id, wr.status, wr.carType,
wr.passengerRate, wr.created_at, wr.price_for_passenger,
wr.distance, wr.duration, wr.start_lat, wr.start_lng,
wr.end_lat, wr.end_lng, wr.payment_method, wr.passenger_wallet,
p.email, p.first_name, p.phone, p.id AS passengerId, t.token AS passengerToken,
{$haversine} AS driver_distance_km
FROM waitingRides wr
INNER JOIN passengers p ON p.id = wr.passenger_id
LEFT JOIN tokens t ON t.passengerID = wr.passenger_id
WHERE
wr.status IN ('wait', 'waiting')
AND wr.created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
AND wr.start_lat IS NOT NULL
HAVING driver_distance_km <= :radius
ORDER BY driver_distance_km ASC
LIMIT 50
";
$stmt = $con->prepare($sql);
// نمرر القيمة مرتين للمفتاحين المختلفين
$stmt->execute([
':lat1' => $lat,
':lng' => $lng,
':lat2' => $lat, // تكرار القيمة للمتغير الثاني
':radius' => $radius
]);
$waitingRides = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// 3. التنسيق
foreach ($waitingRides as $ride) {
$ride['phone'] = $encryptionHelper->decryptData($ride['phone'] ?? '');
$ride['first_name'] = $encryptionHelper->decryptData($ride['first_name'] ?? '');
$ride['email'] = $encryptionHelper->decryptData($ride['email'] ?? '');
// جدول tokens يخزّن التوكن مشفّراً (ride/firebase/addToken.php). كان
// يُرجَع هنا كما هو، فيصل تطبيق السائق blob مشفّر يستخدمه كـ FCM target
// في كل رسالة للراكب ⇒ رفض 400 من FCM ولا يصل الراكب شيء.
if (!empty($ride['passengerToken'])) {
$decodedPassengerToken = false;
try {
$decodedPassengerToken = $encryptionHelper->decryptData($ride['passengerToken']);
} catch (\Throwable $eTok) {
$decodedPassengerToken = false;
}
if ($decodedPassengerToken !== false && $decodedPassengerToken !== null && $decodedPassengerToken !== '') {
$ride['passengerToken'] = trim($decodedPassengerToken);
}
}
$ride['start_location'] = $ride['start_lat'] . ',' . $ride['start_lng'];
$ride['end_location'] = (!empty($ride['end_lat']))
? $ride['end_lat'] . ',' . $ride['end_lng']
: $ride['endName'];
$ride['id'] = (string)$ride['id'];
if (isset($ride['driver_distance_km'])) {
$ride['driver_distance_km'] = number_format((float)$ride['driver_distance_km'], 1);
} elseif (isset($redisResultsMap[$ride['id']])) {
$ride['driver_distance_km'] = number_format((float)$redisResultsMap[$ride['id']], 1);
} else {
$ride['driver_distance_km'] = "0.0";
}
$finalRides[] = $ride;
}
usort($finalRides, function($a, $b) {
return $a['driver_distance_km'] <=> $b['driver_distance_km'];
});
jsonSuccess($finalRides);
} catch (PDOException $e) {
error_log("DB Error getRideWaiting: " . $e->getMessage());
jsonError("Database error");
}
?>