256 lines
12 KiB
PHP
Executable File
256 lines
12 KiB
PHP
Executable File
<?php
|
|
// add_ride.php
|
|
|
|
// 1. تضمين ملف الاتصال بقاعدة البيانات
|
|
require_once __DIR__ . '/../../connect.php';
|
|
$con_ride = Database::get('ride');
|
|
// include "functions.php"; // (تأكد من وجود دوال المساعدة مثل notifyPassengerSocket هنا أو ضمنها)
|
|
|
|
// إعدادات تتبع الأخطاء (للسيرفر)
|
|
ini_set('log_errors', 1);
|
|
ini_set('error_log', '/home/intaleq-api/add_ride_error.log');
|
|
|
|
// =================================================================================
|
|
// 🛠️ دالة مساعدة: إرسال الرحلة لسوق السائقين (Marketplace Broadcast)
|
|
// الوظيفة: ترسل بيانات الرحلة لسيرفر اللوكيشن ليقوم بحفظها في Redis وبثها للسائقين
|
|
// =================================================================================
|
|
function broadcastRideToMarket($rideId, $lat, $lng, $payloadData) {
|
|
// رابط سيرفر اللوكيشن (تأكد من صحة الرابط والبورت)
|
|
$url = "http://location.intaleq.xyz:2021";
|
|
|
|
// قراءة مفتاح الأمان الداخلي للمصادقة
|
|
$INTERNAL_KEY = trim(@file_get_contents('/home/intaleq-api/.internal_socket_key'));
|
|
|
|
// تجهيز البيانات بشكل (Key-Value Map) لسهولة التعامل في التطبيق والسوكيت
|
|
// ملاحظة: نستخدم القيم من $payloadData التي هي عبارة عن List حالياً
|
|
$marketPayload = [
|
|
'id' => (string)$rideId,
|
|
'start_lat' => $lat,
|
|
'start_lng' => $lng,
|
|
'price' => $payloadData[2], // السعر
|
|
'carType' => $payloadData[31], // نوع السيارة
|
|
'startName' => $payloadData[29], // اسم موقع البدء
|
|
'endName' => $payloadData[30], // اسم موقع الوصول
|
|
'distance' => $payloadData[11], // المسافة
|
|
'duration' => $payloadData[15], // الوقت
|
|
'passengerRate' => $payloadData[33], // تقييم الراكب
|
|
// يمكنك إضافة المزيد هنا حسب الحاجة
|
|
];
|
|
|
|
$postData = [
|
|
'action' => 'market_new_ride', // اسم الحدث في السوكيت
|
|
'payload' => $marketPayload
|
|
];
|
|
|
|
// إرسال الطلب (cURL)
|
|
$ch = curl_init();
|
|
curl_setopt($ch, CURLOPT_URL, $url);
|
|
curl_setopt($ch, CURLOPT_POST, 1);
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
// وقت انتظار قصير جداً (200ms) لأننا لا نريد تأخير استجابة الراكب
|
|
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 200);
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-internal-key: $INTERNAL_KEY"]);
|
|
curl_exec($ch);
|
|
curl_close($ch);
|
|
}
|
|
|
|
// =================================================================================
|
|
// 2. استقبال وتصفية البيانات من التطبيق
|
|
// =================================================================================
|
|
$start_location = filterRequest("start_location");
|
|
$end_location = filterRequest("end_location");
|
|
$date_raw = filterRequest("date");
|
|
$time_raw = filterRequest("time");
|
|
$endtime_raw = filterRequest("endtime");
|
|
$price = filterRequest("price");
|
|
$passenger_id = filterRequest("passenger_id");
|
|
$driver_id = filterRequest("driver_id") ?: 0;
|
|
$status = filterRequest("status");
|
|
$price_for_driver = filterRequest("price_for_driver");
|
|
$price_for_passenger = filterRequest("price_for_passenger");
|
|
$distance = filterRequest("distance");
|
|
$carType = filterRequest("carType");
|
|
|
|
// بيانات الراكب الإضافية
|
|
$passenger_name = filterRequest("passenger_name");
|
|
$passenger_phone = filterRequest("passenger_phone");
|
|
$passenger_token = filterRequest("passenger_token");
|
|
$passenger_email = filterRequest("passenger_email");
|
|
$passenger_wallet = filterRequest("passenger_wallet");
|
|
$passenger_rating = filterRequest("passenger_rating");
|
|
|
|
// تفاصيل الرحلة والنصوص
|
|
$start_name_loc = filterRequest("start_name");
|
|
$end_name_loc = filterRequest("end_name");
|
|
$duration_text = filterRequest("duration_text");
|
|
$distance_text = filterRequest("distance_text");
|
|
$is_wallet = filterRequest("is_wallet");
|
|
$has_steps = filterRequest("has_steps");
|
|
|
|
$step0 = filterRequest("step0"); $step1 = filterRequest("step1");
|
|
$step2 = filterRequest("step2"); $step3 = filterRequest("step3");
|
|
$step4 = filterRequest("step4");
|
|
|
|
// معالجة الإحداثيات (فصل النص إلى Lat/Lng)
|
|
$startLat = ""; $startLng = "";
|
|
if (!empty($start_location)) {
|
|
$parts = explode(',', $start_location);
|
|
$startLat = trim($parts[0] ?? ""); $startLng = trim($parts[1] ?? "");
|
|
}
|
|
|
|
$endLat = ""; $endLng = "";
|
|
if (!empty($end_location)) {
|
|
$parts = explode(',', $end_location);
|
|
$endLat = trim($parts[0] ?? ""); $endLng = trim($parts[1] ?? "");
|
|
}
|
|
|
|
// تنسيق التواريخ
|
|
$date_formatted = date("Y-m-d", strtotime($date_raw));
|
|
$time_formatted = date("H:i:s", strtotime($time_raw));
|
|
$endtime_formatted = $endtime_raw ? date("H:i:s", strtotime($endtime_raw)) : "00:00:00";
|
|
|
|
// مصفوفة البيانات للإدخال
|
|
$data = [
|
|
":start_location" => $start_location,
|
|
":end_location" => $end_location,
|
|
":date" => $date_formatted,
|
|
":time" => $time_formatted,
|
|
":endtime" => $endtime_formatted,
|
|
":price" => $price,
|
|
":passenger_id" => $passenger_id,
|
|
":driver_id" => $driver_id,
|
|
":status" => $status,
|
|
":carType" => $carType,
|
|
":price_for_driver" => $price_for_driver,
|
|
":price_for_passenger" => $price_for_passenger,
|
|
":distance" => $distance,
|
|
];
|
|
|
|
// جملة SQL للإدخال
|
|
$sql = "INSERT INTO `ride` (
|
|
`start_location`, `end_location`, `date`, `time`, `endtime`,
|
|
`price`, `passenger_id`, `driver_id`, `status`, `carType`,
|
|
`price_for_driver`, `price_for_passenger`, `distance`
|
|
) VALUES (
|
|
:start_location, :end_location, :date, :time, :endtime,
|
|
:price, :passenger_id, :driver_id, :status, :carType,
|
|
:price_for_driver, :price_for_passenger, :distance
|
|
)";
|
|
|
|
try {
|
|
// 3. الإدخال في قاعدة البيانات الرئيسية (Main DB)
|
|
$stmtMain = $con->prepare($sql);
|
|
$stmtMain->execute($data);
|
|
$insertedId = $con->lastInsertId(); // ID الرحلة الجديد
|
|
|
|
// 4. الإدخال في قاعدة بيانات الرحلات (Ride DB) للأرشفة والتزامن
|
|
try {
|
|
$stmtRide = $con_ride->prepare($sql);
|
|
$stmtRide->execute($data);
|
|
} catch (Exception $e) {
|
|
error_log("⚠️ RideDB Insert Warning: " . $e->getMessage());
|
|
}
|
|
|
|
if ($insertedId) {
|
|
error_log("📝 Ride #$insertedId added successfully.");
|
|
|
|
// 5. تجهيز الـ Payload (قائمة البيانات للتطبيق)
|
|
$kazan = (double)$price - (double)$price_for_driver;
|
|
$payloadTemplate = [];
|
|
// تعبئة البيانات بالترتيب الذي يتوقعه التطبيق (Indices 0-33)
|
|
$payloadTemplate[0] = (string)$startLat;
|
|
$payloadTemplate[1] = (string)$startLng;
|
|
$payloadTemplate[2] = (string)number_format($price, 2, '.', '');
|
|
$payloadTemplate[3] = (string)$endLat;
|
|
$payloadTemplate[4] = (string)$endLng;
|
|
$payloadTemplate[5] = (string)$distance_text;
|
|
$payloadTemplate[6] = "";
|
|
$payloadTemplate[7] = (string)$passenger_id;
|
|
$payloadTemplate[8] = (string)$passenger_name;
|
|
$payloadTemplate[9] = (string)$passenger_token;
|
|
$payloadTemplate[10] = (string)$passenger_phone;
|
|
$payloadTemplate[11] = (string)$distance;
|
|
$payloadTemplate[12] = "1";
|
|
$payloadTemplate[13] = (string)$is_wallet;
|
|
$payloadTemplate[14] = (string)$distance;
|
|
$payloadTemplate[15] = (string)$duration_text;
|
|
$payloadTemplate[16] = (string)$insertedId;
|
|
$payloadTemplate[17] = "";
|
|
$payloadTemplate[18] = "";
|
|
$payloadTemplate[19] = (string)$duration_text;
|
|
$payloadTemplate[20] = $has_steps ?: 'false';
|
|
$payloadTemplate[21] = (string)$step0;
|
|
$payloadTemplate[22] = (string)$step1;
|
|
$payloadTemplate[23] = (string)$step2;
|
|
$payloadTemplate[24] = (string)$step3;
|
|
$payloadTemplate[25] = (string)$step4;
|
|
$payloadTemplate[26] = (string)number_format($price_for_driver, 2, '.', '');
|
|
$payloadTemplate[27] = (string)$passenger_wallet;
|
|
$payloadTemplate[28] = (string)$passenger_email;
|
|
$payloadTemplate[29] = (string)$start_name_loc;
|
|
$payloadTemplate[30] = (string)$end_name_loc;
|
|
$payloadTemplate[31] = (string)$carType;
|
|
$payloadTemplate[32] = (string)number_format($kazan, 2, '.', '');
|
|
$payloadTemplate[33] = (string)$passenger_rating;
|
|
|
|
ksort($payloadTemplate);
|
|
$payloadTemplate = array_values($payloadTemplate);
|
|
|
|
// 6. البحث عن السائقين للتوزيع المباشر (Direct Dispatch)
|
|
$driversData = findBestDrivers($con, $startLat, $startLng, $carType);
|
|
|
|
// متغير لنعرف هل وجدنا سائقين للتوجيه المباشر أم لا
|
|
$foundDirectDrivers = false;
|
|
|
|
if (!empty($driversData)) {
|
|
// أ. إرسال إشعار مباشر للسائقين المختارين
|
|
dispatchRideToDrivers($driversData, $insertedId, $payloadTemplate, $start_name_loc, $encryptionHelper);
|
|
error_log("📨 Dispatched Ride #$insertedId to " . count($driversData) . " drivers.");
|
|
$foundDirectDrivers = true;
|
|
} else {
|
|
error_log("⚠️ No specific drivers found for Direct Dispatch for Ride #$insertedId. Moved to Market only.");
|
|
}
|
|
|
|
// ب. 🔥 نشر الرحلة في السوق المفتوح (Marketplace) دائماً 🔥
|
|
// هذا هو طوق النجاة: حتى لو لم نجد سائقين أعلاه، نضعها في السوق
|
|
broadcastRideToMarket($insertedId, $startLat, $startLng, $payloadTemplate);
|
|
|
|
// ج. ✅ إرجاع نجاح للتطبيق دائماً (ليبقى الراكب في شاشة البحث)
|
|
// يمكنك إرسال معلومة إضافية للتطبيق أن البحث "عام" وليس "مباشر" إذا أردت
|
|
jsonSuccess($insertedId);
|
|
|
|
// ملاحظة: قمنا بإزالة كود الإلغاء (UPDATE ride SET status = 'cancelled...')
|
|
// لأننا نريد منح الفرصة للسائقين البعيدين قليلاً أو الذين فتحوا التطبيق للتو
|
|
|
|
|
|
/*
|
|
else {
|
|
// 🛑 حالة عدم العثور على سائقين
|
|
error_log("⚠️ No drivers found for Ride #$insertedId.");
|
|
|
|
// أ. إلغاء الرحلة فوراً في قواعد البيانات
|
|
// ملاحظة: غيرنا الحالة إلى رسالة واضحة
|
|
$con->prepare("UPDATE ride SET status = 'cancelled_no_driver_found' WHERE id = ?")->execute([$insertedId]);
|
|
$con_ride->prepare("UPDATE ride SET status = 'cancelled_no_driver_found' WHERE id = ?")->execute([$insertedId]);
|
|
|
|
// ب. إشعار الراكب عبر السوكيت (لإظهار Popup)
|
|
if (function_exists('notifyPassengerSocket')) {
|
|
notifyPassengerSocket($passenger_id, 'no_drivers_found', [
|
|
'ride_id' => $insertedId,
|
|
'message' => 'No drivers available nearby'
|
|
]);
|
|
}
|
|
|
|
// ج. إرجاع فشل للتطبيق
|
|
jsonError("no_drivers_found");
|
|
*/
|
|
} else {
|
|
jsonError("Failed to add ride");
|
|
}
|
|
|
|
} catch (Exception $e) {
|
|
error_log("AddRide Critical Error: " . $e->getMessage());
|
|
jsonError("Database Error");
|
|
}
|
|
?>
|