Update: 2026-06-29 23:09:43

This commit is contained in:
Hamza-Ayed
2026-06-29 23:09:43 +03:00
parent 65b2e68154
commit 3506b07bc7
42 changed files with 8252 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
<?php
include "../../connect.php";
header('Content-Type: application/json; charset=utf-8');
//https://location.intaleq.xyz/intaleq/ride/location/add.php
try {
$driver_id = filterRequest("driver_id");
$latitude = filterRequest("latitude");
$longitude = filterRequest("longitude");
$status = filterRequest("status");
$heading = filterRequest("heading");
$speed = filterRequest("speed");
// ملاحظة: قمنا بتجاهل device_timestamp هنا لضمان دقة الترتيب الزمني في السيرفر
// إذا كنت تحتاج وقت الهاتف لأغراض الترتيب في حالة انقطاع النت، يفضل إضافته في عمود منفصل مستقبلاً
// distance قد تأتي باسم totalDistance من التطبيق
$distanceRaw = filterRequest("distance");
if ($distanceRaw === null || $distanceRaw === '') {
$distanceRaw = filterRequest("totalDistance");
}
// تطبيع القيم الرقمية (كما هي في كودك الأصلي)
$norm = function($v, $default = 0.0) {
if ($v === null) return $default;
$v = str_replace(',', '.', trim((string)$v));
return is_numeric($v) ? (float)$v : $default;
};
$lat = $norm($latitude, 0.0);
$lng = $norm($longitude, 0.0);
$head = $norm($heading, 0.0);
$spd = $norm($speed, 0.0);
$dist = round($norm($distanceRaw, 0.0), 2);
if ($dist > 99999999.99) { $dist = 99999999.99; }
if ($dist < -99999999.99){ $dist = -99999999.99; }
if (empty($driver_id) || ($lat == 0.0 && $lng == 0.0)) {
printFailure("Invalid payload");
exit;
}
// ---------------------------------------------------------
// التعديل الجوهري هنا:
// ---------------------------------------------------------
// تم حذف منطق حساب الوقت بواسطة PHP أو الهاتف.
// سنستخدم NOW() داخل جملة SQL مباشرة لضمان توقيت UTC موحد.
$sql = "INSERT INTO `car_tracks`
(`driver_id`,`latitude`,`longitude`,`heading`,`speed`,`distance`,`status`,`created_at`)
VALUES
(:driver_id, :latitude, :longitude, :heading, :speed, :distance, :status, NOW())";
// 👆 استخدمنا NOW() بدلاً من المتغير
$stmt = $con->prepare($sql);
$ok = $stmt->execute([
':driver_id' => $driver_id,
':latitude' => $lat,
':longitude' => $lng,
':heading' => $head,
':speed' => $spd,
':distance' => $dist,
':status' => (string)($status ?? 'on'),
// ':created_at' => $created_at_to_use, // 👈 تم حذف هذا السطر لأنه لم يعد مطلوباً
]);
if ($ok) {
printSuccess("car_tracks saved successfully");
} else {
printFailure("Failed to save car track");
}
} catch (PDOException $e) {
// يفضل عدم طباعة تفاصيل الخطأ للمستخدم النهائي في الإنتاج، لكن لا بأس للـ Debug
error_log("car_tracks insert error: " . $e->getMessage());
printFailure("Database error");
} catch (Throwable $e) {
error_log("car_tracks insert fatal: " . $e->getMessage());
printFailure("Server error");
}
?>

View File

@@ -0,0 +1,129 @@
<?php
// add_batch.php
include "../../connect.php";
header('Content-Type: application/json; charset=utf-8');
try {
// 1. استقبال البيانات
$driver_id = filterRequest("driver_id");
$json_batch = $_POST['batch_data'];
if (empty($driver_id) || empty($json_batch)) {
printFailure("No data received");
exit;
}
$points = json_decode($json_batch, true);
if (!is_array($points) || count($points) === 0) {
printFailure("Invalid JSON");
exit;
}
// ---------------------------------------------------------
// الجزء الأول: حساب مدة العمل الإضافية (PHP Calculation)
// ---------------------------------------------------------
// أ. ترتيب النقاط زمنياً للتأكد (احتياطاً)
usort($points, function($a, $b) {
return strtotime($a['ts']) - strtotime($b['ts']);
});
$batch_added_seconds = 0;
$first_point_time = strtotime($points[0]['ts']);
// ب. جلب آخر وقت مسجل لهذا السائق من قاعدة البيانات
// (لحساب الزمن الضائع بين الباتش السابق وأول نقطة في هذا الباتش)
$stmtLast = $con->prepare("SELECT created_at FROM car_tracks WHERE driver_id = ? ORDER BY created_at DESC LIMIT 1");
$stmtLast->execute([$driver_id]);
$lastRow = $stmtLast->fetch(PDO::FETCH_ASSOC);
if ($lastRow) {
$last_db_time = strtotime($lastRow['created_at']);
$diff_from_db = $first_point_time - $last_db_time;
// إذا كان الفرق منطقياً (أقل من 5 دقائق) وموجباً، نحسبه
if ($diff_from_db > 0 && $diff_from_db < 300) {
$batch_added_seconds += $diff_from_db;
}
}
// ج. حساب الفروقات داخل الباتش نفسه
$prev_time = $first_point_time;
// نحدد تاريخ هذا الباتش (لنعرف أي يوم نحدث في الجدول اليومي)
$batch_date = date('Y-m-d', $first_point_time);
foreach ($points as $key => $point) {
if ($key === 0) continue; // تخطي النقطة الأولى لأننا قارناها مع الداتابيز
$current_time = strtotime($point['ts']);
$diff = $current_time - $prev_time;
// تجاهل القفزات الكبيرة (أكثر من 5 دقائق)
if ($diff > 0 && $diff < 300) {
$batch_added_seconds += $diff;
}
$prev_time = $current_time;
}
// ---------------------------------------------------------
// الجزء الثاني: إدخال التراكات (Bulk Insert) - كودك الأصلي
// ---------------------------------------------------------
$values = [];
$placeholders = [];
foreach ($points as $point) {
$lat = $point['lat'] ?? 0;
$lng = $point['lng'] ?? 0;
$spd = $point['spd'] ?? 0;
$head = $point['head'] ?? 0;
$dist = $point['dst'] ?? 0;
$stat = $point['st'] ?? 'off';
$time = $point['ts'] ?? date('Y-m-d H:i:s');
$placeholders[] = "(?, ?, ?, ?, ?, ?, ?, ?)";
array_push($values, $driver_id, $lat, $lng, $head, $spd, $dist, $stat, $time);
}
$sql = "INSERT INTO `car_tracks`
(`driver_id`, `latitude`, `longitude`, `heading`, `speed`, `distance`, `status`, `created_at`)
VALUES " . implode(', ', $placeholders);
$stmt = $con->prepare($sql);
$ok = $stmt->execute($values);
// ---------------------------------------------------------
// الجزء الثالث: تحديث جدول الملخص اليومي (The Smart Update)
// ---------------------------------------------------------
if ($ok && $batch_added_seconds > 0) {
// نستخدم ON DUPLICATE KEY UPDATE:
// إذا كان السائق موجوداً لهذا اليوم، أضف الثواني للرصيد الموجود
// إذا لم يكن موجوداً، أنشئ سجلاً جديداً
$sqlSummary = "INSERT INTO `driver_daily_summary` (`driver_id`, `date`, `total_seconds`)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE `total_seconds` = `total_seconds` + VALUES(`total_seconds`)";
$stmtSum = $con->prepare($sqlSummary);
$stmtSum->execute([$driver_id, $batch_date, $batch_added_seconds]);
}
if ($ok) {
echo json_encode(array(
"status" => "success",
"count" => count($points),
"added_seconds" => $batch_added_seconds // للتتبع فقط
));
} else {
printFailure("Failed to insert batch");
}
} catch (PDOException $e) {
error_log("Batch insert error: " . $e->getMessage());
printFailure("Database error");
} catch (Throwable $e) {
printFailure("Server error");
}
?>

View File

@@ -0,0 +1,34 @@
<?php
include "../../connect.php";
$passengerId = filterRequest("passengerId");
$lat = filterRequest("lat");
$lng = filterRequest("lng");
$rideId = filterRequest("rideId");
// Validate the latitude and longitude
if ($lat === '' || $lng === '') {
printFailure("Latitude and longitude cannot be empty");
exit;
}
// Prepare an SQL statement with placeholders
$sql = "INSERT INTO `passengerlocation`( `passengerId`, `lat`, `lng`, `rideId`) VALUES (:passengerId, :lat, :lng, :rideId)";
$stmt = $con->prepare($sql);
// Bind the parameters to the SQL query
$stmt->bindParam(':passengerId', $passengerId);
$stmt->bindParam(':lat', $lat);
$stmt->bindParam(':lng', $lng);
$stmt->bindParam(':rideId', $rideId);
// Execute the statement
if ($stmt->execute()) {
// Print a success message
printSuccess("Passenger location saved successfully");
} else {
// Print a failure message
printFailure("Failed to save passenger location");
}
?>

View File

@@ -0,0 +1,20 @@
<?
include "../../connect.php";
$driver_id = filterRequest("driver_id");
$sql = "DELETE FROM `car_locations` WHERE `driver_id` = $driver_id";
$stmt = $con->prepare($sql);
$stmt->execute();
if ($stmt->rowCount() > 0) {
// Print a success message
printSuccess($message = "Car location deleted successfully");
} else {
// Print a failure message
printFailure($message = "Failed to delete car location");
}
?>

View File

@@ -0,0 +1,146 @@
<?php
include "../../connect.php";
// Set timezone for PHP logs only (Keep DB on UTC)
date_default_timezone_set('Asia/Amman');
try {
// 1) Read and validate coordinates
$southwestLat = filterRequest("southwestLat");
$southwestLon = filterRequest("southwestLon");
$northeastLat = filterRequest("northeastLat");
$northeastLon = filterRequest("northeastLon");
if ($southwestLat === false || $southwestLon === false ||
$northeastLat === false || $northeastLon === false) {
printFailure("Invalid coordinates provided");
exit;
}
// Fixed time window in seconds
$freshSeconds = 180; // 3 minutes
// =================================================================
// OPTIMIZATION: Create a Bounding Box Polygon in WKT format
// We create a geometric shape (a rectangle) that represents the map area.
// The SQL query will now find all points *inside* this shape.
// The format is POLYGON((lon lat, lon lat, ...))
// =================================================================
$boundingBoxWKT = sprintf(
'POLYGON((%f %f, %f %f, %f %f, %f %f, %f %f))',
$southwestLon, $southwestLat,
$northeastLon, $southwestLat,
$northeastLon, $northeastLat,
$southwestLon, $northeastLat,
$southwestLon, $southwestLat
);
// =================================================================
// OPTIMIZATION: Modified SQL Query
// - We replaced the two `BETWEEN` clauses with a single, highly efficient
// `ST_CONTAINS` function.
// - `ST_GeomFromText` converts our text polygon into a geometry object.
// - `ST_CONTAINS` uses the SPATIAL INDEX to rapidly find all `location_point`s
// that are within our bounding box.
// =================================================================
$sql = "
SELECT
NOW() AS serverNow,
cl.driver_id,
cl.latitude,
cl.longitude,
cl.heading,
cl.speed,
cl.status,
cl.created_at,
cl.updated_at,
d.phone,
d.email,
d.birthdate,
d.first_name,
d.last_name,
d.gender,
d.maritalStatus,
cr.make AS make,
cr.car_plate AS car_plate,
cr.model AS model,
cr.color AS color,
cr.vin AS vin,
cr.color_hex AS color_hex,
cr.year AS year,
dt.token AS token,
COALESCE(rdAvg.ratingDriver, 0) AS ratingDriver
FROM car_locations cl
JOIN driver d ON d.id = cl.driver_id
LEFT JOIN CarRegistration cr ON cr.driverID = cl.driver_id
LEFT JOIN driverToken dt ON dt.captain_id = cl.driver_id
LEFT JOIN (
SELECT driver_id, AVG(rating) AS ratingDriver
FROM ratingDriver
GROUP BY driver_id
) rdAvg ON rdAvg.driver_id = cl.driver_id
WHERE
-- This is the optimized spatial condition
ST_CONTAINS(ST_GeomFromText(:boundingBox, 4326), cl.location_point)
AND cl.status = 'off'
AND cl.updated_at >= NOW() - INTERVAL :freshSeconds SECOND
AND COALESCE(cr.year, 0) > 2000
AND (cr.make NOT LIKE '%دراج%' AND cr.model NOT LIKE '%دراج%')
ORDER BY cl.updated_at DESC, ratingDriver DESC
LIMIT 5
";
$stmt = $con->prepare($sql);
// Bind the new bounding box parameter
$stmt->bindValue(':boundingBox', $boundingBoxWKT);
$stmt->bindValue(':freshSeconds', $freshSeconds, PDO::PARAM_INT);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (!$rows) {
printFailure("No car locations found");
exit;
}
// Decryption and age calculation logic remains the same
$fieldsToDecrypt = [
'phone','email','gender','birthdate',
'first_name','last_name','maritalStatus',
'token','make','car_plate','vin'
];
foreach ($rows as &$row) {
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;
}
if (isset($row['serverNow'], $row['updated_at'])) {
error_log('PHP Now: '.date('Y-m-d H:i:s')
.' | MySQL Now: '.$row['serverNow']
.' | updated_at: '.$row['updated_at']);
}
}
unset($row);
printSuccess($rows);
} catch (PDOException $e) {
printFailure("Database error: " . $e->getMessage());
} catch (Throwable $e) {
printFailure("Internal error: " . $e->getMessage());
}

View File

@@ -0,0 +1,120 @@
<?php
include "../../connect.php";
try {
// 1) قراءة والتحقق من الإحداثيات
$southwestLat = filterRequest("southwestLat");
$southwestLon = filterRequest("southwestLon");
$northeastLat = filterRequest("northeastLat");
$northeastLon = filterRequest("northeastLon");
if ($southwestLat === false || $southwestLon === false ||
$northeastLat === false || $northeastLon === false) {
printFailure("Invalid coordinates provided");
exit;
}
// نافذة زمنية ثابتة (بدون توسيع)
$freshSeconds = 180; // 3 دقائق
$sql = "
SELECT
cl.driver_id,
cl.latitude,
cl.longitude,
cl.heading,
cl.speed,
cl.status,
cl.created_at,
cl.updated_at,
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,
dt.token,
COALESCE(rdAvg.ratingDriver, 0) AS ratingDriver,
COALESCE(rdAvg.ratingCount, 0) AS ratingCount
FROM car_locations cl
LEFT JOIN driver d ON d.id = cl.driver_id
LEFT JOIN CarRegistration cr ON cr.driverID = cl.driver_id
LEFT JOIN driverToken dt ON dt.captain_id = cl.driver_id
LEFT JOIN (
SELECT driver_id, AVG(rating) AS ratingDriver, COUNT(id) AS ratingCount
FROM ratingDriver
GROUP BY driver_id
) rdAvg ON rdAvg.driver_id = cl.driver_id
WHERE
cl.latitude BETWEEN :southwestLat AND :northeastLat
AND cl.longitude BETWEEN :southwestLon AND :northeastLon
AND cl.status = 'off'
AND cl.updated_at >= NOW() - INTERVAL :freshSeconds SECOND
AND COALESCE(cr.year, 0) < 2000
AND (cr.make NOT LIKE '%دراج%' AND cr.model NOT LIKE '%دراج%')
ORDER BY
ratingDriver DESC, -- ⭐ الأولوية للتقييم
ratingCount DESC, -- ثم الأكثر حصولاً على تقييمات
cl.updated_at DESC -- ثم الأحدث تحديثًا كفاصل
LIMIT 5
";
$stmt = $con->prepare($sql);
$stmt->bindValue(':southwestLat', $southwestLat);
$stmt->bindValue(':southwestLon', $southwestLon);
$stmt->bindValue(':northeastLat', $northeastLat);
$stmt->bindValue(':northeastLon', $northeastLon);
$stmt->bindValue(':freshSeconds', $freshSeconds, PDO::PARAM_INT);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (!$rows) {
printFailure("No car locations found");
exit;
}
// تفكيك التشفير + حساب العمر
$fieldsToDecrypt = [
'phone','email','gender','birthdate',
'first_name','last_name','maritalStatus',
'token','make','car_plate','vin'
];
foreach ($rows as &$row) {
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;
}
}
unset($row);
printSuccess($rows);
} catch (PDOException $e) {
printFailure("Database error: " . $e->getMessage());
} catch (Throwable $e) {
printFailure("Internal error: " . $e->getMessage());
}

View File

@@ -0,0 +1,124 @@
<?php
include "../../connect.php";
try {
// ✅ قراءة والتحقق من الإحداثيات
$southwestLat = filterRequest("southwestLat");
$southwestLon = filterRequest("southwestLon");
$northeastLat = filterRequest("northeastLat");
$northeastLon = filterRequest("northeastLon");
if ($southwestLat === false || $southwestLon === false ||
$northeastLat === false || $northeastLon === false) {
printFailure("Invalid coordinates provided");
exit;
}
// ⏱️ نافذة زمنية ثابتة بالثواني (بدّلها عند الحاجة)
$freshSeconds = 180; // 3 دقائق
// ✅ الاستعلام الآمن والمهيأ
$sql = "
SELECT
cl.driver_id,
cl.latitude,
cl.longitude,
cl.heading,
cl.speed,
cl.status,
cl.created_at,
cl.updated_at,
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,
dt.token,
COALESCE(rdAvg.ratingDriver, 0) AS ratingDriver,
COALESCE(rdAvg.ratingCount, 0) AS ratingCount
FROM car_locations cl
LEFT JOIN driver d ON d.id = cl.driver_id
LEFT JOIN CarRegistration cr ON cr.driverID = cl.driver_id
LEFT JOIN driverToken dt ON dt.captain_id = cl.driver_id
LEFT JOIN (
SELECT driver_id, AVG(rating) AS ratingDriver, COUNT(*) AS ratingCount
FROM ratingDriver
GROUP BY driver_id
) rdAvg ON rdAvg.driver_id = cl.driver_id
WHERE
cl.latitude BETWEEN :southwestLat AND :northeastLat
AND cl.longitude BETWEEN :southwestLon AND :northeastLon
AND cl.status = 'off'
AND cl.updated_at >= NOW() - INTERVAL :freshSeconds SECOND
AND COALESCE(cr.year, 0) > 2017
AND (cr.make NOT LIKE '%دراج%' AND cr.model NOT LIKE '%دراج%')
ORDER BY
ratingDriver DESC, -- ⭐ الأولوية للأعلى تقييماً
ratingCount DESC, -- ثم الأكثر حصولاً على تقييمات
cl.updated_at DESC -- ثم الأحدث تحديثاً كفاصل
LIMIT 5
";
$stmt = $con->prepare($sql);
$stmt->bindValue(':southwestLat', $southwestLat);
$stmt->bindValue(':southwestLon', $southwestLon);
$stmt->bindValue(':northeastLat', $northeastLat);
$stmt->bindValue(':northeastLon', $northeastLon);
$stmt->bindValue(':freshSeconds', $freshSeconds, PDO::PARAM_INT);
$stmt->execute();
$car_locations = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($car_locations) {
// ✅ فك التشفير (مع حماية الأخطاء)
$fieldsToDecrypt = [
'phone','email','gender','birthdate',
'first_name','last_name','maritalStatus',
'token','make','car_plate','vin'
];
foreach ($car_locations as &$row) {
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;
}
}
unset($row);
printSuccess($car_locations);
} else {
printFailure("No car locations found");
}
} catch (PDOException $e) {
printFailure("Database error: " . $e->getMessage());
} catch (Throwable $e) {
printFailure("Internal error: " . $e->getMessage());
}

View File

@@ -0,0 +1,125 @@
<?php
include "../../connect.php";
try {
// ✅ قراءة والتحقق من الإحداثيات
$southwestLat = filterRequest("southwestLat");
$southwestLon = filterRequest("southwestLon");
$northeastLat = filterRequest("northeastLat");
$northeastLon = filterRequest("northeastLon");
if ($southwestLat === false || $southwestLon === false ||
$northeastLat === false || $northeastLon === false) {
printFailure("Invalid coordinates provided");
exit;
}
// ⏱️ نافذة زمنية ثابتة (ثواني)
$freshSeconds = 180; // 3 دقائق — عدّلها إذا لزم
// ✅ الاستعلام الآمن والمهيأ
$sql = "
SELECT
cl.driver_id,
cl.latitude,
cl.longitude,
cl.heading,
cl.speed,
cl.status,
cl.created_at,
cl.updated_at,
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,
dt.token,
COALESCE(rdAvg.ratingDriver, 0) AS ratingDriver,
COALESCE(rdAvg.ratingCount, 0) AS ratingCount
FROM car_locations cl
LEFT JOIN driver d ON d.id = cl.driver_id
LEFT JOIN CarRegistration cr ON cr.driverID = cl.driver_id
LEFT JOIN driverToken dt ON dt.captain_id = cl.driver_id
LEFT JOIN (
SELECT driver_id, AVG(rating) AS ratingDriver, COUNT(*) AS ratingCount
FROM ratingDriver
GROUP BY driver_id
) rdAvg ON rdAvg.driver_id = cl.driver_id
WHERE
cl.latitude BETWEEN :southwestLat AND :northeastLat
AND cl.longitude BETWEEN :southwestLon AND :northeastLon
AND cl.status = 'off'
AND cl.updated_at >= NOW() - INTERVAL :freshSeconds SECOND
-- ⛓️ اختيار فقط الدراجات
AND (cr.make LIKE '%دراج%' OR cr.model LIKE '%دراج%')
ORDER BY
ratingDriver DESC, -- ⭐ أولاً الأعلى تقييماً
ratingCount DESC, -- ثم الأكثر حصولاً على تقييمات
cl.updated_at DESC -- ثم الأحدث تحديثاً كفاصل
LIMIT 10
";
$stmt = $con->prepare($sql);
$stmt->bindValue(':southwestLat', $southwestLat);
$stmt->bindValue(':southwestLon', $southwestLon);
$stmt->bindValue(':northeastLat', $northeastLat);
$stmt->bindValue(':northeastLon', $northeastLon);
$stmt->bindValue(':freshSeconds', $freshSeconds, PDO::PARAM_INT);
$stmt->execute();
$car_locations = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (!$car_locations) {
printFailure("No car locations found");
exit;
}
// ✅ فك التشفير (مع حماية الأخطاء)
$fieldsToDecrypt = [
'phone','email','gender','birthdate',
'first_name','last_name','maritalStatus',
'token','make','car_plate','vin'
];
foreach ($car_locations as &$row) {
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;
}
}
unset($row);
printSuccess($car_locations);
} catch (PDOException $e) {
printFailure("Database error: " . $e->getMessage());
} catch (Throwable $e) {
printFailure("Internal error: " . $e->getMessage());
}

View File

@@ -0,0 +1,70 @@
<?php
/**
* Real-time Driver Location Tracker (Last 10 Days - Full Records)
*/
include_once("../../jwtconnect.php");
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
// API Key
$expected_api_key = getenv('LOCATION_SERVER_API_KEY');
function get_api_key()
{
$headers = getallheaders();
if (isset($headers['x-api-key']))
return $headers['x-api-key'];
if (isset($headers['X-API-KEY']))
return $headers['X-API-KEY'];
if (isset($_SERVER['HTTP_X_API_KEY']))
return $_SERVER['HTTP_X_API_KEY'];
return '';
}
$provided_api_key = get_api_key();
if ($provided_api_key !== $expected_api_key) {
http_response_code(401);
echo json_encode(['error' => 'Unauthorized access']);
exit;
}
// 3. API Input (Optional days parameter, default 1)
$days = isset($_GET['days']) ? (int)$_GET['days'] : 1;
//if ($days < 1 || $days > 30) $days = 1;
if ($days < 1 || $days > 10) $days = 1;
// SQL
$sql = "
SELECT *
FROM car_tracks
WHERE created_at >= NOW() - INTERVAL $days DAY
ORDER BY created_at DESC
";
try {
$stmt = $con->prepare($sql);
$stmt->execute();
// جلب كل النتائج دفعة واحدة
$records = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode([
'success' => true,
'total_records' => count($records),
'from' => date('Y-m-d H:i:s', strtotime("-$days days")),
'to' => date('Y-m-d H:i:s'),
'data' => $records
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
}
catch (PDOException $e) {
http_response_code(500);
echo json_encode([
'error' => 'Database error',
'details' => $e->getMessage()
]);
}

View File

@@ -0,0 +1,43 @@
<?php
include "../../connect.php";
$driver_id = filterRequest("driver_id");
$sql = "SELECT
cl.driver_id,
cl.latitude,
cl.longitude,
cl.heading,
cl.speed,
cl.status,
cl.created_at,
cl.updated_at,
d.gender,
cr.model
FROM
car_locations cl
LEFT JOIN driver d ON
cl.driver_id = d.id
LEFT JOIN CarRegistration cr ON
cl.driver_id = cr.driverID
WHERE
cl.driver_id = '$driver_id'
ORDER BY
created_at
DESC
LIMIT 1;";
$stmt = $con->prepare($sql);
$stmt->execute();
$car_locations = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($car_locations) {
// Print the car location data as JSON
printSuccess($data = $car_locations);
} else {
// Print a failure message
printFailure($message = "No car locations found");
}
?>

View File

@@ -0,0 +1,126 @@
<?php
include "../../connect.php";
try {
// ✅ قراءة والتحقق من الإحداثيات
$southwestLat = filterRequest("southwestLat");
$southwestLon = filterRequest("southwestLon");
$northeastLat = filterRequest("northeastLat");
$northeastLon = filterRequest("northeastLon");
if ($southwestLat === false || $southwestLon === false ||
$northeastLat === false || $northeastLon === false) {
printFailure("Invalid coordinates provided");
exit;
}
// ⏱️ نافذة زمنية ثابتة
$freshSeconds = 180; // 3 دقائق
// ✅ الاستعلام
$sql = "
SELECT
cl.driver_id,
cl.latitude,
cl.longitude,
cl.heading,
cl.speed,
cl.status,
cl.created_at,
cl.updated_at,
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.fuel,
dt.token,
COALESCE(rdAvg.ratingDriver, 0) AS ratingDriver,
COALESCE(rdAvg.ratingCount, 0) AS ratingCount
FROM car_locations cl
LEFT JOIN driver d ON d.id = cl.driver_id
LEFT JOIN CarRegistration cr ON cr.driverID = cl.driver_id
LEFT JOIN driverToken dt ON dt.captain_id = cl.driver_id
LEFT JOIN (
SELECT driver_id, AVG(rating) AS ratingDriver, COUNT(*) AS ratingCount
FROM ratingDriver
GROUP BY driver_id
) rdAvg ON rdAvg.driver_id = cl.driver_id
WHERE
cl.latitude BETWEEN :southwestLat AND :northeastLat
AND cl.longitude BETWEEN :southwestLon AND :northeastLon
AND cl.status = 'off'
AND cl.updated_at >= NOW() - INTERVAL :freshSeconds SECOND
AND (cr.make NOT LIKE '%دراج%' AND cr.model NOT LIKE '%دراج%')
AND cr.fuel = 'كهربائي'
ORDER BY
ratingDriver DESC, -- ⭐ الأعلى تقييماً
ratingCount DESC, -- ثم الأكثر حصولاً على تقييمات
cl.updated_at DESC -- ثم الأحدث تحديثاً
LIMIT 10
";
$stmt = $con->prepare($sql);
$stmt->bindValue(':southwestLat', $southwestLat);
$stmt->bindValue(':southwestLon', $southwestLon);
$stmt->bindValue(':northeastLat', $northeastLat);
$stmt->bindValue(':northeastLon', $northeastLon);
$stmt->bindValue(':freshSeconds', $freshSeconds, PDO::PARAM_INT);
$stmt->execute();
$car_locations = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (!$car_locations) {
printFailure("No electric car locations found");
exit;
}
// ✅ فك التشفير + حساب العمر
$fieldsToDecrypt = [
'phone','email','gender','birthdate',
'first_name','last_name','maritalStatus',
'token','make','car_plate','vin'
];
foreach ($car_locations as &$row) {
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;
}
}
unset($row);
printSuccess($car_locations);
} catch (PDOException $e) {
printFailure("Database error: " . $e->getMessage());
} catch (Throwable $e) {
printFailure("Internal error: " . $e->getMessage());
}

View File

@@ -0,0 +1,111 @@
<?php
include "../../connect.php";
try {
$southwestLat = filterRequest("southwestLat");
$southwestLon = filterRequest("southwestLon");
$northeastLat = filterRequest("northeastLat");
$northeastLon = filterRequest("northeastLon");
if ($southwestLat === false || $southwestLon === false ||
$northeastLat === false || $northeastLon === false) {
printFailure("Invalid coordinates provided");
exit;
}
$sql = "
SELECT
cl.driver_id,
cl.latitude,
cl.longitude,
cl.heading,
cl.speed,
cl.status,
cl.created_at,
cl.updated_at,
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,
dt.token,
COALESCE(AVG(rd.rating), 0) AS ratingDriver,
COUNT(rd.id) AS ratingCount,
'' AS age
FROM car_locations cl
LEFT JOIN driver d ON d.id = cl.driver_id
LEFT JOIN CarRegistration cr ON cr.driverID = cl.driver_id
LEFT JOIN driverToken dt ON dt.captain_id = cl.driver_id
LEFT JOIN ratingDriver rd ON rd.driver_id = cl.driver_id
WHERE
cl.latitude BETWEEN :southwestLat AND :northeastLat
AND cl.longitude BETWEEN :southwestLon AND :northeastLon
AND cl.status = 'off'
AND cl.updated_at >= NOW() - INTERVAL 180 SECOND
AND (cr.make NOT LIKE '%دراجة%' AND cr.model NOT LIKE '%دراجة%')
AND d.gender = 'Female'
GROUP BY cl.driver_id
ORDER BY ratingDriver DESC, ratingCount DESC, cl.updated_at DESC
LIMIT 10;
";
$stmt = $con->prepare($sql);
$stmt->bindParam(':southwestLat', $southwestLat);
$stmt->bindParam(':southwestLon', $southwestLon);
$stmt->bindParam(':northeastLat', $northeastLat);
$stmt->bindParam(':northeastLon', $northeastLon);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($rows) {
$fieldsToDecrypt = [
'phone','email','gender','birthdate',
'first_name','last_name','token',
'make','car_plate','vin','maritalStatus'
];
foreach ($rows as &$row) {
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;
}
}
unset($row);
printSuccess($rows);
} else {
printFailure("No car locations found");
}
} catch (PDOException $e) {
printFailure("Database error: " . $e->getMessage());
} catch (Throwable $e) {
printFailure("Internal error: " . $e->getMessage());
}

View File

@@ -0,0 +1,29 @@
<?php
include "../../connect.php";
$rideId = filterRequest("rideId");
$sql = "SELECT
*
FROM
`passengerlocation` pl
WHERE
pl.rideId = '$rideId'
ORDER BY
pl.createdAt
DESC
LIMIT 1";
$stmt = $con->prepare($sql);
$stmt->execute();
$car_locations = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($car_locations) {
// Print the car location data as JSON
printSuccess($data = $car_locations);
} else {
// Print a failure message
printFailure($message = "No car locations found");
}
?>

View File

@@ -0,0 +1,42 @@
<?php
include "../../connect.php";
$driver_id = filterRequest("driver_id");
$sql = "SELECT
car_locations.id,
car_locations.driver_id,
car_locations.latitude,
car_locations.longitude,
car_locations.heading,
car_locations.speed,
car_locations.`status`,
car_locations.created_at,
car_locations.updated_at,
`driver`.`gender`,
CarRegistration.model
FROM
car_locations
LEFT JOIN `driver` ON `driver`.`id` = car_locations.driver_id
LEFT JOIN `CarRegistration`
ON `CarRegistration`.`driverID` = CarRegistration.driverID
WHERE
driver_id = '$driver_id'
ORDER BY
created_at
DESC
LIMIT 1;";
$stmt = $con->prepare($sql);
$stmt->execute();
$car_locations = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($car_locations) {
// Print the car location data as JSON
printSuccess($data = $car_locations);
} else {
// Print a failure message
printFailure($message = "No car locations found");
}
?>

View File

@@ -0,0 +1,112 @@
<?php
include "../../connect.php";
try {
$southwestLat = filterRequest("southwestLat");
$southwestLon = filterRequest("southwestLon");
$northeastLat = filterRequest("northeastLat");
$northeastLon = filterRequest("northeastLon");
if ($southwestLat === false || $southwestLon === false || $northeastLat === false || $northeastLon === false) {
printFailure("Invalid coordinates provided");
exit;
}
$sql = "
SELECT
cl.driver_id,
cl.latitude,
cl.longitude,
cl.heading,
cl.speed,
cl.status,
cl.created_at,
cl.updated_at,
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,
dt.token,
'' AS age,
COALESCE(rdAvg.ratingDriver, 0) AS ratingDriver,
rdAvg.ratingCount
FROM
car_locations cl
LEFT JOIN driver d ON d.id = cl.driver_id
LEFT JOIN CarRegistration cr ON cr.driverID = cl.driver_id
LEFT JOIN driverToken dt ON dt.captain_id = cl.driver_id
LEFT JOIN (
SELECT driver_id, AVG(rating) AS ratingDriver, COUNT(id) AS ratingCount
FROM ratingDriver
GROUP BY driver_id
) rdAvg ON rdAvg.driver_id = cl.driver_id
WHERE
cl.latitude BETWEEN :southwestLat AND :northeastLat
AND cl.longitude BETWEEN :southwestLon AND :northeastLon
AND cl.status = 'off'
AND cl.updated_at >= NOW() - INTERVAL 5 SECOND
AND (cr.make LIKE '%دراجة%' OR cr.model LIKE '%دراجة%')
GROUP BY cl.driver_id
ORDER BY ratingDriver DESC, cl.updated_at DESC
LIMIT 10;
";
$stmt = $con->prepare($sql);
$stmt->bindParam(':southwestLat', $southwestLat);
$stmt->bindParam(':southwestLon', $southwestLon);
$stmt->bindParam(':northeastLat', $northeastLat);
$stmt->bindParam(':northeastLon', $northeastLon);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($rows) {
$fieldsToDecrypt = [
'phone', 'email', 'gender', 'birthdate',
'first_name', 'last_name', 'maritalStatus', 'token',
'make', 'car_plate', 'vin'
];
$filteredRows = [];
foreach ($rows as &$row) {
foreach ($fieldsToDecrypt as $field) {
if (isset($row[$field])) {
$row[$field] = $encryptionHelper->decryptData($row[$field]);
}
}
// فلترة حسب الجنس
if (strtolower($row['gender']) !== 'female') {
continue;
}
// حساب العمر
if (!empty($row['birthdate'])) {
$birthDate = new DateTime($row['birthdate']);
$today = new DateTime();
$row['age'] = $today->diff($birthDate)->y;
} else {
$row['age'] = null;
}
$filteredRows[] = $row;
}
printSuccess($filteredRows);
} else {
printFailure("No car locations found");
}
} catch (PDOException $e) {
printFailure("Database error: " . $e->getMessage());
}

View File

@@ -0,0 +1,66 @@
<?php
include "../../connect.php";
$driver_id = filterRequest("driver_id");
$current_month = date('m');
$current_year = date('Y');
// Get the first and last days of the current month.
$first_day_of_month = date('Y-m-d', strtotime($current_year . '-' . $current_month . '-01'));
$last_day_of_month = date('Y-m-d', strtotime($current_year . '-' . $current_month . '-' . cal_days_in_month(CAL_GREGORIAN, $current_month, $current_year)));
// Create a SQL query to select the total duration for the driver for each day in the current month.
$sql = "SELECT
DATE(`ride`.created_at) AS day,
COUNT(`ride`.`id`) AS countRide,
SUM(`ride`.`price`) AS pricePerDay,
(
SELECT
SUM(`ride`.`price`)
FROM
`ride`
WHERE
`ride`.`driver_id` = :driver_id_total AND `ride`.`created_at` >= :first_day_total AND `ride`.created_at < :last_day_total AND `ride`.`status` = 'Finished'
) AS totalPrice,
(
SELECT
COUNT(`ride`.`id`)
FROM
`ride`
WHERE
`ride`.`driver_id` = :driver_id_count AND `ride`.`created_at` >= :first_day_count AND `ride`.created_at < :last_day_count AND `ride`.`status` = 'Finished'
) AS totalCount
FROM
`ride`
WHERE
`ride`.`driver_id` = :driver_id_main AND `ride`.`created_at` >= :first_day_main AND `ride`.created_at < :last_day_main AND `ride`.`status` = 'Finished'
GROUP BY
day
ORDER BY
day ASC;";
$stmt = $con->prepare($sql);
// Bind each parameter uniquely
$stmt->bindParam(':driver_id_total', $driver_id, PDO::PARAM_STR);
$stmt->bindParam(':first_day_total', $first_day_of_month, PDO::PARAM_STR);
$stmt->bindParam(':last_day_total', $last_day_of_month, PDO::PARAM_STR);
$stmt->bindParam(':driver_id_count', $driver_id, PDO::PARAM_STR);
$stmt->bindParam(':first_day_count', $first_day_of_month, PDO::PARAM_STR);
$stmt->bindParam(':last_day_count', $last_day_of_month, PDO::PARAM_STR);
$stmt->bindParam(':driver_id_main', $driver_id, PDO::PARAM_STR);
$stmt->bindParam(':first_day_main', $first_day_of_month, PDO::PARAM_STR);
$stmt->bindParam(':last_day_main', $last_day_of_month, PDO::PARAM_STR);
$stmt->execute();
$car_locations = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($car_locations) {
// Print the car location data as JSON
printSuccess($data = $car_locations);
} else {
// Print a failure message
printFailure($message = "No car locations found");
}
?>

View File

@@ -0,0 +1,119 @@
<?php
include "../../connect.php";
// Get and filter input
$southwestLat = filterRequest("southwestLat");
$southwestLon = filterRequest("southwestLon");
$northeastLat = filterRequest("northeastLat");
$northeastLon = filterRequest("northeastLon");
// Validate input
if (is_null($southwestLat) || is_null($southwestLon) || is_null($northeastLat) || is_null($northeastLon)) {
echo json_encode(['status' => 'failure', 'message' => 'Missing required parameters']);
exit;
}
try {
// نافذة زمنية مناسبة (3 دقائق)
$freshSeconds = 180;
$sql = "
SELECT
cl.driver_id,
cl.latitude,
cl.longitude,
cl.heading,
cl.speed,
cl.status,
cl.created_at,
cl.updated_at,
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,
dt.token,
COALESCE(rd.ratingDriver, 0) AS ratingDriver,
COALESCE(rd.ratingCount, 0) AS ratingCount
FROM car_locations cl
LEFT JOIN driver d ON d.id = cl.driver_id
LEFT JOIN CarRegistration cr ON cr.driverID = cl.driver_id
LEFT JOIN driverToken dt ON dt.captain_id = cl.driver_id
LEFT JOIN (
SELECT driver_id, AVG(rating) AS ratingDriver, COUNT(id) AS ratingCount
FROM ratingDriver
GROUP BY driver_id
) rd ON rd.driver_id = cl.driver_id
WHERE
cl.latitude BETWEEN :southwestLat AND :northeastLat
AND cl.longitude BETWEEN :southwestLon AND :northeastLon
AND cl.status = 'off'
AND cl.updated_at >= NOW() - INTERVAL :freshSeconds SECOND
AND COALESCE(cr.year, 0) > 2000
AND (cr.make NOT LIKE '%دراج%' AND cr.model NOT LIKE '%دراج%')
ORDER BY
ratingDriver DESC,
ratingCount DESC,
cl.updated_at DESC
LIMIT 10;
";
$stmt = $con->prepare($sql);
$stmt->bindParam(':southwestLat', $southwestLat);
$stmt->bindParam(':southwestLon', $southwestLon);
$stmt->bindParam(':northeastLat', $northeastLat);
$stmt->bindParam(':northeastLon', $northeastLon);
$stmt->bindValue(':freshSeconds', $freshSeconds, PDO::PARAM_INT);
$stmt->execute();
$car_locations = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($car_locations) {
$fieldsToDecrypt = [
'phone','email','gender','birthdate',
'first_name','last_name','token',
'make','car_plate','vin','maritalStatus'
];
foreach ($car_locations as &$row) {
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']);
$now = new DateTime();
$row['age'] = $now->diff($birthdate)->y;
} catch (Exception $e) {
$row['age'] = null;
}
} else {
$row['age'] = null;
}
}
unset($row);
printSuccess($car_locations);
} else {
printFailure("No car locations found");
}
} catch (PDOException $e) {
printFailure("Database error: " . $e->getMessage());
}

View File

@@ -0,0 +1,44 @@
<?php
include "../../connect.php";
$driver_id = filterRequest("driver_id");
$current_month = date('m');
$current_year = date('Y');
// Get the first and last days of the current month.
$first_day_of_month = date('Y-m-d', strtotime($current_year . '-' . $current_month . '-01'));
$last_day_of_month = date('Y-m-d', strtotime($current_year . '-' . $current_month . '-' . cal_days_in_month(CAL_GREGORIAN, $current_month, $current_year)));
// Create a SQL query to select the total duration for the driver for each day in the current month.
$sql = "SELECT
DATE(created_at) AS day,
SEC_TO_TIME(COUNT(*) * 60) AS total_duration
FROM
car_tracks
WHERE
car_tracks.driver_id = :driver_id
AND car_tracks.created_at >= :first_day_of_month
AND car_tracks.created_at < :last_day_of_month
GROUP BY
day
ORDER BY
day ASC;";
$stmt = $con->prepare($sql);
$stmt->bindParam(':driver_id', $driver_id, PDO::PARAM_STR);
$stmt->bindParam(':first_day_of_month', $first_day_of_month, PDO::PARAM_STR);
$stmt->bindParam(':last_day_of_month', $last_day_of_month, PDO::PARAM_STR);
$stmt->execute();
$car_locations = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($car_locations) {
// Print the car location data as JSON
printSuccess($data = $car_locations);
} else {
// Print a failure message
printFailure($message = "No car locations found");
}
?>

View File

@@ -0,0 +1,70 @@
<?php
// 1. إعدادات التصحيح (Debug) - ضرورية جداً الآن
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With, Access-Control-Allow-Origin");
header("Access-Control-Allow-Methods: POST, OPTIONS , GET");
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// 2. تضمين ملف الاتصال
if (file_exists("../../connect.php")) {
include "../../connect.php";
} else {
// في حال عدم وجود الملف، ننهي التنفيذ ونطبع السبب
die(json_encode(array("status" => "failure", "message" => "Connect file not found")));
}
// 3. التقاط البيانات بذكاء (لحل مشكلة Flutter JSON)
// هذا الجزء يفحص: هل البيانات في POST؟ أم في JSON Body؟
$driver_id = null;
if (isset($_POST['driver_id'])) {
$driver_id = filterRequest("driver_id");
} else {
// محاولة قراءة JSON Body (لأن فلاتر يرسل البيانات هكذا غالباً)
$jsonInput = json_decode(file_get_contents("php://input"), true);
if (isset($jsonInput['driver_id'])) {
$driver_id = htmlspecialchars(strip_tags($jsonInput['driver_id']));
}
}
// التحقق النهائي
if (!$driver_id) {
// طباعة الخطأ بوضوح
echo json_encode(array("status" => "failure", "message" => "driver_id is missing or empty"));
exit;
}
// 4. التنفيذ
try {
$date = date('Y-m-d');
$sql = "SELECT total_seconds FROM driver_daily_summary
WHERE driver_id = ? AND date = ?";
$stmt = $con->prepare($sql);
$stmt->execute([$driver_id, $date]);
$data = $stmt->fetch(PDO::FETCH_ASSOC);
$duration = "00:00:00";
if ($data) {
$seconds = $data['total_seconds'];
$duration = gmdate("H:i:s", $seconds);
}
// 5. بناء الاستجابة يدوياً لتطابق كود Flutter 100%
// الهيكل المطلوب: data['message'][0]['total_duration']
$response = array(
"status" => "success",
"message" => array(
array("total_duration" => $duration)
)
);
echo json_encode($response);
} catch (PDOException $e) {
echo json_encode(array("status" => "failure", "message" => "DB Error: " . $e->getMessage()));
}
?>

View File

@@ -0,0 +1,24 @@
<?php
include "../../connect.php";
// Use prepared statement to prevent SQL injection
$sql = "
SELECT * FROM `server_locations`
";
try {
$stmt = $con->prepare($sql);
$stmt->execute();
$car_locations = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($car_locations) {
printSuccess($car_locations);
} else {
printFailure("No car locations found");
}
} catch (PDOException $e) {
printFailure("Database error: " . $e->getMessage());
}

View File

@@ -0,0 +1,86 @@
<?php
include "../../connect.php";
try {
$southwestLat = filterRequest("southwestLat");
$southwestLon = filterRequest("southwestLon");
$northeastLat = filterRequest("northeastLat");
$northeastLon = filterRequest("northeastLon");
$sql = "
SELECT
cl.driver_id,
cl.latitude,
cl.longitude,
cl.heading,
cl.speed,
cl.status,
cl.created_at,
cl.updated_at,
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,
dt.token,
COALESCE(AVG(rd.rating), 0) AS ratingDriver,
COUNT(rd.id) AS ratingCount,
TIMESTAMPDIFF(YEAR, d.birthdate, CURDATE()) AS age,
(
SELECT COALESCE(AVG(sub.behavior_score), 100)
FROM (
SELECT behavior_score
FROM driver_behavior db
WHERE db.driver_id = cl.driver_id
ORDER BY db.id DESC
LIMIT 5
) AS sub
) AS ai_behavior_score
FROM
car_locations cl
LEFT JOIN driver d ON
d.id = cl.driver_id
LEFT JOIN CarRegistration cr ON
cr.driverID = cl.driver_id
LEFT JOIN driverToken dt ON
dt.captain_id = cl.driver_id
LEFT JOIN ratingDriver rd ON
rd.driver_id = cl.driver_id
WHERE
cl.latitude >= :southwestLat AND cl.latitude <= :northeastLat
AND cl.longitude >= :southwestLon AND cl.longitude <= :northeastLon
AND cl.status = 'off'
AND cl.updated_at >= NOW() - INTERVAL 5 SECOND
AND (cr.make NOT LIKE '%دراجة%' OR cr.model NOT LIKE '%دراجة%')
AND d.gender = 'Female'
GROUP BY cl.driver_id
ORDER BY ratingDriver DESC, cl.updated_at DESC
LIMIT 10;
";
$stmt = $con->prepare($sql);
$stmt->bindParam(':southwestLat', $southwestLat);
$stmt->bindParam(':southwestLon', $southwestLon);
$stmt->bindParam(':northeastLat', $northeastLat);
$stmt->bindParam(':northeastLon', $northeastLon);
$stmt->execute();
$car_locations = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($car_locations) {
printSuccess($car_locations);
} else {
printFailure("No car locations found");
}
} catch (PDOException $e) {
printFailure("Database error: " . $e->getMessage());
}
?>

View File

@@ -0,0 +1,59 @@
<?php
include "../../connect.php";
// استلام البيانات من Flutter
$driver_id = filterRequest("driver_id");
$trip_id = filterRequest("trip_id");
$max_speed = filterRequest("max_speed");
$avg_speed = filterRequest("avg_speed");
$hard_brakes = filterRequest("hard_brakes");
$total_distance = filterRequest("total_distance");
$behavior_score = filterRequest("behavior_score");
// تحقق من القيم الأساسية
if (empty($driver_id) || empty($trip_id)) {
// Log the validation error
error_log("Driver Behavior Error: Missing driver_id ($driver_id) or trip_id ($trip_id)");
printFailure("Missing driver_id or trip_id");
exit();
}
try {
// إدخال البيانات في جدول driver_behavior
$stmt = $con->prepare("
INSERT INTO driver_behavior (
driver_id, trip_id, max_speed, avg_speed,
hard_brakes, total_distance, behavior_score
) VALUES (?, ?, ?, ?, ?, ?, ?)
");
$stmt->execute([
$driver_id,
$trip_id,
$max_speed,
$avg_speed,
$hard_brakes,
$total_distance,
$behavior_score
]);
// التحقق من نجاح العملية
if ($stmt->rowCount() > 0) {
printSuccess("Behavior data saved");
} else {
// Log that the query ran but no rows were inserted
error_log("Driver Behavior Warning: Insert executed but 0 rows affected for driver $driver_id");
printFailure("Failed to save data");
}
} catch (PDOException $e) {
// --- THIS IS THE TYPE ERROR LOG YOU ASKED FOR ---
// This records the exact SQL error (e.g., duplicate entry, foreign key fail) to your server log
error_log("Driver Behavior SQL Error: " . $e->getMessage());
// Return a generic error to the app (or $e->getMessage() if debugging)
printFailure("Database Error");
}
exit();
?>

View File

@@ -0,0 +1,65 @@
<?php
include "../../connect.php";
$driver_id = filterRequest("driver_id");
$latitude = filterRequest("latitude");
$longitude = filterRequest("longitude");
$status = filterRequest("status");
$heading = filterRequest("heading");
$speed = filterRequest("speed");
$distance = filterRequest("distance");
// 1. قمنا بحذف السطر التالي لأنه مصدر المشكلة
// $updated_at = date("Y-m-d H:i:s");
// Basic validation
if (!$driver_id || !$latitude || !$longitude || $status === null) {
http_response_code(400);
printFailure('Missing required fields');
exit;
}
// Secure SQL using prepared statement
// 2. لاحظ التغيير داخل جملة SQL
// بدلنا :updated_at بكلمة NOW() وهي دالة في قاعدة البيانات
$sql = "INSERT INTO `car_locations` (
`driver_id`, `latitude`, `longitude`, `heading`, `speed`, `distance`, `status`, `updated_at`
) VALUES (
:driver_id, :latitude, :longitude, :heading, :speed, :distance, :status, NOW()
)
ON DUPLICATE KEY UPDATE
`latitude` = VALUES(`latitude`),
`longitude` = VALUES(`longitude`),
`heading` = VALUES(`heading`),
`speed` = VALUES(`speed`),
`distance` = VALUES(`distance`),
`status` = VALUES(`status`),
`updated_at` = NOW()"; // وهنا أيضاً جعلنا التحديث يأخذ وقت السيرفر مباشرة
try {
$stmt = $con->prepare($sql);
// The execute method returns true on success and false on failure.
$success = $stmt->execute([
':latitude' => $latitude,
':longitude' => $longitude,
':heading' => $heading,
':speed' => $speed,
':distance' => $distance,
':status' => $status,
// ':updated_at' => $updated_at, <-- قمنا بحذف هذا السطر من المصفوفة لأنه لم يعد موجوداً في الاستعلام
':driver_id' => $driver_id
]);
if ($success) {
printSuccess("Car location updated successfully");
} else {
printFailure("Failed to update car location");
}
} catch (PDOException $e) {
http_response_code(500);
printFailure('Database error occurred');
}
?>

View File

@@ -0,0 +1,48 @@
<?php
include "../../connect.php";
// استقبال البيانات من تطبيق السائق
$driver_id = filterRequest("driver_id");
$lat = filterRequest("lat");
$lng = filterRequest("lng");
$heading = filterRequest("heading"); // اتجاه السيارة
$speed = filterRequest("speed");
$status = filterRequest("status"); // 'on' (متاح) أو 'off' (مشغول/غير متاح)
if (!$driver_id || !$lat || !$lng) {
printFailure("Missing Data");
exit;
}
try {
// استخدام ON DUPLICATE KEY UPDATE لضمان وجود صف واحد فقط لكل سائق
// الجدول: car_locations
$sql = "INSERT INTO car_locations (driver_id, latitude, longitude, heading, speed, status, updated_at)
VALUES (:id, :lat, :lng, :head, :spd, :stat, NOW())
ON DUPLICATE KEY UPDATE
latitude = :lat,
longitude = :lng,
heading = :head,
speed = :spd,
status = :stat,
updated_at = NOW()";
$stmt = $con_tracking->prepare($sql);
$stmt->execute([
':id' => $driver_id,
':lat' => $lat,
':lng' => $lng,
':head' => $heading,
':spd' => $speed,
':stat' => $status
]);
// ملاحظة: لا نحتاج لإرسال socket notification هنا لأن هذا يحدث كل ثانية
// الراكب يرى التحديث لأنه متصل بسوكيت اللوكيشن ويستمع لحدث 'update_driver_location'
printSuccess("Location Updated");
} catch (PDOException $e) {
printFailure("DB Error: " . $e->getMessage());
}
?>