Update: 2026-07-25 18:28:30

This commit is contained in:
Hamza-Ayed
2026-07-25 18:28:31 +03:00
parent 5e103f60f2
commit 4bbc687c15
9 changed files with 133 additions and 61 deletions
@@ -53,14 +53,18 @@ if ($stmt->rowCount() > 0) {
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Decrypt sensitive fields
$fieldsToDecrypt = ['phone', 'email', 'first_name', 'last_name', 'name_arabic', 'national_number', 'address', 'gender', 'site', 'birthdate'];
foreach ($rows as &$row) {
if (!empty($row['phone'])) {
$row['phone'] = $encryptionHelper->decryptData($row['phone']);
}
if (!empty($row['name_arabic'])) {
$row['name_arabic'] = $encryptionHelper->decryptData($row['name_arabic']);
foreach ($fieldsToDecrypt as $f) {
if (!empty($row[$f])) {
$dec = $encryptionHelper->decryptData($row[$f]);
if ($dec !== false && $dec !== null) {
$row[$f] = $dec;
}
}
}
}
unset($row);
jsonSuccess($rows);
@@ -63,14 +63,12 @@ $sql = "SELECT
FROM
`passengers`
WHERE
passengers.id = '$passengerID'
GROUP BY
`passengers`.`id`
passengers.id = :pid
ORDER BY
countPassengerRide DESC";
$stmt = $con->prepare($sql);
$stmt->execute();
$stmt->execute([':pid' => $passengerID]);
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
// ✅ فك تشفير الحقول الحساسة
+7 -5
View File
@@ -1,18 +1,20 @@
<?php
require_once __DIR__ . '/../connect.php';
$passengerEmail = $encryptionHelper->encryptData(filterRequest("passengerEmail"));
$passengerId = filterRequest("passengerId");
$passengerphone = $encryptionHelper->encryptData(filterRequest("passengerphone"));
$rawEmail = filterRequest("passengerEmail");
$rawPhone = filterRequest("passengerphone");
$passengerEmail = !empty($rawEmail) ? $encryptionHelper->encryptData($rawEmail) : '___NON_EXISTENT___';
$passengerId = filterRequest("passengerId");
$passengerphone = !empty($rawPhone) ? $encryptionHelper->encryptData($rawPhone) : '___NON_EXISTENT___';
/**
* الفهرس الأعمى: يسمح بالبحث بعد نقل التخزين إلى AES-GCM العشوائي.
* تُبقى المقارنة القديمة في نفس الاستعلام كاحتياط حتى تنتهي تعبئة الفهارس.
*/
global $blindIndex;
$emailBidx = $blindIndex ? $blindIndex->index('passengers.email', filterRequest("passengerEmail")) : null;
$phoneBidx = $blindIndex ? $blindIndex->index('passengers.phone', filterRequest("passengerphone")) : null;
$emailBidx = (!empty($rawEmail) && $blindIndex) ? $blindIndex->index('passengers.phone', $rawEmail) : null;
$phoneBidx = (!empty($rawPhone) && $blindIndex) ? $blindIndex->index('passengers.phone', $rawPhone) : null;
$sql = "SELECT
`passengers`.`id`,
@@ -22,6 +22,10 @@ $raw = normalizePhone($phone);
// شَفِّر قبل الاستعلام
$enc_raw = $encryptionHelper->encryptData($raw);
global $blindIndex;
$pBidx = $blindIndex ? $blindIndex->index('passengers.phone', $raw) : null;
$dBidx = $blindIndex ? $blindIndex->index('driver.phone', $raw) : null;
try {
error_log("[get_last_ride] Searching phone normalized=$raw");
+39 -29
View File
@@ -60,16 +60,16 @@ if ($driver) {
}
//------------------------------------------------------------------------
// 2) جلب آخر رحلة حالتها نشطة (Apply, Applied, Arrived, Begin)
// 2) جلب آخر رحلة حالتها نشطة
//------------------------------------------------------------------------
$activeStatuses = "'Apply','Applied','Arrived','arrived','Begin'";
$activeStatuses = "'apply','applied','arrived','begin','accepted','started','claimed','new','nothing','waiting','wait','pending','searching'";
if ($userType == 'driver') {
error_log("[MONITOR_RIDE] 4. Searching for active ride for Driver ID: " . $driverID);
$rideQuery = $con->prepare("
SELECT * FROM ride
WHERE driver_id = :driverID AND status IN ($activeStatuses)
WHERE driver_id = :driverID AND LOWER(status) IN ($activeStatuses)
ORDER BY id DESC LIMIT 1
");
$rideQuery->execute([':driverID' => $driverID]);
@@ -77,7 +77,7 @@ if ($userType == 'driver') {
error_log("[MONITOR_RIDE] 4. Searching for active ride for Customer ID: " . $customerID);
$rideQuery = $con->prepare("
SELECT * FROM ride
WHERE passenger_id = :customerID AND status IN ($activeStatuses)
WHERE passenger_id = :customerID AND LOWER(status) IN ($activeStatuses)
ORDER BY id DESC LIMIT 1
");
$rideQuery->execute([':customerID' => $customerID]);
@@ -100,25 +100,28 @@ if (!$ride) {
$rideDriverID = $ride['driverID'] ?? $ride['driver_id'];
error_log("[MONITOR_RIDE] 5. Fetching info for Driver ID from Ride: " . $rideDriverID);
$driverInfoQuery = $con->prepare("
SELECT id, first_name, last_name, phone
FROM driver
WHERE id = :driverID
LIMIT 1
");
$driverInfo = null;
if ($rideDriverID) {
$driverInfoQuery = $con->prepare("
SELECT id, first_name, last_name, phone
FROM driver
WHERE id = :driverID
LIMIT 1
");
$driverInfoQuery->execute([':driverID' => $rideDriverID]);
$driverInfo = $driverInfoQuery->fetch(PDO::FETCH_ASSOC);
$driverInfoQuery->execute([':driverID' => $rideDriverID]);
$driverInfo = $driverInfoQuery->fetch(PDO::FETCH_ASSOC);
if ($driverInfo) {
$driverInfo['phone'] = $encryptionHelper->decryptData($driverInfo['phone']);
$driverInfo['first_name'] = $encryptionHelper->decryptData($driverInfo['first_name']);
$driverInfo['last_name'] = $encryptionHelper->decryptData($driverInfo['last_name']);
$fullName = $driverInfo['first_name'] . " " . $driverInfo['last_name'];
$driverInfo['fullname'] = $fullName;
error_log("[MONITOR_RIDE] 5. Driver Info Found: " . $fullName);
} else {
error_log("[MONITOR_RIDE] 5. WARNING: Driver info not found for ID " . $rideDriverID);
if ($driverInfo) {
$driverInfo['phone'] = $encryptionHelper->decryptData($driverInfo['phone']);
$driverInfo['first_name'] = $encryptionHelper->decryptData($driverInfo['first_name']);
$driverInfo['last_name'] = $encryptionHelper->decryptData($driverInfo['last_name']);
$fullName = trim(($driverInfo['first_name'] ?? '') . " " . ($driverInfo['last_name'] ?? ''));
$driverInfo['fullname'] = $fullName ?: "Unknown Driver";
error_log("[MONITOR_RIDE] 5. Driver Info Found: " . $fullName);
} else {
error_log("[MONITOR_RIDE] 5. WARNING: Driver info not found for ID " . $rideDriverID);
}
}
//------------------------------------------------------------------------
@@ -127,14 +130,21 @@ if ($driverInfo) {
error_log("[MONITOR_RIDE] 6. Querying Tracking DB for Driver ID: " . $rideDriverID);
$locationQuery = $con_tracking->prepare("
SELECT latitude, longitude, speed, heading, updated_at
FROM car_locations
WHERE driver_id = :driverID AND status = 'ON'
ORDER BY updated_at DESC LIMIT 1
");
$locationQuery->execute([':driverID' => $rideDriverID]);
$location = $locationQuery->fetch(PDO::FETCH_ASSOC);
$location = null;
if ($rideDriverID && isset($con_tracking) && $con_tracking) {
try {
$locationQuery = $con_tracking->prepare("
SELECT latitude, longitude, speed, heading, updated_at
FROM car_locations
WHERE driver_id = :driverID AND status = 'ON'
ORDER BY updated_at DESC LIMIT 1
");
$locationQuery->execute([':driverID' => $rideDriverID]);
$location = $locationQuery->fetch(PDO::FETCH_ASSOC) ?: null;
} catch (Throwable $e) {
error_log("[MONITOR_RIDE] Tracking query exception: " . $e->getMessage());
}
}
if ($location) {
error_log("[MONITOR_RIDE] 6. Location Found: Lat=" . $location['latitude'] . " Lng=" . $location['longitude']);
+1 -1
View File
@@ -18,7 +18,7 @@ try {
COUNT(r.id) as total_rides
FROM driver d
LEFT JOIN ride r ON d.id = r.driver_id AND LOWER(r.status) IN ('finished','completed')
GROUP BY d.id
GROUP BY d.id, d.first_name, d.last_name, d.phone
HAVING total_earned > 0
ORDER BY total_earned DESC
LIMIT 50
+3
View File
@@ -37,6 +37,9 @@ $role = $decoded->role ?? 'passenger';
// 3. Database Connection
try {
$con = Database::get('main');
try { $con_tracking = Database::get('tracking'); } catch (Throwable $e) { $con_tracking = $con; }
try { $con_ride = Database::get('ride'); } catch (Throwable $e) { $con_ride = $con; }
try { $con_transit = Database::get('transit'); } catch (Throwable $e) { $con_transit = $con; }
} catch (Exception $e) {
http_response_code(500);
exit(json_encode(['error' => 'Database connection failed']));
+16 -16
View File
@@ -360,13 +360,13 @@
<thead>
<tr>
<th data-i18n="ID">ID</th>
<th>Name</th>
<th>Phone</th>
<th>Email</th>
<th>Rating</th>
<th>Trips</th>
<th>Cancellations</th>
<th>Status</th>
<th data-i18n="Name">Name</th>
<th data-i18n="Phone">Phone</th>
<th data-i18n="Email">Email</th>
<th data-i18n="Rating">Rating</th>
<th data-i18n="Trips">Trips</th>
<th data-i18n="Cancellations">Cancellations</th>
<th data-i18n="Status">Status</th>
</tr>
</thead>
<tbody id="driversTableBody"></tbody>
@@ -398,13 +398,13 @@
<thead>
<tr>
<th data-i18n="ID">ID</th>
<th>Name</th>
<th>Contact</th>
<th>Trips</th>
<th>Rating</th>
<th>Cancellations</th>
<th>Joined</th>
<th>Status</th>
<th data-i18n="Name">Name</th>
<th data-i18n="Contact">Contact</th>
<th data-i18n="Trips">Trips</th>
<th data-i18n="Rating">Rating</th>
<th data-i18n="Cancellations">Cancellations</th>
<th data-i18n="Joined">Joined</th>
<th data-i18n="Status">Status</th>
</tr>
</thead>
<tbody id="passengersTableBody"></tbody>
@@ -458,8 +458,8 @@
<thead>
<tr>
<th data-i18n="ID">ID</th>
<th>Name</th>
<th>Phone</th>
<th data-i18n="Name">Name</th>
<th data-i18n="Phone">Phone</th>
<th data-i18n="Type">Type</th>
<th data-i18n="Requested role">Requested role</th>
<th data-i18n="Requested at">Requested at</th>
+52 -1
View File
@@ -458,6 +458,56 @@
'This browser is registered as a trusted device:': 'هذا المتصفح مسجّل كجهاز موثوق:',
'The endpoint responded successfully but returned no data yet.': 'استجاب الـ API بنجاح لكنه لم يُرجِع بياناتاً بعد.',
'No records recorded for this yet — the table is empty in the database.': 'لا توجد سجلات بعد — الجدول فارغ في قاعدة البيانات.',
// Database and API Field Translations
'Total Revenue': 'إجمالي الإيرادات',
'Company Profit': 'أرباح الشركة',
'Total Driver Pay': 'إجمالي مستحقات السائقين',
'Total Platform Commission': 'عمولة المنصة',
'Cash Payments': 'الدفع النقدي',
'Digital Payments': 'الدفع الرقمي',
'Total Earned': 'إجمالي الأرباح',
'First Name': 'الاسم الأول',
'Last Name': 'اسم العائلة',
'Full Name': 'الاسم الكامل',
'Driver Id': 'معرّف السائق',
'Passenger Id': 'معرّف الراكب',
'Created At': 'تاريخ الإنشاء',
'Updated At': 'تاريخ التحديث',
'Birthdate': 'تاريخ الميلاد',
'Gender': 'الجنس',
'National Number': 'الرقم الوطني',
'Address': 'العنوان',
'Site': 'الموقع',
'Active Routes': 'المسارات النشطة',
'Active Enrollments': 'التسجيلات النشطة',
'Average Pci': 'متوسط PCI',
'Market Share Percent': 'نسبة الحصة السوقية',
'Total Anomalies': 'حالات الشذوذ',
'Total Surge Opportunities': 'فرص الفورة',
'Report Date': 'تاريخ التقرير',
'Date': 'التاريخ',
'User Type': 'نوع المستخدم',
'User': 'المستخدم',
'Ride Details': 'تفاصيل الرحلة',
'Driver Details': 'تفاصيل السائق',
'Driver Location': 'موقع السائق',
'Price': 'السعر',
'Price For Driver': 'حصة السائق',
'Price For Passenger': 'المبلغ من الراكب',
'Distance': 'المسافة',
'Payment Method': 'طريقة الدفع',
'Car Type': 'نوع السيارة',
'Start Location': 'موقع البداية',
'End Location': 'موقع النهاية',
'Cancel Reason': 'سبب الإلغاء',
'Driver First Name': 'اسم السائق الأول',
'Driver Last Name': 'اسم عائلة السائق',
'Passenger First Name': 'اسم الراكب الأول',
'Passenger Last Name': 'اسم عائلة الراكب',
'Contact': 'معلومات الاتصال',
'Click any row to open the full profile': 'اضغط على أي سطر لفتح الملف الشخصي الكامل',
'Search by passenger ID, phone or email': 'البحث برقم الراكب، الهاتف، أو البريد الإلكتروني',
'Search rides by phone number': 'البحث في الرحلات برقم الهاتف',
'Yes': 'نعم',
'No': 'لا',
'Click any row to open the full profile': 'اضغط على أي سطر لفتح الملف الشخصي الكامل',
@@ -3339,11 +3389,12 @@
}
function humanize(key) {
return String(key)
const s = String(key)
.replace(/[_-]+/g, ' ')
.replace(/([a-z])([A-Z])/g, '$1 $2')
.replace(/\b\w/g, (m) => m.toUpperCase())
.trim();
return t(key) || t(s) || s;
}
function msgNode(text) {