Update: 2026-06-29 23:09:43
This commit is contained in:
64
loction_server/siro/connect.php
Executable file
64
loction_server/siro/connect.php
Executable file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
// Load environment variables from .env file
|
||||
require_once realpath(__DIR__ . '/../vendor/autoload.php');
|
||||
require_once __DIR__ . '/load_env.php';
|
||||
|
||||
$env_file = file_exists(__DIR__ . '/../loction-keys/.env')
|
||||
? __DIR__ . '/../loction-keys/.env'
|
||||
: (file_exists('/home/location/env/.env') ? '/home/location/env/.env' : '');
|
||||
if (!empty($env_file)) {
|
||||
loadEnvironment($env_file);
|
||||
}
|
||||
|
||||
// Get environment variables (You don't need user/pass for JWT auth itself)
|
||||
$secretKeyFile = file_exists(__DIR__ . '/../loction-keys/.secret_key')
|
||||
? __DIR__ . '/../loction-keys/.secret_key'
|
||||
: '/home/location/.secret_key';
|
||||
$secretKey = trim((string) @file_get_contents($secretKeyFile));
|
||||
// Only need the secret key now
|
||||
// Debug loaded environment variables
|
||||
|
||||
// --- CORS Headers ---
|
||||
header("Access-Control-Allow-Origin: https://intaleqapp.com"); // Replace * with your Flutter app's origin
|
||||
header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); // Adjust as needed
|
||||
header("Access-Control-Allow-Headers: Content-Type, Authorization");
|
||||
header('Content-Type: application/json'); // Set content type to JSON
|
||||
|
||||
//SET time_zone = 'Asia/Damascus';
|
||||
date_default_timezone_set('Asia/Damascus');
|
||||
|
||||
// Handle preflight requests (OPTIONS)
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
|
||||
http_response_code(200);
|
||||
exit;
|
||||
}
|
||||
// $TRIPZ_SMTP_PASSWORD=getenv('TRIPZ_SMTP_PASSWORD');
|
||||
$dbname = getenv('dbname');
|
||||
// --- Database Connection (Still needed for your application logic) ---
|
||||
try {
|
||||
$dsn = "mysql:host=localhost;dbname=$dbname;charset=utf8mb4";
|
||||
$options = [
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES UTF8"
|
||||
];
|
||||
$user = getenv('USER'); // Still used for DB connection
|
||||
$pass = getenv('PASS'); // Still used for DB connection
|
||||
$con = new PDO($dsn, $user, $pass, $options);
|
||||
//$con->exec("SET time_zone = '+03:00'");
|
||||
// --- JWT Authentication ---
|
||||
// include "encrypt_decrypt.php";
|
||||
include "functions.php"; // Include the functions file
|
||||
|
||||
|
||||
$decodedToken = authenticateJWT(); // Call the authentication function
|
||||
|
||||
|
||||
} catch (PDOException $e) {
|
||||
error_log($e->getMessage());
|
||||
http_response_code(500); // Internal Server Error
|
||||
echo json_encode(['error' => 'A database error occurred.']);
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
468
loction_server/siro/functions.php
Executable file
468
loction_server/siro/functions.php
Executable file
@@ -0,0 +1,468 @@
|
||||
<?php
|
||||
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
use Firebase\JWT\ExpiredException;
|
||||
use Firebase\JWT\SignatureInvalidException;
|
||||
use Firebase\JWT\BeforeValidException;
|
||||
//functions.php for location server
|
||||
// --- JWT Authentication Function (Moved here for better organization) ---
|
||||
//include "encrypt_decrypt.php";
|
||||
|
||||
// --- 3. دالة توجيه الموقع لسيرفر الركاب ---
|
||||
function forwardLocationToPassengerSocket($passengerId, $payload) {
|
||||
if (empty($passengerId)) return;
|
||||
// نفترض أن سيرفر الركاب يعمل محلياً على 3031
|
||||
$url = "http://127.0.0.1:3031";
|
||||
$INTERNAL_KEY = trim(file_get_contents('/home/location/.internal_socket_key'));
|
||||
|
||||
$postData = [
|
||||
'action' => 'update_driver_location',
|
||||
'passenger_id' => $passengerId,
|
||||
'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, 100);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-internal-key: $INTERNAL_KEY"]);
|
||||
curl_exec($ch);
|
||||
curl_close($ch);
|
||||
}
|
||||
|
||||
// 2. استدعها داخل $socket->on('update_location'...)
|
||||
// يجب أن يرسل السائق passenger_id معه في الـ update_location أو تكون مخزنة في الـ session
|
||||
// $socket->on('update_location', function($data) use ($socket) {
|
||||
// ... كود الحفظ في الداتابيز ...
|
||||
//
|
||||
// if (!empty($data['passenger_id'])) {
|
||||
// forwardLocationToPassengerSocket($data['passenger_id'], $data);
|
||||
// }
|
||||
// });
|
||||
function authenticateJWT()
|
||||
{
|
||||
$secretKey = trim(file_get_contents('/home/location/.secret_key')); // Access secret key (ensure it's set in .env)
|
||||
if (!$secretKey) {
|
||||
error_log("SECRET_KEY not set in environment variables.");
|
||||
http_response_code(500); // Internal Server Error
|
||||
echo json_encode(['error' => 'Internal server configuration error.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
// 1. Get the JWT from the Authorization header
|
||||
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
|
||||
$token = null;
|
||||
|
||||
if (preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) {
|
||||
$token = $matches[1];
|
||||
}
|
||||
|
||||
// 2. Check if the token exists
|
||||
if (!$token) {
|
||||
http_response_code(401); // Unauthorized
|
||||
echo json_encode(['error' => 'Authorization token required']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 3. Verify the JWT
|
||||
try {
|
||||
$decoded = JWT::decode($token, new Key($secretKey, 'HS256'));
|
||||
|
||||
/* // 4. Validate claims (audience, issuer)
|
||||
$decrypted_aud = $encryptionHelper->decryptData($decoded->aud);
|
||||
$allowedAudiences = [getenv('allowed1'), getenv('allowed2'),getenv('allowedDriver1'),getenv('allowedDriver2'),
|
||||
getenv('allowedService1'), getenv('allowedService2') ]; // "passenger", "driver"
|
||||
|
||||
if (!in_array($decrypted_aud, $allowedAudiences)) {
|
||||
throw new Exception('Invalid audience');
|
||||
error_log("[Debug] 'Invalid audience'");
|
||||
}
|
||||
|
||||
$decrypted_iss = $encryptionHelper->decryptData($decoded->iss ?? '');
|
||||
if ($decrypted_iss !== 'Tripz') {
|
||||
throw new Exception('Invalid issuer');
|
||||
error_log("[Debug] 'Invalid issuer'");
|
||||
}
|
||||
*/
|
||||
// 5. Authentication successful!
|
||||
return $decoded; // Return the decoded payload
|
||||
|
||||
} catch (ExpiredException $e) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Token expired']);
|
||||
exit;
|
||||
} catch (SignatureInvalidException $e) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Invalid token signature']);
|
||||
exit;
|
||||
} catch (BeforeValidException $e) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Token not yet valid']);
|
||||
exit;
|
||||
} catch (Exception $e) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Invalid token: ' . $e->getMessage()]);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
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://whatsapp.intaleq.xyz/send"
|
||||
//,
|
||||
//"https://bot3.intaleq.xyz/send"
|
||||
];
|
||||
|
||||
// 2) اختيار عشوائي
|
||||
$url = $servers[array_rand($servers)];
|
||||
|
||||
// 3) إعداد البيانات
|
||||
$payload = [
|
||||
"to" => $to,
|
||||
"message" => $message
|
||||
];
|
||||
|
||||
// 4) تنفيذ الطلب
|
||||
$curl = curl_init();
|
||||
curl_setopt_array($curl, [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_CUSTOMREQUEST => "POST",
|
||||
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
|
||||
CURLOPT_HTTPHEADER => [
|
||||
"Content-Type: application/json"
|
||||
],
|
||||
]);
|
||||
|
||||
$response = curl_exec($curl);
|
||||
$err = curl_error($curl);
|
||||
curl_close($curl);
|
||||
|
||||
// 5) تسجيل النتيجة
|
||||
if ($err) {
|
||||
error_log("[sendWhatsAppFromServer] cURL Error on $url: $err");
|
||||
return false;
|
||||
}
|
||||
|
||||
return json_decode($response, true);
|
||||
}
|
||||
|
||||
function debugLog($message) {
|
||||
error_log($message);
|
||||
}
|
||||
|
||||
function filterRequest($requestname, $type = 'string') {
|
||||
if (isset($_POST[$requestname]) && !empty($_POST[$requestname])) {
|
||||
$value = trim($_POST[$requestname]);
|
||||
// Remove any control characters
|
||||
$value = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $value);
|
||||
// Remove any HTML or XML tags
|
||||
$value = strip_tags($value);
|
||||
// Escape any special characters
|
||||
$value = htmlspecialchars($value, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||
|
||||
if ($type === 'numeric') {
|
||||
if (filter_var($value, FILTER_VALIDATE_FLOAT) !== false) {
|
||||
return $value;
|
||||
}
|
||||
} else {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
function getAllData($table, $where = null, $values = null, $json = true)
|
||||
{
|
||||
global $con;
|
||||
$data = array();
|
||||
if ($where == null) {
|
||||
$stmt = $con->prepare("SELECT * FROM $table ");
|
||||
} else {
|
||||
$stmt = $con->prepare("SELECT * FROM $table WHERE $where ");
|
||||
}
|
||||
$stmt->execute($values);
|
||||
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$count = $stmt->rowCount();
|
||||
if ($json == true) {
|
||||
if ($count > 0) {
|
||||
echo json_encode(array("status" => "success","count" => $count, "data" => $data));
|
||||
} else {
|
||||
echo json_encode(array("status" => "failure"));
|
||||
}
|
||||
return $count;
|
||||
} else {
|
||||
if ($count > 0) {
|
||||
return $data;
|
||||
} else {
|
||||
return json_encode(array("status" => "failure"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getData($table, $where = null, $values = null)
|
||||
{
|
||||
global $con;
|
||||
$data = array();
|
||||
$stmt = $con->prepare("SELECT * FROM $table WHERE $where ");
|
||||
$stmt->execute($values);
|
||||
$data = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$count = $stmt->rowCount();
|
||||
if ($count > 0) {
|
||||
echo json_encode(array("status" => "success", "count" => $count, "data" => $data));
|
||||
} else {
|
||||
echo json_encode(array("status" => "failure"));
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function insertData($table, $data, $json = true)
|
||||
{
|
||||
global $con;
|
||||
foreach ($data as $field => $v)
|
||||
$ins[] = ':' . $field;
|
||||
$ins = implode(',', $ins);
|
||||
$fields = implode(',', array_keys($data));
|
||||
$sql = "INSERT INTO $table ($fields) VALUES ($ins)";
|
||||
|
||||
$stmt = $con->prepare($sql);
|
||||
foreach ($data as $f => $v) {
|
||||
$stmt->bindValue(':' . $f, $v);
|
||||
}
|
||||
$stmt->execute();
|
||||
$count = $stmt->rowCount();
|
||||
if ($json == true) {
|
||||
if ($count > 0) {
|
||||
echo json_encode(array("status" => "success"));
|
||||
} else {
|
||||
echo json_encode(array("status" => "failure"));
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
|
||||
function updateData($table, $data, $where, $json = true)
|
||||
{
|
||||
global $con;
|
||||
$cols = array();
|
||||
$vals = array();
|
||||
|
||||
foreach ($data as $key => $val) {
|
||||
$vals[] = "$val";
|
||||
$cols[] = "`$key` = ? ";
|
||||
}
|
||||
$sql = "UPDATE $table SET " . implode(', ', $cols) . " WHERE $where";
|
||||
|
||||
$stmt = $con->prepare($sql);
|
||||
$stmt->execute($vals);
|
||||
$count = $stmt->rowCount();
|
||||
if ($json == true) {
|
||||
if ($count > 0) {
|
||||
echo json_encode(array("status" => "success"));
|
||||
} else {
|
||||
echo json_encode(array("status" => "failure"));
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
function deleteData($table, $where, $json = true)
|
||||
{
|
||||
global $con;
|
||||
$stmt = $con->prepare("DELETE FROM $table WHERE $where");
|
||||
$stmt->execute();
|
||||
$count = $stmt->rowCount();
|
||||
if ($json == true) {
|
||||
if ($count > 0) {
|
||||
echo json_encode(array("status" => "success"));
|
||||
} else {
|
||||
echo json_encode(array("status" => "failure"));
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
function imageUpload($imageRequest)
|
||||
{
|
||||
global $msgError;
|
||||
$imagename = rand(1000, 10000) . $_FILES[$imageRequest]['name'];
|
||||
$imagetmp = $_FILES[$imageRequest]['tmp_name'];
|
||||
$imagesize = $_FILES[$imageRequest]['size'];
|
||||
$allowExt = array("jpg", "png", "gif", "mp3", "pdf");
|
||||
$strToArray = explode(".", $imagename);
|
||||
$ext = end($strToArray);
|
||||
$ext = strtolower($ext);
|
||||
|
||||
if (!empty($imagename) && !in_array($ext, $allowExt)) {
|
||||
$msgError = "EXT";
|
||||
}
|
||||
if ($imagesize > 2 * MB) {
|
||||
$msgError = "size";
|
||||
}
|
||||
if (empty($msgError)) {
|
||||
move_uploaded_file($imagetmp, "../upload/" . $imagename);
|
||||
return $imagename;
|
||||
} else {
|
||||
return "fail";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function deleteFile($dir, $imagename)
|
||||
{
|
||||
if (file_exists($dir . "/" . $imagename)) {
|
||||
unlink($dir . "/" . $imagename);
|
||||
}
|
||||
}
|
||||
|
||||
// function checkAuthenticate()
|
||||
// {
|
||||
// if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
|
||||
// if ($_SERVER['PHP_AUTH_USER'] != "hamzaayedphp" || $_SERVER['PHP_AUTH_PW'] != "malDEV@2101") {
|
||||
// header('WWW-Authenticate: Basic realm="My Realm"');
|
||||
// header('HTTP/1.0 401 Unauthorized');
|
||||
// echo 'Unauthorized';
|
||||
// exit;
|
||||
// }
|
||||
// } else {
|
||||
// exit;
|
||||
// }
|
||||
|
||||
// // End
|
||||
// }
|
||||
|
||||
|
||||
function checkAuthenticate($username, $password)
|
||||
{
|
||||
if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] !== 'on') {
|
||||
// Redirect to HTTPS
|
||||
header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
|
||||
if ($_SERVER['PHP_AUTH_USER'] !== $username || $_SERVER['PHP_AUTH_PW'] !== $password) {
|
||||
header('WWW-Authenticate: Basic realm="My Realm"');
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
echo 'Unauthorized';
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
header('WWW-Authenticate: Basic realm="My Realm"');
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
echo 'Unauthorized';
|
||||
exit;
|
||||
}
|
||||
|
||||
// Continue with authenticated code
|
||||
}
|
||||
// function checkAuthenticate()
|
||||
// {
|
||||
// global $secretKey;
|
||||
|
||||
// if (!isset($_SERVER['HTTP_AUTHORIZATION'])) {
|
||||
// header('HTTP/1.0 401 Unauthorized');
|
||||
// echo json_encode(['error' => 'Unauthorized']);
|
||||
// exit;
|
||||
// }
|
||||
|
||||
// $authHeader = $_SERVER['HTTP_AUTHORIZATION'];
|
||||
// list($token) = sscanf($authHeader, 'Bearer %s');
|
||||
|
||||
// if (!$token) {
|
||||
// header('HTTP/1.0 401 Unauthorized');
|
||||
// echo json_encode(['error' => 'Token not provided']);
|
||||
// exit;
|
||||
// }
|
||||
|
||||
// try {
|
||||
// $decoded = JWT::decode($token, new Key($secretKey, 'HS256'));
|
||||
// return $decoded;
|
||||
// } catch (Exception $e) {
|
||||
// header('HTTP/1.0 401 Unauthorized');
|
||||
// echo json_encode(['error' => 'Invalid token']);
|
||||
// exit;
|
||||
// }
|
||||
// }
|
||||
|
||||
function divideAndAddText($apiKey, $text) {
|
||||
$parts = str_split($apiKey, strlen($apiKey) / 4);
|
||||
|
||||
$dividedApiKey = array();
|
||||
$dividedApiKey['birinci'] = $parts[4] . $text;
|
||||
$dividedApiKey['ikinci'] = $text . $parts[2] . $text;
|
||||
$dividedApiKey['üçüncü'] = $text . $parts[1] . $text;
|
||||
$dividedApiKey['dördüncü'] = $parts[0] . $text;
|
||||
$dividedApiKey['beş'] = $text . $parts[3] . $text;
|
||||
|
||||
$concatenatedApiKey = implode('', $dividedApiKey);
|
||||
|
||||
return $concatenatedApiKey;
|
||||
}
|
||||
|
||||
function retrieveOriginalApiKey($concatenatedApiKey, $text) {
|
||||
$originalApiKey = str_replace($text, '', $concatenatedApiKey);
|
||||
|
||||
$resortedApiKey = array();
|
||||
$resortedApiKey['birinci'] = $originalApiKey[strlen($originalApiKey) - 5] . $originalApiKey[strlen($originalApiKey) - 3];
|
||||
$resortedApiKey['ikinci'] = $originalApiKey[strlen($originalApiKey) - 1] . $originalApiKey[strlen($originalApiKey) - 15];
|
||||
$resortedApiKey['üçüncü'] = $originalApiKey[strlen($originalApiKey) - 9] . $originalApiKey[strlen($originalApiKey) - 12];
|
||||
$resortedApiKey['dördüncü'] = $originalApiKey[strlen($originalApiKey) - 11] . $originalApiKey[strlen($originalApiKey) - 6];
|
||||
$resortedApiKey['beş'] = $originalApiKey[strlen($originalApiKey) - 2] . $originalApiKey[strlen($originalApiKey) - 8];
|
||||
|
||||
return $resortedApiKey;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////
|
||||
|
||||
function printFailure($message = "none")
|
||||
{
|
||||
echo json_encode(array("status" => "failure", "message" => $message));
|
||||
}
|
||||
function printSuccess($message = "none")
|
||||
{
|
||||
echo json_encode(array("status" => "success", "message" => $message));
|
||||
}
|
||||
|
||||
function result($count)
|
||||
{
|
||||
if ($count > 0) {
|
||||
printSuccess();
|
||||
} else {
|
||||
printFailure();
|
||||
}
|
||||
}
|
||||
|
||||
function sendEmail($from,$to, $title, $body)
|
||||
{
|
||||
$header = "From: $from" . "\n" . "CC: $from";
|
||||
mail($to, $title, $body, $header);
|
||||
}
|
||||
64
loction_server/siro/jwtconnect.php
Executable file
64
loction_server/siro/jwtconnect.php
Executable file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
// Load environment variables from .env file
|
||||
require_once realpath(__DIR__ . '/../vendor/autoload.php');
|
||||
require_once __DIR__ . '/load_env.php';
|
||||
|
||||
$env_file = file_exists(__DIR__ . '/../loction-keys/.env')
|
||||
? __DIR__ . '/../loction-keys/.env'
|
||||
: (file_exists('/home/location/env/.env') ? '/home/location/env/.env' : '');
|
||||
if (!empty($env_file)) {
|
||||
loadEnvironment($env_file);
|
||||
}
|
||||
|
||||
// Get environment variables (You don't need user/pass for JWT auth itself)
|
||||
$secretKeyFile = file_exists(__DIR__ . '/../loction-keys/.secret_key')
|
||||
? __DIR__ . '/../loction-keys/.secret_key'
|
||||
: '/home/location/.secret_key';
|
||||
$secretKey = trim((string) @file_get_contents($secretKeyFile));
|
||||
// Only need the secret key now
|
||||
// Debug loaded environment variables
|
||||
|
||||
// --- CORS Headers ---
|
||||
header("Access-Control-Allow-Origin: https://intaleqapp.com"); // Replace * with your Flutter app's origin
|
||||
header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); // Adjust as needed
|
||||
header("Access-Control-Allow-Headers: Content-Type, Authorization");
|
||||
header('Content-Type: application/json'); // Set content type to JSON
|
||||
|
||||
//SET time_zone = 'Asia/Damascus';
|
||||
date_default_timezone_set('Asia/Damascus');
|
||||
|
||||
// Handle preflight requests (OPTIONS)
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
|
||||
http_response_code(200);
|
||||
exit;
|
||||
}
|
||||
// $TRIPZ_SMTP_PASSWORD=getenv('TRIPZ_SMTP_PASSWORD');
|
||||
$dbname = getenv('dbname');
|
||||
// --- Database Connection (Still needed for your application logic) ---
|
||||
try {
|
||||
$dsn = "mysql:host=localhost;dbname=$dbname;charset=utf8mb4";
|
||||
$options = [
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES UTF8"
|
||||
];
|
||||
$user = getenv('USER'); // Still used for DB connection
|
||||
$pass = getenv('PASS'); // Still used for DB connection
|
||||
$con = new PDO($dsn, $user, $pass, $options);
|
||||
//$con->exec("SET time_zone = '+03:00'");
|
||||
// --- JWT Authentication ---
|
||||
// include "encrypt_decrypt.php";
|
||||
include "functions.php"; // Include the functions file
|
||||
|
||||
|
||||
// $decodedToken = authenticateJWT(); // Call the authentication function
|
||||
|
||||
|
||||
} catch (PDOException $e) {
|
||||
error_log($e->getMessage());
|
||||
http_response_code(500); // Internal Server Error
|
||||
echo json_encode(['error' => 'A database error occurred.']);
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
23
loction_server/siro/load_env.php
Executable file
23
loction_server/siro/load_env.php
Executable file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
function loadEnvironment($env_file) {
|
||||
if (!file_exists($env_file)) {
|
||||
error_log("❌ .env not found: $env_file");
|
||||
return false;
|
||||
}
|
||||
|
||||
$lines = file($env_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
foreach ($lines as $line) {
|
||||
$line = trim($line);
|
||||
if (empty($line) || strpos($line, '#') === 0) continue;
|
||||
$parts = explode('=', $line, 2);
|
||||
if (count($parts) === 2) {
|
||||
[$keyName, $value] = $parts;
|
||||
$value = trim($value, "\"'");
|
||||
putenv("$keyName=$value");
|
||||
$_ENV[$keyName] = $value;
|
||||
$_SERVER[$keyName] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
190
loction_server/siro/ride/driversLocation.html
Executable file
190
loction_server/siro/ride/driversLocation.html
Executable file
@@ -0,0 +1,190 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>تتبع السائقين - Tripz</title>
|
||||
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
||||
|
||||
<style>
|
||||
body { margin: 0; padding: 0; font-family: 'Segoe UI', Tahoma, sans-serif; overflow: hidden; }
|
||||
#map { height: 100vh; width: 100%; z-index: 1; }
|
||||
|
||||
/* تصميم لوحة التحكم */
|
||||
.dashboard {
|
||||
position: absolute; top: 20px; right: 20px; width: 280px;
|
||||
background: rgba(255, 255, 255, 0.95); padding: 15px;
|
||||
border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.15);
|
||||
z-index: 1000; text-align: right; border: 1px solid #ddd;
|
||||
}
|
||||
.dashboard h2 { margin: 0 0 10px 0; font-size: 16px; color: #333; border-bottom: 2px solid #3498db; padding-bottom: 8px; }
|
||||
|
||||
/* أزرار التبديل */
|
||||
.mode-switcher { display: flex; gap: 5px; margin-bottom: 15px; }
|
||||
.mode-btn {
|
||||
flex: 1; padding: 8px; border: 1px solid #3498db; background: white;
|
||||
color: #3498db; cursor: pointer; border-radius: 4px; font-size: 12px; transition: 0.2s;
|
||||
}
|
||||
.mode-btn.active { background: #3498db; color: white; font-weight: bold; }
|
||||
|
||||
/* الإحصائيات */
|
||||
.info-row { display: flex; justify-content: space-between; margin-bottom: 5px; font-size: 13px; }
|
||||
.val-active { color: #27ae60; font-weight: bold; }
|
||||
.update-time { font-size: 11px; color: #7f8c8d; text-align: center; margin-top: 10px; display: block; }
|
||||
|
||||
/* زر التحديث */
|
||||
.refresh-btn {
|
||||
width: 100%; margin-top: 8px; padding: 8px; background: #2c3e50;
|
||||
color: white; border: none; border-radius: 4px; cursor: pointer;
|
||||
}
|
||||
.refresh-btn:hover { background: #34495e; }
|
||||
|
||||
/* أيقونة السيارة */
|
||||
.car-wrapper { transition: transform 0.5s ease; }
|
||||
.car-svg { width: 35px; height: 35px; filter: drop-shadow(0px 2px 2px rgba(0,0,0,0.3)); }
|
||||
|
||||
/* Popup */
|
||||
.popup-content { text-align: right; font-size: 12px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="map"></div>
|
||||
|
||||
<div class="dashboard">
|
||||
<h2>نظام التتبع المباشر</h2>
|
||||
|
||||
<div class="mode-switcher">
|
||||
<button class="mode-btn active" id="btnLive" onclick="setMode('live')">مباشر (20د)</button>
|
||||
<button class="mode-btn" id="btnDay" onclick="setMode('day')">اليوم كامل</button>
|
||||
</div>
|
||||
|
||||
<div class="info-row">
|
||||
<span>الوضع:</span>
|
||||
<span id="modeLabel" style="font-weight:bold; color:#2980b9;">مباشر</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span>السائقين:</span>
|
||||
<span id="countVal" class="val-active">0</span>
|
||||
</div>
|
||||
|
||||
<small id="statusMsg" class="update-time">جاري التحميل...</small>
|
||||
<button class="refresh-btn" onclick="fetchData()">تحديث البيانات</button>
|
||||
</div>
|
||||
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
|
||||
<script>
|
||||
// ================= إعدادات النظام =================
|
||||
const BASE_URL = "https://location.intaleq.xyz/intaleq/ride/";
|
||||
let currentMode = 'live';
|
||||
|
||||
// إعداد الخريطة
|
||||
const map = L.map('map').setView([33.513, 36.276], 10);
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution: 'Tripz System'
|
||||
}).addTo(map);
|
||||
|
||||
const markersGroup = L.layerGroup().addTo(map);
|
||||
|
||||
// ================= دوال التحكم =================
|
||||
function setMode(mode) {
|
||||
currentMode = mode;
|
||||
// تحديث الأزرار
|
||||
document.getElementById('btnLive').className = mode === 'live' ? 'mode-btn active' : 'mode-btn';
|
||||
document.getElementById('btnDay').className = mode === 'day' ? 'mode-btn active' : 'mode-btn';
|
||||
|
||||
// تحديث البيانات
|
||||
fetchData();
|
||||
}
|
||||
|
||||
function fetchData() {
|
||||
const statusElem = document.getElementById('statusMsg');
|
||||
statusElem.innerText = "جاري الاتصال بالسيرفر...";
|
||||
statusElem.style.color = "#7f8c8d";
|
||||
|
||||
// تحديد اسم الملف
|
||||
const fileName = currentMode === 'day' ? 'locations_day.json' : 'locations_live.json';
|
||||
const finalUrl = BASE_URL + fileName + '?t=' + Date.now(); // Cache busting
|
||||
|
||||
fetch(finalUrl)
|
||||
.then(response => {
|
||||
// التحقق من أن الملف موجود
|
||||
if (!response.ok) {
|
||||
throw new Error("الملف غير موجود (404)");
|
||||
}
|
||||
// التحقق من نوع المحتوى (لتجنب Hello World)
|
||||
const contentType = response.headers.get("content-type");
|
||||
if (contentType && contentType.indexOf("application/json") === -1) {
|
||||
throw new Error("البيانات ليست JSON (الرجاء تشغيل ملف PHP أولاً)");
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
renderMap(data);
|
||||
statusElem.innerText = "آخر تحديث: " + (data.last_updated || "الآن");
|
||||
})
|
||||
.catch(err => {
|
||||
console.error("Error:", err);
|
||||
statusElem.innerText = "خطأ: " + err.message;
|
||||
statusElem.style.color = "#e74c3c";
|
||||
// لا نمسح الخريطة عند الخطأ للحفاظ على آخر عرض
|
||||
});
|
||||
}
|
||||
|
||||
function renderMap(json) {
|
||||
markersGroup.clearLayers();
|
||||
const drivers = json.drivers || [];
|
||||
|
||||
document.getElementById('countVal').innerText = json.count || drivers.length;
|
||||
document.getElementById('modeLabel').innerText = json.title || (currentMode=='day'?'يومي':'مباشر');
|
||||
|
||||
let bounds = [];
|
||||
|
||||
drivers.forEach(d => {
|
||||
// البحث الذكي عن الإحداثيات
|
||||
let lat = parseFloat(d.lat || d.latitude || d.Lat || d.LAT);
|
||||
let lon = parseFloat(d.lon || d.lng || d.longitude || d.long || d.Lon || d.LNG);
|
||||
|
||||
if (!isNaN(lat) && !isNaN(lon) && lat !== 0 && lon !== 0) {
|
||||
bounds.push([lat, lon]);
|
||||
|
||||
const color = currentMode === 'live' ? '#27ae60' : '#2980b9'; // أخضر للمباشر، أزرق لليومي
|
||||
const heading = d.heading || 0;
|
||||
|
||||
const iconHtml = `
|
||||
<div class="car-wrapper" style="transform: rotate(${heading}deg);">
|
||||
<svg class="car-svg" viewBox="0 0 24 24" fill="${color}">
|
||||
<path d="M18.92 6.01C18.72 5.42 18.16 5 17.5 5h-11c-.66 0-1.21.42-1.42 1.01L3 12v8c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-1h12v1c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-8l-2.08-5.99zM6.5 16c-.83 0-1.5-.67-1.5-1.5S5.67 13 6.5 13s1.5.67 1.5 1.5S7.33 16 6.5 16zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM5 11l1.5-4.5h11L19 11H5z"/>
|
||||
</svg>
|
||||
</div>`;
|
||||
|
||||
const icon = L.divIcon({ className: '', html: iconHtml, iconSize: [35, 35], iconAnchor: [17.5, 17.5] });
|
||||
|
||||
L.marker([lat, lon], {icon: icon})
|
||||
.bindPopup(`
|
||||
<div class="popup-content">
|
||||
<strong>ID:</strong> ${d.driver_id || d.id}<br>
|
||||
<strong>السرعة:</strong> ${d.speed || 0}<br>
|
||||
<strong>الوقت:</strong> ${d.updated_at}
|
||||
</div>
|
||||
`)
|
||||
.addTo(markersGroup);
|
||||
}
|
||||
});
|
||||
|
||||
// توجيه الكاميرا تلقائياً (Auto Zoom)
|
||||
if (bounds.length > 0) {
|
||||
map.fitBounds(bounds, { padding: [50, 50] });
|
||||
}
|
||||
}
|
||||
|
||||
// بدء التشغيل
|
||||
fetchData();
|
||||
// تحديث تلقائي كل 15 ثانية
|
||||
setInterval(fetchData, 15000);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
160
loction_server/siro/ride/heatmap.html
Executable file
160
loction_server/siro/ride/heatmap.html
Executable file
@@ -0,0 +1,160 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>خريطة الكثافة الحرارية (Grid Heatmap) - OpenStreetMap</title>
|
||||
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
|
||||
<style>
|
||||
body { margin: 0; padding: 0; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
|
||||
#map { height: 100vh; width: 100%; }
|
||||
.info-box {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
z-index: 1000;
|
||||
background: white;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,0.2);
|
||||
max-width: 300px;
|
||||
}
|
||||
.legend {
|
||||
margin-top: 10px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.legend i {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
float: right;
|
||||
margin-left: 8px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="info-box">
|
||||
<h3>تحليل كثافة الرحلات</h3>
|
||||
<p>هذه الخريطة تقسم المنطقة إلى مربعات جغرافية وتحسب عدد الرحلات في كل مربع.</p>
|
||||
<div class="legend">
|
||||
<div><i style="background: #bd0026"></i> طلبات عالية جداً (+5)</div>
|
||||
<div><i style="background: #f03b20"></i> طلبات عالية (3-4)</div>
|
||||
<div><i style="background: #fd8d3c"></i> طلبات متوسطة (2)</div>
|
||||
<div><i style="background: #feb24c"></i> طلب واحد (1)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="map"></div>
|
||||
|
||||
<script>
|
||||
// 1. تهيئة الخريطة (مركزها دمشق مبدئياً)
|
||||
var map = L.map('map').setView([33.513, 36.276], 13);
|
||||
|
||||
// 2. إضافة طبقة OpenStreetMap
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
}).addTo(map);
|
||||
|
||||
// 3. البيانات المستخرجة من ملفك (ride.json)
|
||||
// ملاحظة: قمت بوضع البيانات هنا لمحاكاتها، في الواقع سيقوم السكربت بطلبها من ملف heatmap.json
|
||||
var rawData = [
|
||||
{"type":"header","version":"5.2.2","comment":"Export to JSON plugin for PHPMyAdmin"},
|
||||
{"type":"database","name":"intaleq-ridesDB"},
|
||||
{"type":"table","name":"ride","database":"intaleq-ridesDB","data": [
|
||||
// ... تم نسخ عينة من بياناتك هنا لتعمل الصفحة ...
|
||||
{"start_location":"33.4323,36.2432"}, {"start_location":"34.68947,36.36329"},
|
||||
{"start_location":"33.5445,36.30571"}, {"start_location":"33.4323,36.24326"},
|
||||
{"start_location":"33.43222,36.24319"}, {"start_location":"33.51326,36.27646"},
|
||||
{"start_location":"33.50895,36.29209"}, {"start_location":"33.49631,36.3221"},
|
||||
{"start_location":"33.55463,36.32338"}, {"start_location":"33.53447,36.29727"},
|
||||
{"start_location":"33.5727,36.192"}, {"start_location":"33.52811,36.37998"},
|
||||
{"start_location":"33.54115,36.21846"}, {"start_location":"33.4323,36.24309"},
|
||||
{"start_location":"33.50312,36.25959"}, {"start_location":"33.52518,36.35682"},
|
||||
{"start_location":"33.51814,36.3119"}, {"start_location":"33.50142,36.27113"},
|
||||
{"start_location":"33.49593,36.30942"}, {"start_location":"33.55189,36.32245"},
|
||||
{"start_location":"33.5322,36.29513"}, {"start_location":"33.53994,36.22878"},
|
||||
{"start_location":"33.52441,36.28758"}, {"start_location":"33.46744,36.19679"},
|
||||
{"start_location":"33.52842,36.23082"}, {"start_location":"33.50236,36.27406"},
|
||||
{"start_location":"33.4323,36.24331"}, {"start_location":"33.51246,36.29807"}
|
||||
// (ملاحظة: البيانات هنا هي عينة لتعمل الصفحة، يمكنك استبدالها ببياناتك الكاملة)
|
||||
]}
|
||||
];
|
||||
|
||||
// في حال أردت استخدام بياناتك الكاملة، الصق محتوى المصفوفة "data" من ملفك داخل المتغير أدناه
|
||||
// سأقوم الآن باستخراج البيانات من الهيكل المعقد الذي أرسلته
|
||||
var rides = rawData[2].data;
|
||||
|
||||
// 4. خوارزمية الشبكة (Grid Algorithm)
|
||||
var grid = {};
|
||||
var precision = 0.005; // حجم المربع (تقريباً 500 متر). صغّر الرقم لـ 0.002 لدقة أعلى
|
||||
|
||||
rides.forEach(function(ride) {
|
||||
if(ride.start_location) {
|
||||
var coords = ride.start_location.split(',');
|
||||
var lat = parseFloat(coords[0]);
|
||||
var lng = parseFloat(coords[1]);
|
||||
|
||||
// استثناء القيم الصفرية أو البعيدة جداً
|
||||
if(lat > 32 && lat < 38 && lng > 35 && lng < 39) {
|
||||
|
||||
// حساب مفتاح الشبكة (تقريب الإحداثيات)
|
||||
// Math.floor(lat / precision) * precision -> يقوم بتوحيد الأرقام القريبة
|
||||
var gridLat = Math.floor(lat / precision) * precision;
|
||||
var gridLng = Math.floor(lng / precision) * precision;
|
||||
var key = gridLat.toFixed(3) + "_" + gridLng.toFixed(3);
|
||||
|
||||
if(!grid[key]) {
|
||||
grid[key] = {
|
||||
lat: gridLat,
|
||||
lng: gridLng,
|
||||
count: 0
|
||||
};
|
||||
}
|
||||
grid[key].count++;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 5. دالة تحديد اللون بناءً على العدد
|
||||
function getColor(d) {
|
||||
return d > 5 ? '#bd0026' : // أحمر داكن (حار جداً)
|
||||
d > 3 ? '#f03b20' : // أحمر
|
||||
d > 1 ? '#fd8d3c' : // برتقالي
|
||||
'#feb24c'; // أصفر (بارد)
|
||||
}
|
||||
|
||||
// 6. رسم المربعات على الخريطة
|
||||
var bounds = []; // لتحديد حدود الخريطة النهائية
|
||||
|
||||
for (var key in grid) {
|
||||
var zone = grid[key];
|
||||
|
||||
// تحديد زوايا المربع
|
||||
var southWest = [zone.lat, zone.lng];
|
||||
var northEast = [zone.lat + precision, zone.lng + precision];
|
||||
var zoneBounds = [southWest, northEast];
|
||||
|
||||
// رسم المستطيل
|
||||
L.rectangle(zoneBounds, {
|
||||
color: getColor(zone.count),
|
||||
weight: 1,
|
||||
fillOpacity: 0.6
|
||||
}).bindPopup("<b>عدد الرحلات:</b> " + zone.count)
|
||||
.addTo(map);
|
||||
|
||||
bounds.push(southWest);
|
||||
bounds.push(northEast);
|
||||
}
|
||||
|
||||
// 7. تحريك الكاميرا لتشمل كل النقاط
|
||||
if(bounds.length > 0) {
|
||||
map.fitBounds(bounds);
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
80
loction_server/siro/ride/location/add.php
Executable file
80
loction_server/siro/ride/location/add.php
Executable 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");
|
||||
}
|
||||
?>
|
||||
129
loction_server/siro/ride/location/add_batch.php
Executable file
129
loction_server/siro/ride/location/add_batch.php
Executable 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");
|
||||
}
|
||||
?>
|
||||
34
loction_server/siro/ride/location/addpassengerLocation.php
Executable file
34
loction_server/siro/ride/location/addpassengerLocation.php
Executable 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");
|
||||
}
|
||||
?>
|
||||
20
loction_server/siro/ride/location/delete.php
Normal file
20
loction_server/siro/ride/location/delete.php
Normal 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");
|
||||
}
|
||||
|
||||
?>
|
||||
146
loction_server/siro/ride/location/get.php
Executable file
146
loction_server/siro/ride/location/get.php
Executable 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());
|
||||
}
|
||||
120
loction_server/siro/ride/location/getBalash.php
Executable file
120
loction_server/siro/ride/location/getBalash.php
Executable 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());
|
||||
}
|
||||
124
loction_server/siro/ride/location/getComfort.php
Executable file
124
loction_server/siro/ride/location/getComfort.php
Executable 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());
|
||||
}
|
||||
125
loction_server/siro/ride/location/getDelivery.php
Executable file
125
loction_server/siro/ride/location/getDelivery.php
Executable 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());
|
||||
}
|
||||
70
loction_server/siro/ride/location/getDrirversLocationsTrack.php
Executable file
70
loction_server/siro/ride/location/getDrirversLocationsTrack.php
Executable 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()
|
||||
]);
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
?>
|
||||
126
loction_server/siro/ride/location/getElectric.php
Executable file
126
loction_server/siro/ride/location/getElectric.php
Executable 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());
|
||||
}
|
||||
111
loction_server/siro/ride/location/getFemalDriver.php
Executable file
111
loction_server/siro/ride/location/getFemalDriver.php
Executable 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());
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
?>
|
||||
42
loction_server/siro/ride/location/getLocationParents.php
Normal file
42
loction_server/siro/ride/location/getLocationParents.php
Normal 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");
|
||||
}
|
||||
|
||||
?>
|
||||
112
loction_server/siro/ride/location/getPinkBike.php
Executable file
112
loction_server/siro/ride/location/getPinkBike.php
Executable 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());
|
||||
}
|
||||
66
loction_server/siro/ride/location/getRidesDriverByDay.php
Executable file
66
loction_server/siro/ride/location/getRidesDriverByDay.php
Executable 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");
|
||||
}
|
||||
?>
|
||||
119
loction_server/siro/ride/location/getSpeed.php
Executable file
119
loction_server/siro/ride/location/getSpeed.php
Executable 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());
|
||||
}
|
||||
44
loction_server/siro/ride/location/getTotalDriverDuration.php
Executable file
44
loction_server/siro/ride/location/getTotalDriverDuration.php
Executable 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");
|
||||
}
|
||||
|
||||
?>
|
||||
70
loction_server/siro/ride/location/getTotalDriverDurationToday.php
Executable file
70
loction_server/siro/ride/location/getTotalDriverDurationToday.php
Executable 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()));
|
||||
}
|
||||
?>
|
||||
@@ -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());
|
||||
}
|
||||
86
loction_server/siro/ride/location/getfemalbehavior.php
Normal file
86
loction_server/siro/ride/location/getfemalbehavior.php
Normal 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());
|
||||
}
|
||||
?>
|
||||
59
loction_server/siro/ride/location/save_behavior.php
Normal file
59
loction_server/siro/ride/location/save_behavior.php
Normal 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();
|
||||
?>
|
||||
65
loction_server/siro/ride/location/update.php
Normal file
65
loction_server/siro/ride/location/update.php
Normal 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');
|
||||
}
|
||||
?>
|
||||
48
loction_server/siro/ride/location/update_location.php
Executable file
48
loction_server/siro/ride/location/update_location.php
Executable 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());
|
||||
}
|
||||
?>
|
||||
1
loction_server/siro/ride/locations_data.json
Executable file
1
loction_server/siro/ride/locations_data.json
Executable file
File diff suppressed because one or more lines are too long
2998
loction_server/siro/ride/locations_day.json
Normal file
2998
loction_server/siro/ride/locations_day.json
Normal file
File diff suppressed because it is too large
Load Diff
1074
loction_server/siro/ride/locations_live.json
Normal file
1074
loction_server/siro/ride/locations_live.json
Normal file
File diff suppressed because it is too large
Load Diff
88
loction_server/siro/ride/update_locations_web_app.php
Executable file
88
loction_server/siro/ride/update_locations_web_app.php
Executable file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
// =================================================================
|
||||
// ملف: update_locations.php
|
||||
// الوظيفة: إنشاء ملفات JSON للوضع المباشر واليومي
|
||||
// =================================================================
|
||||
|
||||
// السماح بالوصول من أي مكان (CORS)
|
||||
header("Access-Control-Allow-Origin: *");
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
include "../jwtconnect.php";
|
||||
|
||||
// 1. تحديد الوضع (Mode)
|
||||
$mode = isset($_GET['mode']) && $_GET['mode'] == 'day' ? 'day' : 'live';
|
||||
|
||||
// 2. إعداد المتغيرات حسب الوضع
|
||||
if ($mode == 'day') {
|
||||
$fileName = 'locations_day.json';
|
||||
// شرط: أي تحديث حدث اليوم
|
||||
$condition = "DATE(updated_at) = CURDATE()";
|
||||
$title = "سجل اليوم الكامل";
|
||||
} else {
|
||||
$fileName = 'locations_live.json';
|
||||
// شرط: آخر 20 دقيقة فقط
|
||||
$condition = "updated_at >= NOW() - INTERVAL 20 MINUTE";
|
||||
$title = "مباشر (آخر 20 دقيقة)";
|
||||
}
|
||||
|
||||
$savePath = __DIR__ . '/' . $fileName;
|
||||
|
||||
// دالة تنظيف النصوص العربية وإصلاح الترميز
|
||||
function utf8ize($d) {
|
||||
if (is_array($d)) {
|
||||
foreach ($d as $k => $v) { $d[$k] = utf8ize($v); }
|
||||
} else if (is_string ($d)) {
|
||||
return mb_convert_encoding($d, 'UTF-8', 'UTF-8');
|
||||
}
|
||||
return $d;
|
||||
}
|
||||
|
||||
try {
|
||||
// إجبار قاعدة البيانات على ترميز UTF-8
|
||||
if(isset($con)) { $con->exec("set names utf8mb4"); }
|
||||
|
||||
// تنفيذ الاستعلام
|
||||
$sql = "SELECT * FROM `car_locations` WHERE $condition ORDER BY updated_at DESC";
|
||||
$stmt = $con->prepare($sql);
|
||||
$stmt->execute();
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// تنظيف البيانات
|
||||
$cleanRows = utf8ize($rows);
|
||||
|
||||
// تجهيز البيانات للحفظ
|
||||
$outputData = [
|
||||
'mode' => $mode,
|
||||
'title' => $title,
|
||||
'last_updated' => date('Y-m-d H:i:s'),
|
||||
'count' => count($cleanRows),
|
||||
'drivers' => $cleanRows
|
||||
];
|
||||
|
||||
// تحويل إلى JSON
|
||||
$jsonContent = json_encode($outputData, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
|
||||
if ($jsonContent === false) {
|
||||
die("خطأ في تكوين JSON: " . json_last_error_msg());
|
||||
}
|
||||
|
||||
// حفظ الملف
|
||||
if (file_put_contents($savePath, $jsonContent) !== false) {
|
||||
echo "<div style='font-family:tahoma; direction:rtl; text-align:right; padding:20px; background:#e8f5e9; border:1px solid #4caf50; border-radius:5px;'>";
|
||||
echo "<h3 style='color:green; margin:0;'>✅ تم التحديث بنجاح!</h3>";
|
||||
echo "<p><b>الوضع:</b> $title</p>";
|
||||
echo "<p><b>اسم الملف:</b> $fileName</p>";
|
||||
echo "<p><b>عدد السائقين:</b> " . count($cleanRows) . "</p>";
|
||||
echo "</div>";
|
||||
} else {
|
||||
die("فشل الكتابة في الملف. تأكد من صلاحيات المجلد.");
|
||||
}
|
||||
|
||||
} catch (PDOException $e) {
|
||||
die("خطأ قاعدة بيانات: " . $e->getMessage());
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user