Initial commit with updated Auth and media ignored
This commit is contained in:
462
functions.php
Executable file
462
functions.php
Executable file
@@ -0,0 +1,462 @@
|
||||
<?php
|
||||
//functions.php
|
||||
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
use Firebase\JWT\ExpiredException;
|
||||
use Firebase\JWT\SignatureInvalidException;
|
||||
use Firebase\JWT\BeforeValidException;
|
||||
|
||||
|
||||
$INTERNAL_KEY = trim(file_get_contents('/home/intaleq-api/.internal_socket_key'));
|
||||
|
||||
|
||||
/**
|
||||
* دالة البحث الهجين (Redis + MySQL)
|
||||
* @param $redis Client : اتصال الريدز
|
||||
* @param $con PDO : اتصال قاعدة البيانات الرئيسية (Main DB)
|
||||
* @param $lat float : إحداثيات الراكب
|
||||
* @param $lng float : إحداثيات الراكب
|
||||
* @param $carType string: نوع الطلب (comfort, speed, Lady...)
|
||||
*/
|
||||
|
||||
function sendToLocationServer($action, $data) {
|
||||
// رابط سيرفر اللوكيشن الداخلي أو العام
|
||||
$url = "http://location.intaleq.xyz:2021";
|
||||
$INTERNAL_KEY = trim(@file_get_contents('/home/intaleq-api/.internal_socket_key'));
|
||||
|
||||
$postData = [
|
||||
'action' => $action,
|
||||
...$data
|
||||
];
|
||||
|
||||
$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);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 500); // سريع جداً
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-internal-key: $INTERNAL_KEY"]);
|
||||
curl_exec($ch);
|
||||
curl_close($ch);
|
||||
}
|
||||
|
||||
function findBestDrivers($con, $lat, $lng, $carType) {
|
||||
// 1. الاتصال بـ Redis لجلب الأقرب
|
||||
$locationServerUrl = "https://location.intaleq.xyz/api_get_nearby.php";
|
||||
$INTERNAL_KEY = trim(@file_get_contents('/home/intaleq-api/.internal_socket_key'));
|
||||
|
||||
$postData = ['lat' => $lat, 'lng' => $lng, 'radius' => 5, 'limit' => 100];
|
||||
|
||||
$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, 3);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-internal-key: $INTERNAL_KEY"]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$info = curl_getinfo($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ($info['http_code'] !== 200) return [];
|
||||
|
||||
$json = json_decode($response, true);
|
||||
$nearbyDrivers = ($json['status'] ?? false) ? $json['data'] : [];
|
||||
|
||||
if (empty($nearbyDrivers)) return [];
|
||||
|
||||
// 2. تجهيز البيانات للفلترة
|
||||
$driverIds = [];
|
||||
$redisMap = [];
|
||||
foreach ($nearbyDrivers as $d) {
|
||||
$driverIds[] = $d['id'];
|
||||
$redisMap[$d['id']] = $d;
|
||||
}
|
||||
|
||||
$placeholders = implode(',', array_fill(0, count($driverIds), '?'));
|
||||
|
||||
// تعريف الثوابت
|
||||
$CAT_CAR = 1; $CAT_BIKE = 2; $CAT_VAN = 3; $FUEL_ELECTRIC = 3;
|
||||
|
||||
// 3. الاستعلام (بدون platform)
|
||||
$sql = "SELECT
|
||||
d.id AS driver_id,
|
||||
dt.token,
|
||||
cr.year,
|
||||
cr.vehicle_category_id,
|
||||
d.gender
|
||||
FROM driver d
|
||||
JOIN CarRegistration cr ON cr.driverID = d.id
|
||||
JOIN driverToken dt ON dt.captain_id = d.id
|
||||
WHERE d.id IN ($placeholders) ";
|
||||
|
||||
$carType = trim($carType);
|
||||
switch ($carType) {
|
||||
case 'Comfort':
|
||||
$sql .= " AND cr.vehicle_category_id = $CAT_CAR AND CAST(TRIM(cr.year) AS UNSIGNED) > 2017 ";
|
||||
break;
|
||||
case 'Mishwar Vip':
|
||||
$sql .= " AND cr.vehicle_category_id = $CAT_CAR AND CAST(TRIM(cr.year) AS UNSIGNED) > 2020 ";
|
||||
break;
|
||||
case 'Scooter':
|
||||
case 'Pink Bike':
|
||||
$sql .= " AND cr.vehicle_category_id = $CAT_BIKE ";
|
||||
break;
|
||||
case 'Electric':
|
||||
$sql .= " AND cr.vehicle_category_id = $CAT_CAR AND cr.fuel_type_id = $FUEL_ELECTRIC ";
|
||||
break;
|
||||
case 'Lady':
|
||||
$femaleHash = 'bQ6yWJ2EVXKZooHdGclvmFiDlZCM8UYeO+ILFjDUvpQ=';
|
||||
$sql .= " AND cr.vehicle_category_id = $CAT_CAR AND d.gender = '$femaleHash' ";
|
||||
break;
|
||||
case 'Van':
|
||||
$sql .= " AND cr.vehicle_category_id = $CAT_VAN ";
|
||||
break;
|
||||
case 'Awfar Car':
|
||||
$sql .= " AND cr.vehicle_category_id = $CAT_CAR AND CAST(TRIM(cr.year) AS UNSIGNED) > 1995 ";
|
||||
break;
|
||||
case 'Fixed Price':
|
||||
case 'Speed':
|
||||
case 'Rayeh Gai':
|
||||
default:
|
||||
$sql .= " AND cr.vehicle_category_id = $CAT_CAR AND CAST(TRIM(cr.year) AS UNSIGNED) > 2000 ";
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt = $con->prepare($sql);
|
||||
$stmt->execute($driverIds);
|
||||
$finalDrivers = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// دمج البيانات
|
||||
foreach ($finalDrivers as &$driver) {
|
||||
$did = $driver['driver_id'];
|
||||
if (isset($redisMap[$did])) {
|
||||
$driver['distance_km'] = $redisMap[$did]['distance'];
|
||||
$driver['lat'] = $redisMap[$did]['lat'];
|
||||
$driver['lng'] = $redisMap[$did]['lng'];
|
||||
} else {
|
||||
$driver['distance_km'] = 999;
|
||||
}
|
||||
}
|
||||
|
||||
// الترتيب
|
||||
usort($finalDrivers, function($a, $b) {
|
||||
return $a['distance_km'] <=> $b['distance_km'];
|
||||
});
|
||||
|
||||
return array_slice($finalDrivers, 0, 30);
|
||||
} catch (Exception $e) {
|
||||
error_log("FindBestDrivers Error: " . $e->getMessage());
|
||||
return [];
|
||||
}
|
||||
}
|
||||
// --- دالة مساعدة لمخاطبة سيرفر السائقين (Location Socket) ---
|
||||
function notifyDriversRideTaken($rideId, $winnerDriverId) {
|
||||
// رابط سيرفر السائقين الداخلي (نفس البورت المستخدم في driver_socket.php)
|
||||
$url = getenv('LOCATION_SOCKET_URL');
|
||||
if (!$url) throw new RuntimeException('LOCATION_SOCKET_URL not configured');
|
||||
$INTERNAL_KEY = trim(@file_get_contents('/home/intaleq-api/.internal_socket_key'));
|
||||
|
||||
$postData = [
|
||||
'action' => 'ride_taken_event', // هذا الأكشن الجديد في السوكيت
|
||||
'ride_id' => $rideId,
|
||||
'taken_by_driver_id' => $winnerDriverId
|
||||
];
|
||||
|
||||
$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);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 500); // نصف ثانية فقط، لا نريد تعطيل الـ API
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-internal-key: $INTERNAL_KEY"]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
}
|
||||
function notifyDriversOnLocationServer($drivers_ids_array, $payload, $rideId = null) {
|
||||
// رابط سيرفر اللوكيشن الخارجي
|
||||
$url = getenv('LOCATION_SOCKET_URL');
|
||||
if (!$url) throw new RuntimeException('LOCATION_SOCKET_URL not configured');
|
||||
$INTERNAL_KEY = trim(@file_get_contents('/home/intaleq-api/.internal_socket_key'));
|
||||
|
||||
$postData = [
|
||||
'action' => 'dispatch_order', // اسم الحدث المتفق عليه في socket_server.php هناك
|
||||
'drivers_ids' => json_encode($drivers_ids_array), // نحول المصفوفة لنص JSON
|
||||
'ride_id' => $rideId ?? '', // ✅ تصحيح اسم المتغير
|
||||
'payload' => $payload
|
||||
];
|
||||
|
||||
$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);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 1000); // لا تنتظر أكثر من ثانية
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
"x-internal-key: $INTERNAL_KEY"
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
|
||||
if (curl_errno($ch)) {
|
||||
error_log("Curl Error (Location Socket): " . curl_error($ch));
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 🚀 دالة إشعار الراكب (تعمل على سيرفر الرحلات)
|
||||
* تخاطب السوكيت الموجود محلياً على نفس السيرفر
|
||||
*/
|
||||
function notifyPassengerOnRideServer($passenger_id, $payload) {
|
||||
// الرابط المحلي لسيرفر سوكيت الركاب
|
||||
$url = getenv('PASSENGER_SOCKET_URL');
|
||||
if (!$url) {
|
||||
error_log("[FATAL] PASSENGER_SOCKET_URL not configured");
|
||||
throw new RuntimeException('PASSENGER_SOCKET_URL not configured');
|
||||
}
|
||||
$INTERNAL_KEY = trim(@file_get_contents('/home/intaleq-api/.internal_socket_key'));
|
||||
|
||||
$postData = [
|
||||
'action' => 'update_ride_status',
|
||||
'passenger_id' => $passenger_id,
|
||||
'payload' => $payload
|
||||
];
|
||||
|
||||
$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);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 1000);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
"x-internal-key: $INTERNAL_KEY"
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
|
||||
if (curl_errno($ch)) {
|
||||
error_log("Curl Error (Passenger Socket): " . curl_error($ch));
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
return $response;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// دالة توزيع الطلب (محدثة لاستخدام sendFCM_Internal)
|
||||
// ============================================================================
|
||||
// ============================================================================
|
||||
// دالة توزيع الطلب (Dispatch Function) - النسخة المصححة
|
||||
// ============================================================================
|
||||
function dispatchRideToDrivers($driversData, $rideId, $payloadTemplate, $startNameLoc, $encryptionHelper) {
|
||||
$countDrivers = count($driversData);
|
||||
error_log("🚀 [DISPATCH_START] RideID: $rideId | Drivers Count: $countDrivers");
|
||||
|
||||
$socketUrl = getenv('LOCATION_SOCKET_URL');
|
||||
if (!$socketUrl) throw new RuntimeException('LOCATION_SOCKET_URL not configured');
|
||||
|
||||
$internalKeyPath = '/home/intaleq-api/.internal_socket_key';
|
||||
$internalKey = file_exists($internalKeyPath) ? trim(file_get_contents($internalKeyPath)) : '';
|
||||
|
||||
foreach ($driversData as $driver) {
|
||||
$driverId = $driver['driver_id'];
|
||||
$rawToken = $driver['token'] ?? '';
|
||||
|
||||
error_log("--------------------------------------------------");
|
||||
error_log("👤 [DRIVER_PROCESS] Processing Driver ID: $driverId");
|
||||
|
||||
// 1. معالجة التوكن
|
||||
$driverToken = processDriverToken($rawToken, $encryptionHelper);
|
||||
|
||||
// تجهيز البيانات الخاصة بالسائق
|
||||
$payloadForDriver = $payloadTemplate;
|
||||
$payloadForDriver[6] = (string)$driverId;
|
||||
$payloadForDriver[18] = (string)$driverId;
|
||||
|
||||
// 2. إرسال السوكيت
|
||||
sendSocketNotification($driverId, $rideId, $payloadForDriver, $socketUrl, $internalKey);
|
||||
|
||||
// 3. إرسال FCM
|
||||
if (!empty($driverToken)) {
|
||||
$fcmData = [
|
||||
'DriverList' => $payloadForDriver,
|
||||
'order_id' => (string)$rideId
|
||||
];
|
||||
$fcmResult = sendFcmNotification(
|
||||
$driverToken,
|
||||
"طلب جديد 🔔",
|
||||
"هناك رحلة جديدة من " . $startNameLoc,
|
||||
$fcmData,
|
||||
"Order",
|
||||
"ding"
|
||||
);
|
||||
error_log("📲 [FCM_RESULT] " . json_encode($fcmResult));
|
||||
} else {
|
||||
error_log("⚠️ [FCM_SKIP] No valid token for Driver $driverId");
|
||||
}
|
||||
}
|
||||
error_log("🏁 [DISPATCH_END] RideID: $rideId");
|
||||
}
|
||||
|
||||
/**
|
||||
* معالجة توكن السائق وفك تشفيره
|
||||
*/
|
||||
function processDriverToken($rawToken, $encryptionHelper) {
|
||||
if (empty($rawToken)) {
|
||||
error_log("🚫 [TOKEN_MISSING] No token found.");
|
||||
return '';
|
||||
}
|
||||
try {
|
||||
$decrypted = $encryptionHelper->decryptData($rawToken);
|
||||
if ($decrypted !== false && !empty($decrypted)) {
|
||||
error_log("✅ [TOKEN_DECRYPT] Success.");
|
||||
return trim($decrypted);
|
||||
}
|
||||
error_log("⚠️ [TOKEN_DECRYPT] Failed. Using Raw.");
|
||||
return $rawToken;
|
||||
} catch (Exception $e) {
|
||||
error_log("❌ [TOKEN_EXCEPTION] Error. Using Raw.");
|
||||
return $rawToken;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* إرسال إشعار السوكيت لسيرفر اللوكيشن
|
||||
*/
|
||||
function sendSocketNotification($driverId, $rideId, $payload, $url, $internalKey) {
|
||||
$postData = [
|
||||
'action' => 'dispatch_order',
|
||||
'drivers_ids' => json_encode([$driverId]),
|
||||
'ride_id' => $rideId,
|
||||
'payload' => $payload
|
||||
];
|
||||
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
|
||||
if (!empty($internalKey)) curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-internal-key: $internalKey"]);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
|
||||
|
||||
$res = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
error_log("📡 [SOCKET_SEND] Driver $driverId | HTTP: $httpCode");
|
||||
}
|
||||
|
||||
/**
|
||||
* إرسال إشعار FCM الموحد
|
||||
*/
|
||||
function sendFcmNotification($token, $title, $body, $data, $category, $tone) {
|
||||
if (class_exists('FcmService')) {
|
||||
global $redis;
|
||||
$fcmService = new FcmService($redis ?? null);
|
||||
return $fcmService->send($token, $title, $body, $data, $category, $tone);
|
||||
} elseif (function_exists('sendFCM_Internal')) {
|
||||
return sendFCM_Internal($token, $title, $body, $data, $category, false, $tone);
|
||||
}
|
||||
return ['status' => 'error', 'message' => 'FCM service not loaded'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function authenticateJWT(): object
|
||||
{
|
||||
global $redis;
|
||||
if (!class_exists('JwtService')) {
|
||||
require_once __DIR__ . '/core/Auth/JwtService.php';
|
||||
}
|
||||
$jwtService = new JwtService($redis ?? null);
|
||||
return $jwtService->authenticate();
|
||||
}
|
||||
define("MB", 1048576);
|
||||
|
||||
/**
|
||||
* Send WhatsApp message using your server's API
|
||||
*
|
||||
* @param string $to The recipient phone number (e.g., 96279xxxxxxx)
|
||||
* @param string $message The message to send
|
||||
* @return mixed API response object or false on failure
|
||||
*/
|
||||
|
||||
function sendWhatsAppFromServer($to, $message)
|
||||
{
|
||||
// 1) قائمة السيرفرات المتاحة
|
||||
$servers = [
|
||||
//"https://botmasa.intaleq.xyz/send",//mayar
|
||||
// "https://botmasa2.intaleq.xyz/send",//shad
|
||||
"https://bot5.intaleq.xyz/send",//ramat bus
|
||||
"https://bot3.intaleq.xyz/send",//shahd
|
||||
//"https://whatsapp.tripz-egypt.com/send"//tripz
|
||||
];
|
||||
|
||||
// 2) محاولة الإرسال (Primary -> Fallback)
|
||||
$response = null;
|
||||
$success = false;
|
||||
|
||||
foreach ($servers as $url) {
|
||||
$curl = curl_init();
|
||||
curl_setopt_array($curl, [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 3, // مهلة قصيرة للمحاولة
|
||||
CURLOPT_CUSTOMREQUEST => "POST",
|
||||
CURLOPT_POSTFIELDS => json_encode([
|
||||
"to" => $to,
|
||||
"message" => $message
|
||||
], JSON_UNESCAPED_UNICODE),
|
||||
CURLOPT_HTTPHEADER => ["Content-Type: application/json"],
|
||||
]);
|
||||
|
||||
$response = curl_exec($curl);
|
||||
$err = curl_error($curl);
|
||||
curl_close($curl);
|
||||
|
||||
if (!$err) {
|
||||
$success = true;
|
||||
break;
|
||||
} else {
|
||||
error_log("[sendWhatsAppFromServer] Server $url failed, trying next... Error: $err");
|
||||
}
|
||||
}
|
||||
|
||||
if (!$success) return false;
|
||||
return json_decode($response, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function sendFCM_Internal(
|
||||
$target,
|
||||
$title,
|
||||
$body,
|
||||
$customData = [],
|
||||
$category = 'Order',
|
||||
$isTopic = false,
|
||||
$tone = 'order'
|
||||
) {
|
||||
global $redis;
|
||||
if (!class_exists('FcmService')) {
|
||||
require_once __DIR__ . '/core/Services/FcmService.php';
|
||||
}
|
||||
$fcm = new FcmService($redis ?? null);
|
||||
|
||||
return $fcm->send($target, $title, $body, is_array($customData) ? $customData : [], $category, $tone);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user