Initial commit with updated Auth and media ignored

This commit is contained in:
Hamza-Ayed
2026-04-28 13:04:27 +03:00
commit 67af97474c
477 changed files with 66444 additions and 0 deletions

0
auth/Tester/error_log Normal file
View File

View File

@@ -0,0 +1,29 @@
<?php
require_once __DIR__ . '/../../connect.php';
$appPlatform = filterRequest("appPlatform");
$sql = "SELECT
*
FROM
`testApp`
WHERE
appPlatform = '$appPlatform'-- AND isTest = 0;";
$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($stmt->rowCount() > 0) {
// Print the retrieved data
// echo json_encode($result);
jsonSuccess($data = $result);
} else {
// Print a failure message
jsonError($message = "No driver order data found");
}
?>

View File

@@ -0,0 +1,23 @@
<?php
require_once __DIR__ . '/../../connect.php';
$appPlatform = filterRequest("appPlatform");
$sql = "UPDATE
`testApp`
SET
`isTest` = '1'
WHERE
`testApp`.appPlatform = '$appPlatform';";
$stmt = $con->prepare($sql);
$stmt->execute();
if ($stmt->rowCount() > 0) {
// Print a success message
jsonSuccess($message = "Test data updated successfully");
} else {
// Print a failure message
jsonError($message = "Failed to update driver order data");
}
?>

View File

@@ -0,0 +1,35 @@
<?php
require_once __DIR__ . '/../../connect.php';
// Sanitize and validate input
$driverId = filterRequest("driverId");
$issueDate = filterRequest("IssueDate");
$inspectionResult = filterRequest("InspectionResult");
// Prepare SQL statement
$sql = "INSERT INTO criminalDocuments (driverId, IssueDate, InspectionResult)
VALUES (:driverId, :issueDate, :inspectionResult)";
try {
$stmt = $con->prepare($sql);
// Bind parameters
$stmt->bindParam(':driverId', $driverId, PDO::PARAM_INT);
$stmt->bindParam(':issueDate', $issueDate, PDO::PARAM_STR);
$stmt->bindParam(':inspectionResult', $inspectionResult, PDO::PARAM_STR);
// Execute the statement
$stmt->execute();
// Check if the insertion was successful
if ($stmt->rowCount() > 0) {
jsonSuccess(null, "Criminal document data saved successfully");
} else {
jsonError("Failed to save criminal document data");
}
} catch (PDOException $e) {
// Log the error and print a generic failure message
error_log("Database Error: " . $e->getMessage());
jsonError("An error occurred while saving the data");
}
?>

View File

@@ -0,0 +1,60 @@
<?php
require_once __DIR__ . '/../../connect.php';
$id = filterRequest("id");
// يمكن استقبال سبب الحظر من التطبيق أو وضعه كقيمة افتراضية
$reason = "Driver requested deletion (deleteFromHimself)";
// تأكد أن المعرف رقم صحيح
if (!is_numeric($id)) {
jsonError("Invalid ID");
exit();
}
try {
// 1. جلب رقم الهاتف الخاص بالسائق قبل التحديث
// نحتاج الهاتف لإضافته في القائمة السوداء
$stmtPhone = $con->prepare("SELECT phone FROM `driver` WHERE `id` = :id");
$stmtPhone->bindParam(':id', $id, PDO::PARAM_INT);
$stmtPhone->execute();
$driverData = $stmtPhone->fetch(PDO::FETCH_ASSOC);
// التحقق من وجود السائق
if (!$driverData) {
jsonError("Driver not found");
exit();
}
$phone = $driverData['phone'];
// 2. تحديث حالة السائق
$sql = "UPDATE `driver` SET `status` = 'deleteFromHimself' WHERE `id` = :id";
$stmt = $con->prepare($sql);
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();
if ($stmt->rowCount() > 0) {
// 3. الإضافة إلى القائمة السوداء (blacklist_driver)
// نستخدم NOW() لتسجيل الوقت الحالي تلقائياً
// لا نمرر id العمود الأول لأنه غالباً Auto Increment في قاعدة البيانات
$insertSql = "INSERT INTO `blacklist_driver` (`driver_id`, `phone`, `reason`, `created_at`)
VALUES (:driver_id, :phone, :reason, NOW())";
$insertStmt = $con->prepare($insertSql);
$insertStmt->execute([
':driver_id' => $id,
':phone' => $phone,
':reason' => $reason
]);
jsonSuccess(null, "Record marked as deleted and added to blacklist successfully");
} else {
jsonError("Failed to update record or no change made");
}
} catch (PDOException $e) {
// في حال حدوث خطأ في قاعدة البيانات (مثلاً تكرار الإضافة)
jsonError("Database Error: " . $e->getMessage());
}
?>

15
auth/captin/error_log Normal file
View File

@@ -0,0 +1,15 @@
[21-May-2025 12:28:44 Europe/Berlin] PHP Fatal error: Uncaught PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'driver.education' in 'field list' in /home2/seferli1/server.sefer.live/sefer.click/sefer/auth/captin/loginFromGoogle.php:43
Stack trace:
#0 /home2/seferli1/server.sefer.live/sefer.click/sefer/auth/captin/loginFromGoogle.php(43): PDO->prepare('SELECT\n driv...')
#1 {main}
thrown in /home2/seferli1/server.sefer.live/sefer.click/sefer/auth/captin/loginFromGoogle.php on line 43
[21-May-2025 21:09:18 Europe/Berlin] PHP Fatal error: Uncaught PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'driver.education' in 'field list' in /home2/seferli1/server.sefer.live/sefer.click/sefer/auth/captin/loginFromGoogle.php:43
Stack trace:
#0 /home2/seferli1/server.sefer.live/sefer.click/sefer/auth/captin/loginFromGoogle.php(43): PDO->prepare('SELECT\n driv...')
#1 {main}
thrown in /home2/seferli1/server.sefer.live/sefer.click/sefer/auth/captin/loginFromGoogle.php on line 43
[22-May-2025 03:30:03 Europe/Berlin] PHP Fatal error: Uncaught PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'driver.education' in 'field list' in /home2/seferli1/server.sefer.live/sefer.click/sefer/auth/captin/loginFromGoogle.php:43
Stack trace:
#0 /home2/seferli1/server.sefer.live/sefer.click/sefer/auth/captin/loginFromGoogle.php(43): PDO->prepare('SELECT\n driv...')
#1 {main}
thrown in /home2/seferli1/server.sefer.live/sefer.click/sefer/auth/captin/loginFromGoogle.php on line 43

View File

View File

@@ -0,0 +1,24 @@
<?php
require_once __DIR__ . '/../../connect.php';
$driverID = filterRequest("id");
// تحقق أن المعرف رقم صحيح
if (!is_numeric($driverID)) {
jsonError("Invalid driver ID");
exit();
}
// استخدم bindParam لتفادي حقن SQL
$sql = "SELECT `accountBank` FROM `driver` WHERE `id` = :id";
$stmt = $con->prepare($sql);
$stmt->bindParam(':id', $driverID, PDO::PARAM_INT);
$stmt->execute();
if ($stmt->rowCount() > 0) {
$row = $stmt->fetchAll(PDO::FETCH_ASSOC);
jsonSuccess($row);
} else {
jsonError("No account bank record found");
}
?>

View File

@@ -0,0 +1,39 @@
<?php
require_once __DIR__ . '/../../connect.php';
$sql = "
SELECT
`id`,
`phone`,
`email`,
`gender`,
`birthdate`,
`first_name`,
`last_name`,
`sosPhone`
FROM
`passengers`
";
$stmt = $con->prepare($sql);
$stmt->execute();
if ($stmt->rowCount() > 0) {
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
// فك تشفير الحقول الحساسة
foreach ($rows as &$row) {
$row['phone'] = $encryptionHelper->decryptData($row['phone']);
$row['email'] = $encryptionHelper->decryptData($row['email']);
$row['gender'] = $encryptionHelper->decryptData($row['gender']);
$row['birthdate'] = $encryptionHelper->decryptData($row['birthdate']);
$row['first_name'] = $encryptionHelper->decryptData($row['first_name']);
$row['last_name'] = $encryptionHelper->decryptData($row['last_name']);
$row['sosPhone'] = $encryptionHelper->decryptData($row['sosPhone']);
}
jsonSuccess($rows);
} else {
jsonError("No wallet record found");
}
?>

View File

@@ -0,0 +1,23 @@
<?php
require_once __DIR__ . '/../../connect.php';
// $driverID = filterRequest("id");
$sql = "
SELECT * FROM `promptDriverIDEgypt`";
$stmt = $con->prepare($sql);
$stmt->execute();
if ($stmt->rowCount() > 0) {
// Fetch the record
$row = $stmt->fetchAll(PDO::FETCH_ASSOC);
jsonSuccess($row);
}
else{
// Print a failure message
jsonError($message = "No wallet record found");
}
?>

66
auth/captin/login.php Normal file
View File

@@ -0,0 +1,66 @@
<?php
require_once __DIR__ . '/../../connect.php';
$email = filterRequest('email');
$phone = filterRequest('phone');
$password = filterRequest('password');
// تشفير الحقول المطلوبة قبل الاستعلام
$email = $encryptionHelper->encryptData($email);
$phone = $encryptionHelper->encryptData($phone);
$sql = "SELECT
driver.id,
driver.phone,
driver.email,
driver.password,
driver.gender,
driver.birthdate,
driver.site,
driver.first_name,
driver.last_name,
driver.education,
driver.employmentType,
driver.maritalStatus,
driver.created_at,
driver.updated_at,
email_verifications.verified
FROM
driver
LEFT JOIN email_verifications ON email_verifications.email = driver.email
WHERE
driver.phone = :phone AND driver.email = :email";
$stmt = $con->prepare($sql);
$stmt->bindParam(':email', $email);
$stmt->bindParam(':phone', $phone);
$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$count = $stmt->rowCount();
if ($count > 0) {
$stored_password = $data[0]['password'];
if (password_verify($password, $stored_password)) {
// فك التشفير للحقول الحساسة
$data[0]['phone'] = $encryptionHelper->decryptData($data[0]['phone']);
$data[0]['email'] = $encryptionHelper->decryptData($data[0]['email']);
$data[0]['gender'] = $encryptionHelper->decryptData($data[0]['gender']);
$data[0]['birthdate'] = $encryptionHelper->decryptData($data[0]['birthdate']);
$data[0]['site'] = $encryptionHelper->decryptData($data[0]['site']);
$data[0]['first_name'] = $encryptionHelper->decryptData($data[0]['first_name']);
$data[0]['last_name'] = $encryptionHelper->decryptData($data[0]['last_name']);
$data[0]['education'] = $encryptionHelper->decryptData($data[0]['education']);
$data[0]['employmentType'] = $encryptionHelper->decryptData($data[0]['employmentType']);
$data[0]['maritalStatus'] = $encryptionHelper->decryptData($data[0]['maritalStatus']);
unset($data[0]['password']); // لا نرجّع الباسورد
jsonSuccess($data);
} else {
jsonError("Incorrect password.");
}
} else {
jsonError("User does not exist.");
}
?>

111
auth/captin/loginFromGoogle.php Executable file
View File

@@ -0,0 +1,111 @@
<?php
// loginFromGoogle.php
require_once __DIR__ . '/../../connect.php';
try {
/* ────────────────────────────────
1) قراءة القيم الأولية
───────────────────────────────── */
// $emailRaw = filterRequest('email'); // البريد القادم من التطبيق (غير مشفَّر)
$driverID = filterRequest('id'); // DriverID المُرسل
// error_log("[Debug] Email (raw): $emailRaw");
error_log("[Debug] DriverID: $driverID");
/* ────────────────────────────────
2) تشفير الإيميل
───────────────────────────────── */
// $emailEnc = $encryptionHelper->encryptData($emailRaw);
// error_log("[Debug] Email (encrypted): $emailEnc");
/* ────────────────────────────────
3) إعداد الاستعلام الموحَّد
───────────────────────────────── */
$sql = "
SELECT
driver.id, driver.phone, driver.email, driver.gender, driver.birthdate,
driver.site, driver.first_name, driver.last_name, driver.bankCode,
driver.accountBank, driver.employmentType,driver.status, driver.maritalStatus,
driver.created_at, driver.updated_at,
phone_verification.is_verified,
CarRegistration.make, CarRegistration.model, CarRegistration.year,
df.is_claimed, inv.isInstall, inv.isGiftToken
FROM driver
LEFT JOIN phone_verification ON phone_verification.phone_number = driver.phone
LEFT JOIN driver_gifts df ON df.driver_id = driver.id
LEFT JOIN CarRegistration ON CarRegistration.driverID = driver.id
LEFT JOIN invites inv ON inv.driverId = driver.id
WHERE
driver.id = :id
-- AND phone_verification.is_verified = '1'
LIMIT 1
";
// error_log("[Debug] queryString:\n$sql");
$stmt = $con->prepare($sql);
// باراميترات الربط
$params = [
//':email' => $emailEnc,
':id' => $driverID,
];
foreach ($params as $k => $v) {
$stmt->bindValue($k, $v);
}
/* ───────── dumpParams (اختياري) ───────── */
ob_start();
$stmt->debugDumpParams();
error_log("[Debug] dumpParams:\n" . ob_get_clean());
/* ────────────────────────────────
4) تنفيذ الاستعلام
───────────────────────────────── */
$stmt->execute();
error_log("[Debug] stmt->rowCount(): " . $stmt->rowCount());
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
// error_log("[Debug] Raw fetched JSON: " . json_encode($rows, JSON_UNESCAPED_UNICODE));
if (!$rows) {
jsonError("User does not exist or phone not verified.");
exit;
}
/* ────────────────────────────────
5) فك التشفير للحقول الحسّاسة
───────────────────────────────── */
$data = &$rows[0]; // مرجع لتوفير الذاكرة
$decryptIfNotNull = function($field) use (&$data, $encryptionHelper) {
if (isset($data[$field]) && $data[$field] !== null) {
$data[$field] = $encryptionHelper->decryptData($data[$field]);
}
};
foreach ([
'phone', 'email', 'gender', 'birthdate', 'site',
'first_name', 'last_name'
] as $field) {
$decryptIfNotNull($field);
}
error_log("[Debug] Raw fetched JSON: " . json_encode($rows, JSON_UNESCAPED_UNICODE));
echo json_encode([
"status" => "success",
"count" => 1,
"data" => $rows // نتيجة واحدة فقط
], JSON_UNESCAPED_UNICODE);
} catch (PDOException $e) {
error_log("[PDO ERROR] " . $e->getMessage());
jsonError("Database error: ".$e->getCode());
} catch (Exception $e) {
error_log("[GENERAL ERROR] " . $e->getMessage());
jsonError("Error occurred.");
} finally {
$stmt = null;
$con = null;
}
?>

View File

@@ -0,0 +1,77 @@
<?php
require_once __DIR__ . '/../../connect.php';
$email = filterRequest('email');
$password = filterRequest('password');
// تشفير الإيميل لاستخدامه في الاستعلام
$encryptedEmail = $encryptionHelper->encryptData($email);
// SQL لاسترجاع المستخدم بناءً على البريد الإلكتروني المشفر
$sql = "SELECT
driver.id,
driver.phone,
driver.email,
driver.gender,
driver.birthdate,
driver.site,
driver.first_name,
driver.last_name,
driver.bankCode,
driver.accountBank,
driver.education,
driver.employmentType,
driver.maritalStatus,
driver.created_at,
driver.updated_at,
driver.password,
phone_verification.is_verified,
CarRegistration.make,
CarRegistration.model,
CarRegistration.year
FROM
driver
LEFT JOIN phone_verification ON phone_verification.phone_number = driver.phone
LEFT JOIN CarRegistration ON CarRegistration.driverID = driver.id
WHERE
driver.email = :email AND phone_verification.is_verified = '1'
LIMIT 1";
$stmt = $con->prepare($sql);
$stmt->bindParam(':email', $encryptedEmail);
$stmt->execute();
$data = $stmt->fetch(PDO::FETCH_ASSOC);
if ($data) {
if (password_verify($password, $data['password'])) {
unset($data['password']);
// فك تشفير الحقول الحساسة
$data['phone'] = $encryptionHelper->decryptData($data['phone']);
$data['email'] = $encryptionHelper->decryptData($data['email']);
$data['gender'] = $encryptionHelper->decryptData($data['gender']);
$data['birthdate'] = $encryptionHelper->decryptData($data['birthdate']);
$data['site'] = $encryptionHelper->decryptData($data['site']);
$data['first_name'] = $encryptionHelper->decryptData($data['first_name']);
$data['last_name'] = $encryptionHelper->decryptData($data['last_name']);
$data['education'] = $encryptionHelper->decryptData($data['education']);
$data['employmentType'] = $encryptionHelper->decryptData($data['employmentType']);
$data['maritalStatus'] = $encryptionHelper->decryptData($data['maritalStatus']);
echo json_encode([
"status" => "success",
"data" => $data
]);
} else {
jsonError("Incorrect password.");
}
} else {
jsonError("User does not exist or phone number not verified.");
}
$stmt = null;
$con = null;
exit();
?>

132
auth/captin/register.php Executable file
View File

@@ -0,0 +1,132 @@
<?php
$allowRegistration = true;
require_once __DIR__ . '/../../connect.php';
try {
/* =========== 1) الحقول الواردة من الـ POST =========== */
$required = ["phone", "password", "first_name", "last_name"];
$optional = [
"id", "email", "gender", "license_type", "national_number",
"name_arabic", "issue_date", "expiry_date", "license_categories",
"address", "licenseIssueDate", "status", "birthdate", "site",
"accountBank", "bankCode", "employmentType",
"maritalStatus", "fullNameMaritial", "expirationDate"
];
$data = [];
// التحقق من الحقول المطلوبة
foreach ($required as $f) {
$val = filterRequest($f);
if ($val === null || $val === '') {
jsonError("Missing required field: $f");
exit;
}
$data[$f] = $val;
}
// قراءة الحقول الاختيارية
foreach ($optional as $f) {
$v = filterRequest($f);
$data[$f] = ($v === null || $v === '' || $v === 'Not specified') ? null : $v;
}
if ($data['email'] === null) {
// phone هنا ما زال خامًا (غير مُشفَّر)
$data['email'] = $data['phone'] . '@intaleqapp.com';
}
/* =========== 2) تشفير الحقول الحسّاسة =========== */
$encryptThese = ["phone", "email", "first_name", "last_name", "name_arabic","gender", "national_number",
"address", "site", "fullNameMaritial"];
foreach ($encryptThese as $f) {
if ($data[$f] !== null) {
$data[$f] = $encryptionHelper->encryptData($data[$f]);
}
}
/* =========== 3) توليد driver ID (id) إذا لم يُرسَل =========== */
/* =========== 4) هَش كلمة المرور =========== */
$data['password_hashed'] = password_hash($data['password'], PASSWORD_DEFAULT);
/* =========== 5) منع التكرار في الهاتف / الإيميل =========== */
$dup = $con->prepare(
"SELECT id FROM driver WHERE phone = :phone OR email = :email"
);
$dup->execute([
':phone' => $data['phone'],
':email' => $data['email']
]);
if ($dup->rowCount() > 0) {
jsonError("Phone or email already registered.");
exit;
}
/* =========== 6) إدخال السجل الجديد =========== */
$sql = "
INSERT INTO driver (
id, phone, email, password, gender, license_type, national_number,
name_arabic, issue_date, expiry_date, license_categories,
address, licenseIssueDate, status, birthdate, site,
first_name, last_name, accountBank, bankCode,
employmentType, maritalStatus, fullNameMaritial, expirationDate,
created_at, updated_at
) VALUES (
:id, :phone, :email, :pwd, :gender, :license_type, :national_number,
:name_arabic, :issue_date, :expiry_date, :license_categories,
:address, :licenseIssueDate, :status, :birthdate, :site,
:first_name, :last_name, :accountBank, :bankCode,
:employmentType, :maritalStatus, :fullNameMaritial, :expirationDate,
NOW(), NOW()
)
";
$ins = $con->prepare($sql);
// خريطة الربط (تطابق تمامًا أسماء الـ placeholders في الـ SQL أعلاه)
$bind = [
'id' => $data['id'],
'phone' => $data['phone'],
'email' => $data['email'],
'pwd' => $data['password_hashed'],
'gender' => $data['gender'],
'license_type' => $data['license_type'],
'national_number' => $data['national_number'],
'name_arabic' => $data['name_arabic'],
'issue_date' => $data['issue_date'],
'expiry_date' => $data['expiry_date'],
'license_categories'=> $data['license_categories']?? 'B',
'address' => $data['address'],
'licenseIssueDate' => $data['licenseIssueDate'],
'status' => $data['status'] ?? 'yet',
'birthdate' => $data['birthdate'],
'site' => $data['site'],
'first_name' => $data['first_name'],
'last_name' => $data['last_name'],
'accountBank' => 'yet',
'bankCode' => 'yet',
'employmentType' => $data['employmentType']?? 'yet',
'maritalStatus' => $data['maritalStatus']?? 'yet',
'fullNameMaritial' => $data['fullNameMaritial']?? 'yet',
'expirationDate' => $data['expirationDate']?? 'yet',
];
foreach ($bind as $key => $value) {
$ins->bindValue(":$key", $value);
}
if ($ins->execute()) {
jsonSuccess($data['id']); // ترجع driver ID
} else {
jsonError("Failed to insert driver record.");
}
} catch (PDOException $e) {
error_log("DriverInsert PDO: " . $e->getMessage());
jsonError("Database error.");
}
?>

View File

@@ -0,0 +1,16 @@
<?php
require_once __DIR__ . '/../../connect.php';
$id = filterRequest("id");
$sql = "DELETE FROM `passengers` WHERE `id` = :id";
$stmt = $con->prepare($sql);
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();
if ($stmt->rowCount() > 0) {
jsonSuccess(null, "Passenger deleted successfully.");
} else {
jsonError("Failed to delete passenger.");
}
?>

View File

@@ -0,0 +1,130 @@
<?php
require_once __DIR__ . '/../../connect.php';
// استرجاع البيانات من الطلب
$phone_number = filterRequest("phone_number");
$driverId = filterRequest("driverId");
$email = filterRequest("email");
$expiration_time = filterRequest("expiration_time"); // اختياري للمستقبل
// تحقق من وجود رقم الهاتف
if (empty($phone_number)) {
jsonError("Phone number is required");
exit;
}
// توليد رمز تحقق مكوّن من 5 أرقام
$token_code = str_pad(random_int(0, 99999), 5, '0', STR_PAD_LEFT);
// تشفير البيانات الحساسة
$encryptedPhone = $encryptionHelper->encryptData($phone_number);
$encryptedToken = $encryptionHelper->encryptData($token_code);
$encryptedEmail = $encryptionHelper->encryptData($email); // اختياري إذا بتحب تشفيره
// التحقق من وجود الرقم مسبقاً في قاعدة البيانات
$sqlCheck = "SELECT * FROM `phone_verification` WHERE `phone_number` = :phone";
$stmtCheck = $con->prepare($sqlCheck);
$stmtCheck->bindParam(":phone", $encryptedPhone);
$stmtCheck->execute();
$success = false;
// إذا كان الرقم موجود → تحديث
if ($stmtCheck->rowCount() > 0) {
$sqlUpdate = "UPDATE `phone_verification`
SET `token_code` = :token,
`expiration_time` = DATE_ADD(NOW(), INTERVAL 5 MINUTE)
WHERE `phone_number` = :phone";
$stmt = $con->prepare($sqlUpdate);
$stmt->bindParam(":token", $encryptedToken);
$stmt->bindParam(":phone", $encryptedPhone);
$stmt->execute();
$success = $stmt->rowCount() > 0;
} else {
// إذا الرقم غير موجود → إدخال جديد
$sqlInsert = "INSERT INTO `phone_verification`
(`phone_number`, `driverId`, `email`, `token_code`, `expiration_time`, `is_verified`, `created_at`)
VALUES
(:phone, :driverId, :email, :token, DATE_ADD(NOW(), INTERVAL 5 MINUTE), 0, NOW())";
$stmt = $con->prepare($sqlInsert);
$stmt->bindParam(":phone", $encryptedPhone);
$stmt->bindParam(":driverId", $driverId);
$stmt->bindParam(":email", $encryptedEmail);
$stmt->bindParam(":token", $encryptedToken);
$stmt->execute();
$success = $stmt->rowCount() > 0;
}
// إذا تم الحفظ بنجاح → أرسل الرمز عبر SMS
if ($success) {
// تحميل بيانات الاتصال بالـ SMS API من المتغيرات البيئية
$username = getenv('SMS_USERNAME');
$password = getenv('SMS_PASSWORD_EGYPT');
$sender = getenv('SMS_SENDER');
if (!$username || !$password || !$sender) {
jsonError("SMS credentials are missing");
exit;
}
$message = "Tripz app code is " . $token_code;
$receiver = $phone_number;
$apiUrl = 'https://sms.kazumi.me/api/sms/send-sms';
$payload = [
'username' => $username,
'password' => $password,
'language' => 'e',
'sender' => $sender,
'receiver' => $receiver,
'message' => $message
];
$jsonPayload = json_encode($payload);
$smsResponse = callAPI("POST", $apiUrl, $jsonPayload);
if ($smsResponse) {
jsonSuccess(null, "Verification code sent and saved successfully");
} else {
jsonError("Code saved, but SMS sending failed");
}
} else {
jsonError("Failed to save verification data");
}
// دالة الاتصال بالـ API
function callAPI($method, $url, $data) {
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_POSTFIELDS => $data,
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Accept: application/json"
],
CURLOPT_TIMEOUT => 30,
CURLOPT_CONNECTTIMEOUT => 10
]);
$api_raw_response = curl_exec($curl);
if (curl_errno($curl)) {
error_log("cURL Error [".curl_errno($curl)."]: " . curl_error($curl));
curl_close($curl);
return false;
}
curl_close($curl);
$decoded_response = json_decode($api_raw_response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
error_log("Invalid JSON response from SMS API.");
return false;
}
error_log("SMS API response: " . print_r($decoded_response, true));
return $decoded_response;
}
?>

View File

@@ -0,0 +1,44 @@
<?php
require_once __DIR__ . '/../../connect.php';
$id = filterRequest("id");
$columnValues = [];
// الحقول التي تحتاج تشفير
$fieldsToEncrypt = [
"phone", "email", "gender", "birthdate", "site",
"first_name", "last_name", "accountBank", "education",
"employmentType", "maritalStatus"
];
// الحقول غير المشفرة
$plainFields = ["status", "bankCode", "updated_at"];
foreach ($_POST as $key => $value) {
$filtered = filterRequest($key);
if ($key === "password") {
// هاش لكلمة المرور
$hashed = password_hash($filtered, PASSWORD_DEFAULT);
$columnValues[] = "`password` = '$hashed'";
} elseif (in_array($key, $fieldsToEncrypt)) {
$encrypted = $encryptionHelper->encryptData($filtered);
$columnValues[] = "`$key` = '$encrypted'";
} elseif (in_array($key, $plainFields)) {
$columnValues[] = "`$key` = '$filtered'";
}
}
// بناء جملة التحديث
$setClause = implode(", ", $columnValues);
$sql = "UPDATE `driver` SET $setClause WHERE `id` = '$id'";
$stmt = $con->prepare($sql);
$stmt->execute();
if ($stmt->rowCount() > 0) {
jsonSuccess(null, "Driver data updated successfully");
} else {
jsonError("Failed to update driver data");
}
?>

View File

@@ -0,0 +1,38 @@
<?php
require_once __DIR__ . '/../../connect.php';
// Sanitize and validate input
$driverId = filterRequest("driverId");
// SQL query to check if a gift already exists for the driver (unclaimed)
$checkSql = "SELECT COUNT(*) FROM driver_gifts WHERE driver_id = :driverId -- AND is_claimed = 0";
try {
$checkStmt = $con->prepare($checkSql);
$checkStmt->bindParam(':driverId', $driverId, PDO::PARAM_INT);
$checkStmt->execute();
$giftExists = $checkStmt->fetchColumn();
if ($giftExists > 0) {
jsonError("Gift already exists for this driver");
exit;
}
// Insert a new claimed gift
$sql = "INSERT INTO driver_gifts (driver_id, gift_description, is_claimed)
VALUES (:driverId, 'new account 300 le', 1)";
$stmt = $con->prepare($sql);
$stmt->bindParam(':driverId', $driverId, PDO::PARAM_INT);
$stmt->execute();
if ($stmt->rowCount() > 0) {
jsonSuccess(null, "Gift data saved successfully");
} else {
jsonError("Failed to save gift data");
}
} catch (PDOException $e) {
error_log("Database Error: " . $e->getMessage());
jsonError("An error occurred while saving the data");
}
?>

View File

@@ -0,0 +1,56 @@
<?php
require_once __DIR__ . '/../../connect.php';
$id = filterRequest("id");
// تحقق من وجود بيانات
if (empty($_POST)) {
jsonError("No passenger data provided for update.");
exit;
}
// الحقول الحساسة التي يجب تشفيرها
$fieldsToEncrypt = ["phone", "email", "gender", "birthdate", "site", "first_name", "last_name", "sosPhone"];
// بناء الحقول والمعاملات
$columnValues = [];
$params = [];
foreach ($fieldsToEncrypt as $field) {
if (isset($_POST[$field])) {
$value = filterRequest($field);
$encryptedValue = $encryptionHelper->encryptData($value);
$columnValues[] = "`$field` = ?";
$params[] = $encryptedValue;
}
}
// تحقق من أن هناك حقول للتحديث
if (empty($columnValues)) {
jsonError("No valid encrypted passenger data provided for update.");
exit;
}
// تركيب جملة SQL
$setClause = implode(", ", $columnValues);
$params[] = $id;
$sql = "UPDATE `passengers` SET $setClause WHERE `id` = ?";
try {
$stmt = $con->prepare($sql);
foreach ($params as $index => $value) {
$stmt->bindValue($index + 1, $value);
}
if ($stmt->execute()) {
jsonSuccess(null, "Passenger data updated successfully with encryption");
} else {
jsonError("Failed to update passenger data");
}
} catch (PDOException $e) {
jsonError("Database error: " . $e->getMessage());
}
?>

View File

@@ -0,0 +1,39 @@
<?php
require_once __DIR__ . '/../../connect.php';
// استقبال معرف السائق
$id = filterRequest("id");
// استقبال بيانات شام كاش من التطبيق
$accountBank = filterRequest("accountBank"); // الاسم (مثال: intaleq)
$bankCode = filterRequest("bankCode"); // الكود الطويل (مثال: 80f23afe...)
// التحقق من وصول البيانات المطلوبة
if ($id && $accountBank && $bankCode) {
try {
// 1. تشفير اسم الحساب (حسب القواعد في السكربت السابق accountBank مشفر)
$encryptedAccountBank = $encryptionHelper->encryptData($accountBank);
// 2. كود المحفظة يبقى كما هو (حسب القواعد bankCode غير مشفر)
$plainBankCode = $encryptionHelper->encryptData($bankCode);
// 3. جملة التحديث
$stmt = $con->prepare("UPDATE `driver` SET `accountBank` = ?, `bankCode` = ? WHERE `id` = ?");
$stmt->execute(array($encryptedAccountBank, $plainBankCode, $id));
// التحقق من نجاح العملية
// rowCount > 0 يعني تم التحديث، أحياناً يعطي 0 إذا كانت البيانات هي نفسها لم تتغير
// لذا نرسل نجاح في كلتا الحالتين طالما لم يحدث Error
jsonSuccess(null, "ShamCash info updated successfully");
} catch (PDOException $e) {
// في حال وجود خطأ في قاعدة البيانات
jsonError("Database Error: " . $e->getMessage());
}
} else {
jsonError("Missing required fields: id, accountBank, or bankCode");
}
?>

View File

39
auth/captin/verifyOtpDriver.php Executable file
View File

@@ -0,0 +1,39 @@
<?php
require_once __DIR__ . '/../../connect.php';
$phone_number = filterRequest("phone_number");
$token_code = filterRequest("token_code");
$encryptedPhone = $encryptionHelper->encryptData($phone_number);
$encryptedToken = $encryptionHelper->encryptData($token_code);
// Check if the phone number and token code match
$sql = "SELECT
`id`,
`phone_number`,
`token_code`,
`expiration_time`,
`is_verified`,
`created_at`
FROM
`phone_verification`
WHERE
`phone_number` = :phone_number AND `token_code` = :token_code -- AND `expiration_time` > NOW()";
$stmt = $con->prepare($sql);
$stmt->bindParam(':phone_number', $encryptedPhone, PDO::PARAM_STR);
$stmt->bindParam(':token_code', $encryptedToken, PDO::PARAM_STR);
$stmt->execute();
$result = $stmt->fetch();
if ($result) {
// $id = $result["id"];
$sql = "UPDATE `phone_verification` SET `is_verified` = 1 WHERE `phone_number` = :phone_number";
$stmt = $con->prepare($sql);
$stmt->bindParam(':phone_number', $phone_number, PDO::PARAM_STR);
$stmt->execute();
jsonSuccess($message = "Your phone number has been verified.");
} else {
jsonError($message = "Your phone number could not be verified. Please try again.");
}
?>

View File

@@ -0,0 +1,21 @@
<?php
require_once __DIR__ . '/../connect.php';
// استقبال وتشفير رقم الهاتف
$phoneNumber = filterRequest("phone_number");
$phoneNumber = $encryptionHelper->encryptData($phoneNumber);
// تجهيز الاستعلام باستخدام bindParam للحماية
$sql = "SELECT * FROM `phone_verification` WHERE `phone_number` = :phone_number";
$stmt = $con->prepare($sql);
$stmt->bindParam(":phone_number", $phoneNumber);
$stmt->execute();
if ($stmt->rowCount() > 0) {
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
jsonSuccess($rows);
} else {
jsonError("No phone verified yet found");
}
?>

View File

@@ -0,0 +1,39 @@
<?php
require_once __DIR__ . '/../connect.php';
// استقبال القيم
$phoneNumber = filterRequest("phone_number");
$email = filterRequest("email");
// تشفير القيم المطلوبة للمقارنة داخل SQL
$phoneNumber = $encryptionHelper->encryptData($phoneNumber);
$email = $encryptionHelper->encryptData($email);
// تنفيذ الاستعلام
$sql = "
SELECT
pv.*,
p.email
FROM
`phone_verification_passenger` pv
INNER JOIN
`passengers` p ON pv.phone_number = p.phone
WHERE
pv.phone_number = :phoneNumber AND p.email = :email
";
$stmt = $con->prepare($sql);
$stmt->bindParam(':phoneNumber', $phoneNumber, PDO::PARAM_STR);
$stmt->bindParam(':email', $email, PDO::PARAM_STR);
$stmt->execute();
if ($stmt->rowCount() > 0) {
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
// يمكنك هنا لاحقًا تفكيك تشفير أي حقل إذا كنت ترجع phone/email مثلاً للمستخدم، لكن في حالتنا ما في حاجة.
jsonSuccess($rows);
} else {
jsonError("No Phone verified or related email found");
}
?>

23
auth/cnMap.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
require_once __DIR__ . '/../connect.php';
// Import the map
$cn = array(
"0" => "3",
"1" => "7",
"2" => "1",
"3" => "9",
"4" => "0",
"5" => "5",
"6" => "2",
"7" => "6",
"8" => "4",
"9" => "8"
);
// Convert the map to a JSON string with JSON_FORCE_OBJECT option
$jsonString = json_encode($cn, JSON_FORCE_OBJECT);
// Send the JSON string to the Flutter app
echo $jsonString;
?>

1
auth/cn_map.json Normal file
View File

@@ -0,0 +1 @@
["3","7","1","9","0","5","2","6","4","8"]

View File

@@ -0,0 +1,245 @@
<?php
require_once __DIR__ . '/../../connect.php';
$driverId = filterRequest("driver_id");
$type = filterRequest("type");
// 🔒 Validate image
if (!isset($_FILES['image']) || $_FILES['image']['error'] !== UPLOAD_ERR_OK) {
error_log("Upload error: Image not provided or upload failed.");
jsonError("Image upload failed");
exit;
}
$file = $_FILES['image'];
$extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
$allowed = ['jpg', 'jpeg', 'png'];
if (!in_array($extension, $allowed)) {
error_log("Unsupported file type: $extension");
jsonError("Unsupported file type");
exit;
}
$uniqueName = "driver_" . $type . "_" . $driverId . ".$extension";
$uploadDir = "../uploads/documents/";
$uploadPath = $uploadDir . $uniqueName;
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
if (!move_uploaded_file($file['tmp_name'], $uploadPath)) {
error_log("Failed to move uploaded file.");
jsonError("Failed to move uploaded image");
exit;
}
$imageUrl = "https://intaleq.xyz/intaleq/auth/uploads/documents/" . $uniqueName ;
$imageData = file_get_contents($uploadPath);
$imageBase64 = base64_encode($imageData);
$mimeType = match ($extension) {
'jpg', 'jpeg' => 'image/jpeg',
'png' => 'image/png',
default => 'application/octet-stream',
};
$prompts = [
"id_front_sy" => <<<EOT
You are an OCR expert for Syrian national ID cards (green card).
### TASK
Analyse the **front side** of the ID and return **raw JSON only** with exactly these keys:
{
"full_name": "", // الاسم الثلاثي أو الرباعي
"national_number": "", // الرقم الوطني (LATIN digits only)
"dob": "YYYY-MM-DD", // تاريخ الميلاد
"address": "" // العنوان
}
### RULES
* Read the red number on the bottom of the card.
* Convert any Eastern-Arabic digits (٠١٢٣٤٥٦٧٨٩) to Western-Arabic digits (0-9).
* `national_number` must contain **Latin digits only, no spaces or other characters**.
* If a field is missing, set it to **null**.
* Convert the birth date to ISO `YYYY-MM-DD`.
* Return valid JSON only — no extra keys, no markdown.
EOT,
"id_back_sy" => <<<EOT
أنت خبير OCR مختص ببطاقات الهوية السورية (الوجه الخلفي).
### المطلوب
حلّل صورة الوجه الخلفي للهوية السورية وأعد **JSON صِرف** يحتوي المفاتيح التالية فقط:
{
"governorate": "", // المحافظة (مثال: دمشق)
"address": "", // العنوان التفصيلي (حيّ، بلدة …)
"gender": "", //Male or Female
"issue_date": "YYYY-MM-DD"// تاريخ الإصدار بصيغة ISO
}
### القواعد
1. حوّل أي أرقام عربية شرقية (٠١٢٣٤٥٦٧٨٩) إلى أرقام لاتينية (0-9).
2. أعدّ تاريخ الإصدار بالتقويم الميلادي بصيغة `YYYY-MM-DD`.
3. استخدم أحرف لاتينية كبيرة لزمرة الدم مع رمز `+` أو `-` فقط.
4. إذا كان أحد الحقول غير موجود مطلقًا، أعد قيمته **null**.
5. لا تُرجع أي مفاتيح إضافية أو شروح أو Markdown — JSON صالح فقط.
EOT,
"driving_license_sy_front" => <<<EOT
You are an OCR expert for Syrian documents.
### TASK
Analyse the **front side of a Syrian driving licence** and return **clean JSON only** with the following keys (no extra keys, no markdown):
{
"name_arabic": "", // الاسم الثلاثي أو الرباعي بالعربية
"birth_place": "", // المحافظة أو المنطقة المكتوبة بعد كلمة الولادة
"birth_year": "", // سنة الميلاد فقط (أربعة أرقام)
"national_number": ""
"civil_registry": "", // سطر "القيد" (مثال: سهوة 3)
"blood_type": "" // زمرة الدم بالشكل: A+ , A- , B+ , B- , AB+ , AB- , O+ , O-
}
### RULES
* إذا كانت القيمة مفقودة تمامًا اكتب **null**.
* لا تُغيّر ترتيب المفاتيح.
* لا تُرسل أى شرح أو أسطر إضافية JSON خالص فقط.
EOT,
"driving_license_sy_back" => <<<EOT
You are an OCR expert for Syrian driving licences.
### TASK
Analyse the **back side** of a Syrian driving licence and return **raw JSON only** with exactly these keys:
{
"issue_date": "YYYY-MM-DD", // تاريخ المنح
"expiry_date": "YYYY-MM-DD", // صالحة لغاية
"license_number": "", // رقم الإجازة
"license_category": "" // D1, D2, D3 … (as printed after "UNIVERSAL DRIVING LICENCE")
}
### RULES
* If a value is totally absent, set it to **null**.
* Convert all dates to ISO `YYYY-MM-DD` (Gregorian).
* Do **NOT** add extra keys, comments, or markdown — return valid JSON only.
EOT,
"vehicle_license_sy_front" => <<<EOT
You are an OCR expert specialized in analyzing Syrian vehicle registration cards (الرخصة البرتقالية).
Your task is to extract structured data from the **front side** of the Syrian orange vehicle card and return **raw JSON only** with the following exact fields:
{
"car_plate": "", // رقم المركبة الكامل مع اسم المحافظة، مأخوذ من الجهة اليسرى في السطر الأول (مثال: "155186 درعا")
"owner": "", // اسم المالك الكامل
"vin": "", // رقم الهيكل
"color": "", // اللون بالعربية أو الإنجليزية (مثال: "أبيض" أو "White")
"color_hex": "", // كود اللون بصيغة Hex (مثال: "#FFFFFF") أو #27332F إن تعذّر
"issue_date": "YYYY-MM-DD", // تاريخ المنح بصيغة ISO
"inspection_date": "YYYY-MM-DD" // تاريخ الفحص القادم بصيغة ISO
}
### Instructions & Rules:
1. Do **not** extract the "رمز المركبة" (on the right side of the first line) — use only the **left side** of the first line for `car_plate`.
2. Convert any Arabic dates (like `2024/05/13`) into ISO format `YYYY-MM-DD`.
3. If any value is missing or unreadable, return `null` for it.
4. Maintain Arabic encoding (e.g., owner name, city name, color).
5. Never guess — extract only what's visually found on the card.
6. Never include any explanation or extra output — return the JSON only.
Example of valid `car_plate`:
- "155186 درعا"
- "45291 دمشق"
- "122334 حمص"
EOT,
"vehicle_license_sy_back" => <<<EOT
You are an OCR expert for Syrian vehicle registration cards (orange card).
### TASK
Analyse the **back side** of the card and return **raw JSON only** with exactly these keys (no more, no less):
{
"make": "", // الصانع (Hyundai …)
"model": "", // الطراز (H1 …)
"year": "", // سنة الصنع بالأرقام اللاتينية (e.g. "2019")
"fuel": "", // نوع الوقود (بنزين، ديزل …) أو بالإنجليزية (Petrol, Diesel,electric)
"chassis": "" // رقم الهيكل (VIN)
}
### RULES
* Convert any Eastern-Arabic digits (٠١٢٣٤٥٦٧٨٩) to Western digits (0-9).
* Normalise color names to standard English if possible, then map to a common Hex code
• "أبيض / White" → **#FFFFFF**
• "أسود / Black" → **#000000**
• "أحمر / Red" → **#FF0000**
• "أزرق / Blue" → **#0000FF**
• … (use the closest basic colour); if no match, set **color_hex = null**.
* If any field is unreadable or absent, set its value to **null**.
* Do **NOT** include extra keys, comments, or markdown — output valid JSON only.
EOT
];
$prompt = $prompts[$type] ?? $prompts["id_front_sy"];
$apiKey = getenv("GEMINI_API_KEY");
$apiURL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-lite:generateContent?key=$apiKey";
$headers = ["Content-Type: application/json"];
$payload = [
"contents" => [
["role" => "user", "parts" => [["text" => $prompt]]],
["role" => "user", "parts" => [["inlineData" => ["mimeType" => $mimeType, "data" => $imageBase64]]]]
]
];
$ch = curl_init($apiURL);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
$response = curl_exec($ch);
if (curl_errno($ch)) {
$error_msg = curl_error($ch);
error_log("CURL error: $error_msg");
jsonError("AI Error: $error_msg");
curl_close($ch);
exit;
}
curl_close($ch);
error_log("AI raw response: $response");
$data = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
error_log("JSON decode error: " . json_last_error_msg());
jsonError("Failed to parse AI response");
exit;
}
$textRaw = $data['candidates'][0]['content']['parts'][0]['text'] ?? '';
$textRaw = trim(preg_replace('/```json|```/', '', $textRaw));
$json = json_decode($textRaw, true);
$requiredKey = match ($type) {
'id_front_sy' => 'national_number',
'id_back_sy' => 'gender',
'driving_license_sy' => 'license_type',
'vehicle_license_sy' => 'chassis',
default => null,
};
if (!$json || ($requiredKey && !isset($json[$requiredKey]))) {
error_log("AI response missing required key '$requiredKey': $textRaw");
jsonError("AI failed to extract required information");
exit;
}
printSuccess([
"image_url" => $imageUrl,
"data" => $json
]);

View File

@@ -0,0 +1,97 @@
<?php
/**
* upload_document.php
* الغرض: رفع صورة وثيقة فقط وإرجاع رابطها (بدون ذكاء صناعي)
*/
require_once __DIR__ . '/../../connect.php';
$driverId = trim((string) filterRequest("driver_id"));
$type = trim((string) filterRequest("type"));
// ✅ التحقق من الحقول الاختيارية
if ($driverId === "") { $driverId = "unknown"; }
if ($type === "") { $type = "generic"; }
// ✅ التحقق من ملف الصورة
if (!isset($_FILES['image']) || $_FILES['image']['error'] !== UPLOAD_ERR_OK) {
error_log("Upload error: Image not provided or upload failed.");
jsonError("Image upload failed");
exit;
}
$file = $_FILES['image'];
// ✅ السماح بالامتدادات الشائعة + فحص MIME الحقيقي
$allowedExt = ['jpg', 'jpeg', 'png'];
$extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($extension, $allowedExt, true)) {
error_log("Unsupported file extension: $extension");
jsonError("Unsupported file type");
exit;
}
// فحص نوع المحتوى الفعلي (أكثر أماناً)
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($file['tmp_name']) ?: 'application/octet-stream';
$allowedMime = ['image/jpeg', 'image/png'];
if (!in_array($mime, $allowedMime, true)) {
error_log("Unsupported MIME type: $mime");
jsonError("Unsupported image MIME type");
exit;
}
// (اختياري) حد أقصى للحجم 10MB
$maxBytes = 10 * 1024 * 1024;
if ($file['size'] > $maxBytes) {
error_log("Image too large: {$file['size']} bytes");
jsonError("Image too large (max 10MB)");
exit;
}
// 📁 مسارات الحفظ
$uploadDir = "../uploads/documents/";
if (!is_dir($uploadDir)) {
if (!mkdir($uploadDir, 0755, true) && !is_dir($uploadDir)) {
error_log("Failed to create upload directory: $uploadDir");
jsonError("Server error: cannot create upload directory");
exit;
}
}
$baseName = "driver_{$type}_{$driverId}";
$uniqueName = $baseName . "." . $extension;
$uploadPath = $uploadDir . $uniqueName;
// ⬆️ نقل الملف
if (!move_uploaded_file($file['tmp_name'], $uploadPath)) {
error_log("Failed to move uploaded file to $uploadPath");
jsonError("Failed to move uploaded image");
exit;
}
// 🔒 منع التنفيذ لو رُفع PHP بالخطأ
@chmod($uploadPath, 0644);
// 🌐 توليد BASE_URL آمن (يدعم ENV أو يعتمد على المضيف الحالي)
if (!defined('BASE_URL')) {
$APP_BASE_URL = rtrim(getenv('APP_BASE_URL') ?: '', '/');
if ($APP_BASE_URL === '') {
$scheme = isset($_SERVER['REQUEST_SCHEME']) ? $_SERVER['REQUEST_SCHEME'] : ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http');
$host = $_SERVER['HTTP_HOST'] ?? 'localhost';
define('BASE_URL', $scheme . '://' . $host);
} else {
define('BASE_URL', $APP_BASE_URL);
}
}
// ⚙️ مسار الرابط العام (عدّل المسار حسب نشر مشروعك)
$publicPath = "/intaleq/auth/uploads/documents/" . $uniqueName;
$imageUrl = rtrim(BASE_URL, '/') . $publicPath;
// ✅ نتيجة نهائية: فقط رابط الصورة وبعض البيانات المفيدة
printSuccess([
$imageUrl,
]);

0
auth/error_log Normal file
View File

64
auth/google_auth/callback.php Executable file
View File

@@ -0,0 +1,64 @@
<?php
// File: callback.php
// هذا الملف يستقبل الرد من جوجل بعد تسجيل المستخدم دخوله.
// يقوم بتحديث حالة الجلسة بالبيانات الصحيحة.
// 1. الإعدادات
$clientID = '1086900987150-j8brn0i5s97315kh1ej9jr72grkfqgh5.apps.googleusercontent.com';
$clientSecret = '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';
$redirectUri = 'https://api.tripz-egypt.com/tripz/auth/google_auth/callback.php';
// 2. التحقق من وجود 'code' و 'state' من جوجل
if (!isset($_GET['code']) || !isset($_GET['state'])) {
die('Invalid callback request.');
}
$authCode = $_GET['code'];
$loginToken = basename($_GET['state']); // الحماية من Path Traversal
$pollDir = __DIR__ . '/polls';
$sessionFile = $pollDir . '/' . $loginToken . '.json';
// التحقق من أن ملف الجلسة موجود
if (!file_exists($sessionFile)) {
die('Invalid or expired session.');
}
// 3. تبديل الـ code بـ access token
$tokenUrl = 'https://oauth2.googleapis.com/token';
$postData = [
'code' => $authCode,
'client_id' => $clientID,
'client_secret' => $clientSecret,
'redirect_uri' => $redirectUri,
'grant_type' => 'authorization_code'
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $tokenUrl);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$tokenData = json_decode($response, true);
if (isset($tokenData['access_token'])) {
// 4. جلب بيانات المستخدم
$userInfoUrl = 'https://www.googleapis.com/oauth2/v2/userinfo?access_token=' . $tokenData['access_token'];
$userInfoResponse = file_get_contents($userInfoUrl);
$userData = json_decode($userInfoResponse, true);
if (isset($userData['id'])) {
// 5. تحديث ملف الجلسة بالبيانات الجديدة
$finalData = [
'status' => 'success',
'userData' => $userData
];
file_put_contents($sessionFile, json_encode($finalData));
}
}
// 6. عرض صفحة نجاح للمستخدم في المتصفح
echo '<!DOCTYPE html><html><head><title>Success</title><meta name="viewport" content="width=device-width, initial-scale=1.0"></head><body style="font-family: sans-serif; text-align: center; padding-top: 50px;"><h1>Authentication Successful</h1><p>You can now return to the Tripz app.</p></body></html>';
exit();
?>

View File

@@ -0,0 +1,38 @@
<?php
// File: check_status.php
// هذا الملف الذي سيقوم التطبيق بالاتصال به بشكل دوري.
// يتحقق من حالة الجلسة ويرجع البيانات عند نجاحها.
header('Content-Type: application/json');
// 1. استقبال الـ loginToken من التطبيق
$input = json_decode(file_get_contents('php://input'), true);
if (!isset($input['loginToken'])) {
http_response_code(400);
echo json_encode(['status' => 'error', 'message' => 'Login token is missing.']);
exit();
}
$loginToken = basename($input['loginToken']); // حماية
// 2. التحقق من ملف الجلسة
$pollDir = __DIR__ . '/polls';
$sessionFile = $pollDir . '/' . $loginToken . '.json';
if (file_exists($sessionFile)) {
$sessionData = json_decode(file_get_contents($sessionFile), true);
// إذا نجحت العملية، أرجع البيانات واحذف الملف
if ($sessionData['status'] === 'success') {
echo json_encode($sessionData);
unlink($sessionFile); // حذف الملف بعد النجاح
} else {
// إذا كانت لا تزال معلقة
echo json_encode(['status' => 'pending']);
}
} else {
// إذا انتهت المهلة أو حدث خطأ
http_response_code(404);
echo json_encode(['status' => 'expired', 'message' => 'Session not found or expired.']);
}
exit();
?>

View File

@@ -0,0 +1,55 @@
<?php
$redirectUri = 'https://api.tripz-egypt.com/tripz/auth/google_auth/callback.php';
// google_auth.php
require_once __DIR__ . '/../vendor/autoload.php';
use Google\Client;
header('Content-Type: application/json');
$response = [
'success' => false,
'error' => null,
'data' => null,
];
try {
if (!isset($_POST['code'])) {
throw new Exception("Missing authorization code.");
}
$code = $_POST['code'];
$client = new Client();
$client->setClientId('1086900987150-j8brn0i5s97315kh1ej9jr72grkfqgh5.apps.googleusercontent.com');
$client->setClientSecret('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');
$client->setRedirectUri('postmessage');
$client->addScope('email');
$client->addScope('profile');
$token = $client->fetchAccessTokenWithAuthCode($code);
if (isset($token['error'])) {
throw new Exception("Access token error: " . $token['error']);
}
$client->setAccessToken($token['access_token']);
$oauth2 = new Google_Service_Oauth2($client);
$userinfo = $oauth2->userinfo->get();
$response['success'] = true;
$response['data'] = [
'id' => $userinfo->id,
'email' => $userinfo->email,
'name' => $userinfo->name,
'picture' => $userinfo->picture,
];
} catch (Exception $e) {
$response['error'] = $e->getMessage();
}
echo json_encode($response);

41
auth/google_auth/login.php Executable file
View File

@@ -0,0 +1,41 @@
<?php
// File: start_login.php
// هذا الملف يبدأ عملية تسجيل الدخول.
// يقوم بإنشاء معرف فريد ورابط تسجيل الدخول وإرسالهم للتطبيق.
// 1. الإعدادات
$clientID = '1086900987150-j8brn0i5s97315kh1ej9jr72grkfqgh5.apps.googleusercontent.com';
$redirectUri = 'https://api.tripz-egypt.com/tripz/auth/google_auth/callback.php';
$scopes = 'email profile';
// 2. إنشاء معرف فريد للجلسة (login token)
$loginToken = bin2hex(random_bytes(24));
// 3. إنشاء مجلد لتخزين الجلسات المؤقتة إذا لم يكن موجوداً
$pollDir = __DIR__ . '/polls';
if (!is_dir($pollDir)) {
mkdir($pollDir, 0775, true);
}
// 4. إنشاء ملف مؤقت لهذه الجلسة
$sessionFile = $pollDir . '/' . $loginToken . '.json';
file_put_contents($sessionFile, json_encode(['status' => 'pending']));
// 5. بناء رابط جوجل مع تمرير المعرف الفريد في متغير 'state'
$authUrl = 'https://accounts.google.com/o/oauth2/v2/auth?' . http_build_query([
'client_id' => $clientID,
'redirect_uri' => $redirectUri,
'response_type' => 'code',
'scope' => $scopes,
'access_type' => 'offline',
'state' => $loginToken // مهم جداً
]);
// 6. إرجاع الرابط والمعرف للتطبيق
header('Content-Type: application/json');
echo json_encode([
'authUrl' => $authUrl,
'loginToken' => $loginToken
]);
exit();
?>

67
auth/login.php Normal file
View File

@@ -0,0 +1,67 @@
<?php
require_once __DIR__ . '/../connect.php';
$email = filterRequest('email');
$phone = filterRequest('phone');
$password = filterRequest('password');
// Hash the password
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
$sql = "SELECT
passengers.`id`,
passengers.`phone`,
passengers.`email`,
passengers.`password`,
passengers.`gender`,
passengers.`birthdate`,
passengers.`site`,
passengers.`first_name`,
passengers.`last_name`,
passengers.`education`,
passengers.`employmentType`,
passengers.`maritalStatus`,
passengers.`created_at`,
passengers.`updated_at`,
email_verifications.verified
FROM
`passengers`
LEFT JOIN email_verifications ON email_verifications.email = passengers.email
WHERE
passengers.phone = :phone AND passengers.email = :email ";
$stmt = $con->prepare($sql);
$stmt->bindParam(':email', $email);
$stmt->bindParam(':phone', $phone);
$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$count = $stmt->rowCount();
if ($count > 0) {
$stored_password = $data[0]['password'];
if (password_verify($password, $stored_password)) {
unset($data[0]['password']);
echo json_encode([
"status" => "success",
"count" => $count,
"data" => $data
]);
} else {
// The password is incorrect
echo json_encode([
"status" => "Failure",
"data" => "Incorrect password."
]);
// jsonError("Incorrect password.");
}
} else {
// The user does not exist
echo json_encode([
"status" => "Failure",
"data" => "User does not exist."
]);
// jsonError("User does not exist.");
}
$conn->close();
?>

104
auth/loginFromGooglePassenger.php Executable file
View File

@@ -0,0 +1,104 @@
<?php
require_once __DIR__ . '/../connect.php';
// استدعاء المعاملات
$email = filterRequest('email');
$id = filterRequest('id');
$platform = filterRequest("platform") ?: 'unknown';
$appName = filterRequest("appName") ?: 'unknown';
// تشفير الإيميل لأنه يُرسل من التطبيق غير مشفّر
$email = $encryptionHelper->encryptData($email);
// تجهيز الاستعلام
$sql = "SELECT
p.`id`,
p.`phone`,
p.`email`,
p.`gender`,
p.`status`,
p.`birthdate`,
p.`site`,
p.`first_name`,
p.`last_name`,
p.`sosPhone`,
p.`education`,
p.`employmentType`,
p.`maritalStatus`,
p.`created_at`,
p.`updated_at`,
phone_verification_passenger.verified,
invitesToPassengers.isInstall,
invitesToPassengers.inviteCode,
invitesToPassengers.isGiftToken,
(SELECT `version` FROM `packageInfo` WHERE platform = :platform AND appName = :appName) AS package,
promos.promo_code AS promo,
promos.amount AS discount,
promos.validity_end_date AS validity,
t.token AS fcm_token,
t.fingerPrint AS fcm_fingerprint
FROM passengers p
LEFT JOIN phone_verification_passenger
ON phone_verification_passenger.phone_number = p.phone
LEFT JOIN invitesToPassengers
ON invitesToPassengers.inviterPassengerPhone = p.phone
LEFT JOIN promos
ON promos.passengerID = p.id
LEFT JOIN tokens t
ON t.passengerID = p.id
WHERE p.email = :email AND p.id = :id AND phone_verification_passenger.verified = '1'
LIMIT 1";
// تنفيذ الاستعلام
$stmt = $con->prepare($sql);
$stmt->bindParam(':email', $email);
$stmt->bindParam(':id', $id);
$stmt->bindParam(':appName', $appName);
$stmt->bindParam(':platform', $platform);
$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$count = $stmt->rowCount();
// تجهيز الرد
header('Content-Type: application/json');
if ($count > 0) {
foreach ($data as &$row) {
// فك تشفير الحقول الحساسة
$row['phone'] = $encryptionHelper->decryptData($row['phone']);
$row['email'] = $encryptionHelper->decryptData($row['email']);
$row['gender'] = $encryptionHelper->decryptData($row['gender']);
$row['birthdate'] = $encryptionHelper->decryptData($row['birthdate']);
$row['site'] = $encryptionHelper->decryptData($row['site']);
$row['first_name'] = $encryptionHelper->decryptData($row['first_name']);
$row['last_name'] = $encryptionHelper->decryptData($row['last_name']);
$row['sosPhone'] = $encryptionHelper->decryptData($row['sosPhone']);
$row['education'] = $encryptionHelper->decryptData($row['education']);
$row['employmentType'] = $encryptionHelper->decryptData($row['employmentType']);
$row['maritalStatus'] = $encryptionHelper->decryptData($row['maritalStatus']);
// فك تشفير توكن FCM إذا وجد
if (!empty($row['fcm_token'])) {
$row['fcm_token'] = $encryptionHelper->decryptData($row['fcm_token']);
}
}
echo json_encode([
"status" => "success",
"count" => $count,
"data" => $data
]);
} else {
error_log("User does not exist: " . $email);
echo json_encode([
"status" => "Failure",
"data" => "User does not exist."
]);
}
// تنظيف الموارد
$stmt = null;
$con = null;
exit();

88
auth/otpmessage.php Executable file
View File

@@ -0,0 +1,88 @@
<?php
require_once __DIR__ . '/../connect.php'; // Contains DB connection, filterRequest, printSuccess/Failure, encryptionHelper
$receiver = filterRequest("phone_number"); // رقم الهاتف
if (empty($receiver)) {
jsonError("Receiver phone number is required.");
exit;
}
$username = getenv('SMS_USERNAME');
$password = getenv('SMS_PASSWORD_EGYPT'); // Make sure this is the correct variable name for Egypt
$sender = getenv('SMS_SENDER');
if (!$username || !$password || !$sender) {
exit;
}
$otp = rand(10000, 99999);
$message = "Tripz app code is " . $otp;
$apiUrl = 'https://sms.kazumi.me/api/sms/send-sms';
$payload = [
'username' => $username,
'password' => $password,
'language' => 'e' , // Assuming 'e' is for English as per original
'sender' => $sender,
'receiver' => $receiver,
'message' => $message
];
$jsonPayload = json_encode($payload);
$response = callAPI("POST", $apiUrl, $jsonPayload);
if ($response && isset($response->message) && $response->message == 'Success') {
// 3. تخزين في Redis بدلاً من MySQL (أسرع وأكثر أماناً مع TTL تلقائي)
if ($redis) {
try {
$redis->setex("otp:passenger:$receiver", 300, $otp); // صلاحية 5 دقائق
jsonSuccess(null, "OTP sent and saved to Redis successfully");
} catch (Exception $e) {
error_log("Redis Error (OTP): " . $e->getMessage());
jsonError("OTP sent but failed to save in Redis");
}
} else {
jsonError("Redis service unavailable");
}
} else {
jsonError("OTP not sent (SMS API failed or invalid response)");
}
// دالة الاتصال بالـ API
function callAPI($method, $url, $data) {
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_POSTFIELDS => $data,
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Accept: application/json" // Often good to add
],
CURLOPT_TIMEOUT => 30, // Set a timeout
CURLOPT_CONNECTTIMEOUT => 10 // Set a connection timeout
]);
$api_raw_response = curl_exec($curl);
if (curl_errno($curl)) {
$curl_error_msg = curl_error($curl);
$curl_error_no = curl_errno($curl);
error_log("cURL Error (callAPI): [{$curl_error_no}] " . $curl_error_msg);
curl_close($curl);
return false; // Indicate cURL failure clearly
}
curl_close($curl);
$decoded_response = json_decode($api_raw_response);
if (json_last_error() !== JSON_ERROR_NONE) {
return null; // Indicate JSON decode failure
}
error_log("callAPI: Decoded response: " . print_r($decoded_response, true));
return $decoded_response;
}
?>

30
auth/packageInfo.php Normal file
View File

@@ -0,0 +1,30 @@
<?php
require_once __DIR__ . '/../connect.php';
$platform = filterRequest("platform");
$appName = filterRequest("appName");
$sql = "SELECT
`id`,
`platform`,
`appName`,
`createdAt`,
`version`
FROM
`packageInfo`
WHERE
platform='$platform' and appName='$appName';";
$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($stmt->rowCount() > 0) {
// Print all the records
// printData($result);
jsonSuccess($data = $result);
} else {
// Print a failure message
jsonError($message = "No records found");
}
?>

View File

View File

@@ -0,0 +1,42 @@
<?php
require_once __DIR__ . '/../../connect.php';
$phone_number = filterRequest("phone_number");
$token_code = filterRequest("token_code");
$expiration_time = filterRequest("expiration_time"); // Assuming this is a timestamp
// Check if the phone number already exists
$sql = "SELECT * FROM `phone_verification_passenger` WHERE `phone_number` = '$phone_number'";
$stmt = $con->prepare($sql);
$stmt->execute();
$rowCount = $stmt->rowCount();
if ($rowCount > 0) {
// The phone number already exists, so update the data
$sql = "UPDATE `phone_verification_passenger` SET `token_code` = '$token_code', `expiration_time` = DATE_ADD(NOW(), INTERVAL 5 MINUTE) WHERE `phone_number` = '$phone_number'";
$stmt = $con->prepare($sql);
$stmt->execute();
if ($stmt->rowCount() > 0) {
// The update was successful
jsonSuccess($message = "Phone verification data updated successfully");
} else {
// The update was unsuccessful
jsonError($message = "Failed to update phone verification data");
}
} else {
// The phone number does not exist, so insert the data
$sql = "INSERT INTO `phone_verification_passenger` (`phone_number`, `token_code`, `expiration_time`, `is_verified`, `created_at`) VALUES ('$phone_number', '$token_code', DATE_ADD(NOW(), INTERVAL 5 MINUTE), 0, NOW())";
$stmt = $con->prepare($sql);
$stmt->execute();
if ($stmt->rowCount() > 0) {
// The insertion was successful
jsonSuccess($message = "Phone verification data saved successfully");
} else {
// The insertion was unsuccessful
jsonError($message = "Failed to save phone verification data");
}
}
?>

View File

@@ -0,0 +1,28 @@
<?php
require_once __DIR__ . '/../../connect.php';
$phone_number = $encryptionHelper->encryptData(filterRequest("phone_number"));
$token_code = $encryptionHelper->encryptData(filterRequest("token"));
// error_log("phone=$phone_number, token=$token_code");
// Check if the phone number and token code match
$sql = "SELECT * FROM `phone_verification_passenger` WHERE `phone_number` = '$phone_number' AND `token` = '$token_code'
AND `verified` = 0 ";
// error_log("sql is =$sql");
$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetch();
if ($result) {
// $id = $result["id"];
$sql = "UPDATE `phone_verification_passenger` SET `verified` = 1 WHERE `phone_number` = '$phone_number'";
$stmt = $con->prepare($sql);
$stmt->execute();
jsonSuccess($message = "Your phone number has been verified.");
} else {
jsonError($message = "Your phone number could not be verified. Please try again.");
}
?>

View File

@@ -0,0 +1,30 @@
<?php
require_once __DIR__ . '/../connect.php';
$email = filterRequest("email");
$headers = "MIME-Version: 1.0" . "\r\n";
$headers .= "Content-type: text/html; charset=UTF-8" . "\r\n";
$headers .= "From: SEFER Team" . "\r\n";
// Create the email subject and body
$subject = 'Your SEFER account has been deleted';
$body = '
Dear passenger,
We are sorry to see you go, but we respect your decision to delete your SEFER account.
We would like to thank you for using our platform and for being a part of the SEFER community. We hope that you had a positive experience and that we were able to make your travels easier and more enjoyable.
If you have any questions or concerns, please do not hesitate to contact us.
Sincerely,
The SEFER Team
';
// Send the email
mail($email, $subject, $body);
?>

0
auth/resetPassword.php Normal file
View File

34
auth/sendEmail.php Executable file
View File

@@ -0,0 +1,34 @@
<?php
require_once __DIR__ . '/../connect.php';
$email = filterRequest("email");
$token = filterRequest("token");
$admin='support@sefer.live';
$headers = "MIME-Version: 1.0" . "\r\n";
$headers .= "Content-type: text/html; charset=UTF-8" . "\r\n";
$headers .= "From: $admin" . "\r\n";
$subject = "Verify your email address";
$bodyEmail = "
<html>
<head>
<title>Verify your email address</title>
</head>
<body>
<p>Hi [$email],</p>
<p>We recently received a request to verify your email address for your account on SEFER App.</p>
<p>To verify your email address, please write this to app .</p>
$token
<p>If you did not request to verify your email address, please ignore this email.</p>
<p>Thank you,</p>
SEFER Team.
</body>
</html>
";
mail($email, $subject, $bodyEmail, $headers);

72
auth/sendVerifyEmail.php Normal file
View File

@@ -0,0 +1,72 @@
<?php
require_once __DIR__ . '/../connect.php';
$email = filterRequest("email");
$token = filterRequest("token");
$sql = "SELECT * FROM `email_verifications` WHERE `email` = '$email'";
$stmt = $con->prepare($sql);
$stmt->execute();
$rowCount = $stmt->rowCount();
$admin='support@mobile-app.store';
$headers = "MIME-Version: 1.0" . "\r\n";
$headers .= "Content-type: text/html; charset=UTF-8" . "\r\n";
$headers .= "From: $admin" . "\r\n";
$subject = "Verify your email address";
$bodyEmail = "
<html>
<head>
<title>Verify your email address</title>
</head>
<body>
<p>Hi [$email],</p>
<p>We recently received a request to verify your email address for your account on SEFER App.</p>
<p>To verify your email address, please write this to app .</p>
$token
<p>If you did not request to verify your email address, please ignore this email.</p>
<p>Thank you,</p>
SEFER Team.
</body>
</html>
";
if ($rowCount > 0) {
// The email already exists, so update the data
$sql = "UPDATE `email_verifications` SET `token` = '$token' WHERE `email` = '$email'";
$stmt = $con->prepare($sql);
$stmt->execute();
if ($stmt->rowCount() > 0) {
// The update was successful
jsonSuccess($message = "Email verification data updated successfully");
mail($email, $subject, $bodyEmail, $headers);
} else {
// The update was unsuccessful
jsonError($message = "Failed to update email verification data");
}
} else {
// The email does not exist, so insert the data
$sql = "INSERT INTO `email_verifications` (`email`, `token`) VALUES ('$email', '$token')";
$stmt = $con->prepare($sql);
$stmt->execute();
if ($stmt->rowCount() > 0) {
// The insertion was successful
jsonSuccess($message = "Email verification data saved successfully");
mail($email, $subject, $bodyEmail, $headers);
} else {
// The insertion was unsuccessful
jsonError($message = "Failed to save email verification data");
}
}
?>

70
auth/signup.php Normal file
View File

@@ -0,0 +1,70 @@
<?php
$allowRegistration = true;
require_once __DIR__ . '/../connect.php';
// جلب البيانات من المستخدم
$phone = filterRequest("phone");
$email = filterRequest("email");
$first_name = filterRequest("first_name");
$last_name = filterRequest("last_name");
$password = filterRequest("password");
$gender = filterRequest("gender");
$birthdate = filterRequest("birthdate");
$site = filterRequest("site");
$id = filterRequest("id");
// تشفير البيانات الحساسة
$phone = $encryptionHelper->encryptData($phone);
$email = $encryptionHelper->encryptData($email);
$gender = $encryptionHelper->encryptData($gender);
$birthdate = $encryptionHelper->encryptData($birthdate);
$site = $encryptionHelper->encryptData($site);
$first_name = $encryptionHelper->encryptData($first_name);
$last_name = $encryptionHelper->encryptData($last_name);
// تشفير الباسورد
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
try {
// التحقق من وجود الإيميل أو رقم الهاتف مسبقًا
$sql = "SELECT * FROM passengers WHERE phone = :phone OR email = :email";
$stmt = $con->prepare($sql);
$stmt->bindParam(":phone", $phone);
$stmt->bindParam(":email", $email);
$stmt->execute();
$results = $stmt->fetchAll();
if (count($results) > 0) {
jsonError("The email or phone number is already registered.");
exit;
}
// إدخال البيانات الجديدة
$sql = "INSERT INTO passengers (
id, phone, email, password, gender, birthdate, site, first_name, last_name
) VALUES (
:id, :phone, :email, :password, :gender, :birthdate, :site, :first_name, :last_name
)";
$stmt = $con->prepare($sql);
$stmt->bindParam(":id", $id);
$stmt->bindParam(":phone", $phone);
$stmt->bindParam(":email", $email);
$stmt->bindParam(":password", $hashedPassword);
$stmt->bindParam(":gender", $gender);
$stmt->bindParam(":birthdate", $birthdate);
$stmt->bindParam(":site", $site);
$stmt->bindParam(":first_name", $first_name);
$stmt->bindParam(":last_name", $last_name);
$stmt->execute();
if ($stmt->rowCount() > 0) {
jsonSuccess(null, "success to save passenger data");
} else {
jsonError("Failed to save passenger data");
}
} catch (PDOException $e) {
error_log("Database Error: " . $e->getMessage());
jsonError("An error occurred while saving the data.");
}
?>

0
auth/sms/error_log Normal file
View File

28
auth/sms/getSender.php Normal file
View File

@@ -0,0 +1,28 @@
<?php
require_once __DIR__ . '/../../connect.php';
$sql = "SELECT
*
FROM
`smsSender`
WHERE
id = '1'";
$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($stmt->rowCount() > 0) {
jsonSuccess($data = $result);
} else {
jsonError($message = "No driver order data found");
}
?>

View File

@@ -0,0 +1,68 @@
<?php
require_once __DIR__ . '/../../connect.php';
// استقبال رقم الهاتف
$phone = filterRequest('phone');
$language = filterRequest('lang') ?? 'r';
// 1⃣ جلب بيانات API من البيئة
$username = "Sefer";
$password = getenv("SMS_PASSWORD_EGYPT");
$apiEndpoint = getenv("SMS_API_ENDPOINT");
$sender = "SEFER";
$appName = "Tripz";
if (!$password || !$apiEndpoint) {
jsonError("API configuration is missing");
exit;
}
// 2⃣ توليد كود OTP من السيرفر
$otp = rand(100000, 999999);
// 3⃣ تشفير البيانات قبل تخزينها
$phoneEncrypted = $encryptionHelper->encryptData($phone);
$otpEncrypted = $encryptionHelper->encryptData($otp);
// 4⃣ تخزين OTP في قاعدة البيانات
try {
$insertOtp = "INSERT INTO otp_verification_fingerPrint (phone, otp) VALUES (?, ?)";
$stmt = $con->prepare($insertOtp);
$stmt->execute([$phoneEncrypted, $otpEncrypted]);
} catch (PDOException $e) {
error_log("DB Insert Error: " . $e->getMessage());
jsonError("Failed to save OTP to the database");
exit;
}
// 5⃣ إرسال الرسالة عبر API
$message = "$appName app code is $otp\ncopy it to app";
$payload = json_encode([
"username" => $username,
"password" => $password,
"message" => $message,
"language" => $language,
"sender" => $sender,
"receiver" => $phone
]);
$ch = curl_init($apiEndpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// 6⃣ التحقق من نجاح الإرسال
if ($httpCode != 200) {
error_log("SMS API Failed. HTTP Code: $httpCode. Response: " . $response);
jsonError("Failed to send OTP SMS");
exit;
}
// 7⃣ إرجاع النتيجة
jsonSuccess(["message" => "OTP sent successfully"]);
?>

View File

@@ -0,0 +1,27 @@
<?php
// Include the database connection file
require_once __DIR__ . '/../../connect.php';
// Filter and encrypt the phone number input
$phone_number = filterRequest("phone_number");
$phone_number = $encryptionHelper->encryptData($phone_number);
// Prepare the SQL query to verify the phone
$sql = "UPDATE phone_verification SET is_verified = 1 WHERE phone_number = :phone_number";
// Prepare the statement
$stmt = $con->prepare($sql);
$stmt->bindParam(":phone_number", $phone_number);
// Execute the query
$stmt->execute();
$affectedRows = $stmt->rowCount();
// Check if the update was successful
if ($affectedRows > 0) {
jsonSuccess(["message" => "Phone number verified successfully"]);
} else {
jsonError("No phone number found or verification failed");
}
?>

View File

@@ -0,0 +1,23 @@
<?php
require_once __DIR__ . '/../../connect.php';
// استقبال وتشفير رقم الهاتف
$phone_number = filterRequest("phone_number");
$phone_number = $encryptionHelper->encryptData($phone_number);
// تنفيذ الاستعلام
$sql = "UPDATE phone_verification_passenger SET verified = 1 WHERE phone_number = :phone_number";
$stmt = $con->prepare($sql);
$stmt->bindParam(":phone_number", $phone_number);
$stmt->execute();
$affectedRows = $stmt->rowCount();
// إرجاع النتيجة
if ($affectedRows > 0) {
jsonSuccess(["message" => "Phone number verified successfully"]);
} else {
jsonError("No phone number found or verification failed");
}
?>

View File

View File

@@ -0,0 +1,134 @@
<?php
// تضمين ملف الاتصال بقاعدة البيانات والدوال المساعدة
require_once __DIR__ . '/../../connect.php';
// include "functions.php"; // افترض أن دالة filterRequest موجودة هنا
// --- بداية التعديل: استخدام واجهة RaseelPlus API ---
// توليد رمز تحقق عشوائي مكون من 5 أرقام
$otp = rand(10000, 99999);
// استقبال رقم الهاتف من الطلب
// تأكد من أن دالة filterRequest تقوم بتنقية المدخلات بشكل آمن
$receiver = filterRequest("receiver");
// رسالة الـ OTP. يمكنك تخصيصها حسب الحاجة
// تذكر أن التطبيق اسمه Tripz-egypt.com
$messageBody = "Your verification code for Tripz is: " . $otp;
// عنوان API الجديد
$apiUrl = 'https://raseelplus.com/api/send';
// بيانات الطلب (Payload) الجديدة لتتوافق مع RaseelPlus
$payload = [
"number" => $receiver, // رقم المستلم
"type" => "text",
"message" => $messageBody,
"instance_id" => "6863C59A7AFBD", // المعرف المأخوذ من مثال cURL
"access_token"=> "68617b9b8fe53" // مفتاح الوصول المأخوذ من مثال cURL
];
error_log("Sending OTP to $receiver via RaseelPlus. Message: $messageBody");
// استدعاء الـ API
$response = callAPI("POST", $apiUrl, json_encode($payload));
error_log("RaseelPlus API Response: " . print_r($response, true));
// --- نهاية التعديل ---
// التحقق من الاستجابة من الـ API
// ملاحظة: قد تحتاج إلى تعديل هذا الشرط بناءً على شكل الاستجابة الفعلي من RaseelPlus
// نفترض هنا أن الاستجابة الناجحة تحتوي على "status":"success" أو شيء مشابه
if ($response && !isset($response->error) && (isset($response->status) && $response->status == 'success' || isset($response->message))) {
// تحديد وقت انتهاء صلاحية الرمز (بعد 5 دقائق)
$expiration_time = date('Y-m-d H:i:s', strtotime('+5 minutes'));
$created_at = date('Y-m-d H:i:s');
error_log("API call successful. Saving to DB: phone=$receiver, token=$otp, expires=$expiration_time");
try {
// تشفير البيانات قبل حفظها (ممارسة أمنية جيدة)
// $receiver_encrypted = $encryptionHelper->encryptData($receiver);
// $otp_encrypted = $encryptionHelper->encryptData($otp);
// استخدام البيانات غير المشفرة مؤقتاً إذا لم تكن تستخدم التشفير حالياً
$receiver_to_db = $receiver;
$otp_to_db = $otp;
$stmt = $con->prepare("
INSERT INTO phone_verification_passenger
(phone_number, token, expiration_time, verified, created_at)
VALUES (?, ?, ?, 0, ?)
");
$success = $stmt->execute([$receiver_to_db, $otp_to_db, $expiration_time, $created_at]);
if ($success) {
error_log("OTP saved successfully to DB.");
// jsonSuccess() هي دالة مخصصة لديك لطباعة استجابة نجاح
jsonSuccess(null, 'OTP sent and saved successfully');
} else {
error_log("SQL execution failed.");
// jsonError() هي دالة مخصصة لديك لطباعة استجابة فشل
jsonError('OTP sent but failed to save to database');
}
} catch (PDOException $e) {
error_log("Database Error: " . $e->getMessage());
jsonError('Database error occurred');
}
} else {
// فشل إرسال الـ OTP
$errorMessage = isset($response->message) ? $response->message : "Unknown error";
error_log("Failed to send OTP. API response: " . $errorMessage);
jsonError('Failed to send OTP: ' . $errorMessage);
}
/**
* دالة لإجراء استدعاءات API باستخدام cURL
* @param string $method نوع الطلب (e.g., "POST", "GET")
* @param string $url عنوان URL للـ API
* @param mixed $data البيانات المراد إرسالها
* @return mixed الاستجابة من الـ API بعد فك تشفير JSON
*/
function callAPI($method, $url, $data)
{
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true, // إرجاع الاستجابة كنص بدلاً من طباعتها
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30, // مهلة زمنية للطلب
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_POSTFIELDS => $data,
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Accept: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
error_log("cURL Error #: " . $err);
return null; // إرجاع null في حالة وجود خطأ في cURL
} else {
return json_decode($response); // فك تشفير استجابة JSON
}
}
// مثال على دالة طباعة النجاح (ضعها في ملف functions.php)
?>

View File

@@ -0,0 +1,97 @@
<?php
require_once __DIR__ . '/../../connect.php';
$text='444';
$encryptedText = $encryptionHelper->encryptData($text);
$username = getenv('SMS_USERNAME');
$password = getenv('SMS_PASSWORD_EGYPT');
$sender = getenv('SMS_SENDER');
$language = filterRequest("language");
$receiver = filterRequest("receiver");
$otp = rand(10000, 99999);
$message0 = "Tripz app code is " . $otp;
$apiUrl = 'https://sms.kazumi.me/api/sms/send-sms';
$payload = [
'username' => $username,
'password' => $password,
'language' => $language,
'sender' => $sender,
'receiver' => $receiver,
'message' => $message0
];
error_log("Sending SMS to $receiver with OTP: $otp");
$response = callAPI("POST", $apiUrl, json_encode($payload));
error_log("API Response: " . print_r($response, true));
// التحقق من رسالة الاستجابة
if ($response && isset($response->message) && $response->message == "Success") {
$expiration_time = date('Y-m-d H:i:s', strtotime('+5 minutes'));
$created_at = date('Y-m-d H:i:s');
error_log("Saving to DB: phone=$receiver, token=$otp, expires=$expiration_time");
try {
$receiver1=$encryptionHelper->encryptData($receiver);
$otp1=$encryptionHelper->encryptData($otp);
$stmt = $con->prepare("
INSERT INTO phone_verification_passenger
(phone_number, token, expiration_time, verified, created_at)
VALUES (?, ?, ?, 0, ?)
");
$success = $stmt->execute([$receiver1, $otp1, $expiration_time, $created_at]);
if ($success) {
error_log("OTP saved successfully to DB.");
jsonSuccess(null, 'OTP sent and saved successfully');
} else {
error_log("SQL execution failed.");
jsonError('OTP sent but not saved to database');
}
} catch (PDOException $e) {
error_log("Database Error: " . $e->getMessage());
jsonError('Database error');
}
} else {
error_log("OTP not sent. API response did not indicate success. Response: " . print_r($response, true));
jsonError('OTP not sent');
}
// دالة التعامل مع API
function callAPI($method, $url, $data)
{
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_POSTFIELDS => $data,
CURLOPT_HTTPHEADER => ["Content-Type: application/json"]
]);
$response = curl_exec($curl);
if (curl_errno($curl)) {
error_log("cURL Error: " . curl_error($curl));
}
curl_close($curl);
return json_decode($response);
}
?>

75
auth/syria/auth_proxy.php Executable file
View File

@@ -0,0 +1,75 @@
<?php
// Start a session to store state and tokens.
session_start();
// 1. SETUP: Install the Google API Client Library
// Run this command in your project directory: composer require google/apiclient:^2.0
require_once __DIR__ . '/vendor/autoload.php';
// 2. CONFIGURATION: Replace with your credentials from Google Cloud Console
$clientID = '1086900987150-j8brn0i5s97315kh1ej9jr72grkfqgh5.apps.googleusercontent.com'; // Replace with your Client ID
$clientSecret = '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'; // Replace with your Client Secret
// This must be the exact URL of this script.
$redirectUri = 'https://api.tripz-egypt.com/tripz/auth/syria/auth_proxy.php'; // Replace with your script's URL
// 3. APP CONFIGURATION: Your Flutter app's custom URI scheme
// This is how the browser will redirect back to your app.
$appRedirectScheme = 'intaleqapp://auth'; // e.g., myapp://auth
// Create a new Google Client object
$client = new Google_Client();
$client->setClientId($clientID);
$client->setClientSecret($clientSecret);
$client->setRedirectUri($redirectUri);
$client->addScope("email");
$client->addScope("profile");
// 4. LOGIC: Handle the authentication flow
if (isset($_GET['code'])) {
// A. User has been redirected back from Google with an authorization code.
try {
// Exchange the authorization code for an access token.
$token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
if (isset($token['error'])) {
// Handle error from Google
throw new Exception('Error fetching access token: ' . $token['error_description']);
}
$client->setAccessToken($token['access_token']);
// Get user profile information from Google.
$google_oauth = new Google_Service_Oauth2($client);
$google_account_info = $google_oauth->userinfo->get();
$id = $google_account_info->id;
$email = $google_account_info->email;
$name = $google_account_info->name;
$picture = $google_account_info->picture;
// B. Redirect back to the Flutter app with the user data in the URL.
// We use urlencode to ensure data is passed correctly.
$redirectUrl = $appRedirectScheme .
'?status=success' .
'&id=' . urlencode($id) .
'&email=' . urlencode($email) .
'&name=' . urlencode($name) .
'&picture=' . urlencode($picture);
header('Location: ' . $redirectUrl);
exit();
} catch (Exception $e) {
// C. Handle any errors and redirect back to the app with an error status.
$error_message = urlencode($e->getMessage());
header('Location: ' . $appRedirectScheme . '?status=error&message=' . $error_message);
exit();
}
} else {
// D. This is the initial request from the Flutter app.
// Redirect the user to Google's OAuth 2.0 server for authentication.
$authUrl = $client->createAuthUrl();
header('Location: ' . $authUrl);
exit();
}
?>

View File

@@ -0,0 +1,85 @@
<?php
/**
* delete_old_serial_docs.php
* يحذف صور الوثائق الأقدم من مدة محددة (افتراضي 48 ساعة) من private_uploads
* ضع الملف بجانب upload_serial_document.php ليستخدم نفس الشجرة.
*/
date_default_timezone_set('Asia/Damascus');
// === الإعدادات ===
// نفس ما في upload_serial_document.php:
const UPLOAD_ROOT = __DIR__ . "/../../private_uploads";
const ALLOWED_EXTS = ['jpg','png','webp'];
// المدة قبل الحذف (ثواني): افتراضي يومين، ويمكن تمريرها عبر CLI
$ttlSeconds = 2 * 24 * 60 * 60; // 48 ساعة
if (PHP_SAPI === 'cli' && isset($argv[1]) && ctype_digit($argv[1])) {
$ttlSeconds = (int)$argv[1];
}
// ملف لوج اختياري
$logFile = __DIR__ . '/delete_old_serial_docs.log';
$log = @fopen($logFile, 'ab');
// دالة بسيطة للّوج
$logln = function(string $msg) use ($log) {
$line = '[' . date('Y-m-d H:i:s') . '] ' . $msg . PHP_EOL;
if ($log) @fwrite($log, $line);
};
// تحقّق أن مجلد الرفع صحيح وموجود
$root = realpath(UPLOAD_ROOT);
if ($root === false || !is_dir($root)) {
$logln("❌ UPLOAD_ROOT not found: " . UPLOAD_ROOT);
exit(1);
}
$logln("===== Start cleanup in: {$root} | TTL={$ttlSeconds}s =====");
// مُكرّر آمن عبر RecursiveIterator
$it = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($root, FilesystemIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST
);
$now = time();
$deleted = 0;
$checked = 0;
// اسم الملف المتوقع: driverId__docType.ext
$docTypes = [
'driver_license_front','driver_license_back',
'car_license_front','car_license_back',
];
$docTypesRegex = implode('|', array_map('preg_quote', $docTypes));
foreach ($it as $node) {
if (!$node->isFile()) continue;
$checked++;
$path = $node->getPathname();
$ext = strtolower($node->getExtension());
// فلترة الامتدادات
if (!in_array($ext, ALLOWED_EXTS, true)) continue;
// فلترة اسم الملف (حماية من حذف ملفات أخرى)
$name = $node->getBasename();
if (!preg_match('/^[A-Za-z0-9_-]+__(' . $docTypesRegex . ')\.(jpg|png|webp)$/i', $name)) {
continue;
}
$age = $now - $node->getMTime();
if ($age >= $ttlSeconds) {
if (@unlink($path)) {
$deleted++;
$logln("🗑 Deleted: {$path} | age=" . round($age/3600, 1) . "h");
} else {
$logln("⚠️ Failed to delete: {$path}");
}
}
}
$logln("Done. checked={$checked}, deleted={$deleted}");
if ($log) @fclose($log);

View File

@@ -0,0 +1,49 @@
<?php
require_once __DIR__ . '/../../../connect.php';
$driverId = filterRequest("id");
if (empty($driverId)) {
jsonError("driver_id is required.");
exit;
}
try {
// تفاصيل السائق
$sql = "SELECT * FROM driver WHERE id = :id LIMIT 1";
$stmt = $con->prepare($sql);
$stmt->execute([':id' => $driverId]);
$driver = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$driver) {
jsonError("Driver not found.");
exit;
}
// فك التشفير للحقول الحساسة
foreach ($driver as $k => $v) {
if (in_array($k, ['phone',
'email',
'first_name',
'last_name',
'national_number',
'address','gender','site',
'birthdate',
'name_arabic'])) {
$driver[$k] = $encryptionHelper->decryptData($v);
}
}
// الوثائق
$sql2 = "SELECT doc_type, image_name, link FROM driver_documents WHERE driverID = :id";
$stmt2 = $con->prepare($sql2);
$stmt2->execute([':id' => $driverId]);
$docs = $stmt2->fetchAll(PDO::FETCH_ASSOC);
printSuccess([
"driver" => $driver,
"documents" => $docs
]);
} catch (PDOException $e) {
jsonError("Error: " . $e->getMessage());
}

View File

@@ -0,0 +1,20 @@
<?php
require_once __DIR__ . '/../../../connect.php';
try {
$sql = "SELECT id, first_name,last_name, phone FROM driver WHERE status <> 'active' ORDER BY id DESC";
$stmt = $con->prepare($sql);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
// فك التشفير
foreach ($rows as &$r) {
$r['phone'] = $encryptionHelper->decryptData($r['phone']);
$r['first_name'] = $encryptionHelper->decryptData($r['first_name']);
$r['last_name'] = $encryptionHelper->decryptData($r['last_name']);
}
jsonSuccess($rows); // يرجع كـ message: [...]
} catch (PDOException $e) {
jsonError("Error: " . $e->getMessage());
}

View File

@@ -0,0 +1,26 @@
<?php
require_once __DIR__ . '/../../../connect.php';
$phoneNumber = filterRequest("phone_number");
// تشفير الرقم قبل البحث
$phoneNumber_encrypted = $encryptionHelper->encryptData($phoneNumber);
try {
// الاستعلام عن السائق حسب رقم الهاتف وحالة التحقق
$stmt = $con->prepare("
SELECT * FROM phone_verification
WHERE phone_number = ? AND is_verified = 1
");
$stmt->execute([$phoneNumber_encrypted]);
$driver = $stmt->fetch(PDO::FETCH_ASSOC);
if ($driver) {
jsonSuccess(null, "Phone number is verified.");
} else {
jsonError("Phone number is not verified or does not exist.");
}
} catch (PDOException $e) {
jsonError("Database error: " . $e->getMessage());
}

View File

@@ -0,0 +1,391 @@
<?php
/**
* Endpoint: register_driver_and_car.php
* [MODIFIED] Added vehicle_category_id and fuel_type_id support.
* [MODIFIED] Fixed birthdate logic: Append -01-01 BEFORE encryption.
* [MODIFIED] Added Syrian phone number formatting logic.
*/
//register_driver_and_car.php
$allowRegistration = true;
require_once __DIR__ . '/../../../connect.php';
header('Content-Type: application/json; charset=utf-8');
try {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
jsonError("Invalid method.");
exit;
}
/* ================== General Settings ================== */
$PUBLIC_BASE = "https://intaleq.xyz/driver_docs";
/* ================== 1) Input Fields ================== */
$raw_first_name = null;
$raw_last_name = null;
$required = ["phone", "password", "first_name", "last_name"];
$optional = [
"id","email","gender","license_type","national_number",
"name_arabic","issue_date","expiry_date","license_categories",
"address","licenseIssueDate","status","birthdate","site",
"employmentType","maritalStatus","fullNameMaritial","expirationDate"
];
$carRequired = [
"vin","car_plate","make","model","year","expiration_date",
"color","owner","color_hex","fuel"
];
// حقول اختيارية للسيارة (التصنيف والوقود الرقمي)
// vehicle_category_id, fuel_type_id
$docKeys = [
'driver_license_front',
'driver_license_back',
'car_license_front',
'car_license_back'
];
// Read driver fields
$data = [];
foreach ($required as $f) {
$v = filterRequest($f);
if ($v === null || $v === '') {
jsonError("Missing required field: $f");
exit;
}
$data[$f] = $v;
if ($f === 'first_name') $raw_first_name = $v;
if ($f === 'last_name') $raw_last_name = $v;
}
foreach ($optional as $f) {
$v = filterRequest($f);
$data[$f] = ($v === null || $v === '' || $v === 'Not specified') ? null : $v;
}
/* ================== 🟢 START PHONE FORMATTING LOGIC 🟢 ================== */
if (!empty($data['phone'])) {
$phone = $data['phone'];
// 1. إزالة المسافات والرموز
$phone = preg_replace('/[ \-\(\)\+]/', '', $phone);
$phone = trim($phone);
// 2. توحيد البادئات الدولية
if (strpos($phone, '00963') === 0) {
$phone = substr($phone, 2);
} elseif (strpos($phone, '0963') === 0) {
$phone = substr($phone, 1);
}
// 3. معالجة الحالات الخاصة بالصفر الزائد بعد الرمز الدولي
if (strpos($phone, '96309') === 0) {
$phone = '9639' . substr($phone, 5);
}
elseif (strpos($phone, '9630') === 0) {
$phone = '9639' . substr($phone, 4);
}
// 4. معالجة الأرقام المحلية
elseif (strpos($phone, '09') === 0) {
$phone = '963' . substr($phone, 1);
}
elseif (strpos($phone, '9') === 0 && strlen($phone) == 9) {
$phone = '963' . $phone;
}
elseif (strpos($phone, '0') === 0 && strlen($phone) == 10) {
$phone = '963' . substr($phone, 1);
}
// 5. التأكد من وجود 9 بعد الرمز الدولي
if (strpos($phone, '963') === 0 && strlen($phone) > 3) {
if (strpos($phone, '9639') !== 0) {
$phone = '9639' . substr($phone, 3);
}
}
$data['phone'] = $phone;
}
/* ================== 🔴 END PHONE FORMATTING LOGIC 🔴 ================== */
// تجهيز تاريخ الميلاد قبل التشفير
if (!empty($data['birthdate'])) {
$data['birthdate'] = trim($data['birthdate']);
$data['birthdate'] = $data['birthdate'] . '-01-01';
} else {
$data['birthdate'] = '1970-01-01';
}
// Read car fields
$car = [];
foreach ($carRequired as $f) {
$v = filterRequest($f);
if ($v === null || $v === '') {
jsonError("Missing required field: $f");
exit;
}
$car[$f] = $v;
}
// Read document links
$docUrls = [];
foreach ($docKeys as $k) {
$u = filterRequest($k);
if ($u === null || $u === '') {
jsonError("Missing document URL: $k");
exit;
}
if (!filter_var($u, FILTER_VALIDATE_URL)) {
jsonError("Invalid document URL: $k");
exit;
}
$docUrls[$k] = $u;
}
/* ================== 2) Generate default id/email ================== */
if (empty($data['id'])) {
$data['id'] = 'DRV' . date('YmdHis') . random_int(1000, 9999);
}
if ($data['email'] === null) {
$data['email'] = $data['phone'] . '@intaleqapp.com';
}
/* ================== 3) Encrypt sensitive fields ================== */
$toEncryptDriver = [
"phone","email","first_name","last_name","name_arabic","gender",
"national_number","address","site","fullNameMaritial","birthdate"
];
foreach ($toEncryptDriver as $f) {
if (!empty($data[$f])) {
$data[$f] = $encryptionHelper->encryptData($data[$f]);
}
}
// Encrypt car sensitive data
$car['vin'] = $encryptionHelper->encryptData($car['vin']);
$car['car_plate'] = $encryptionHelper->encryptData($car['car_plate']);
$car['owner'] = $encryptionHelper->encryptData($car['owner']);
/* ================== 4) Hash password (HMAC + password_hash) ================== */
// نقرأ الـ HMAC key من env
$pepper = getenv('SECRET_KEY_HMAC');
// نبني baseString من أكثر من بارامتر
// هنا نستخدم id + phone (بعد ما طبّقنا منطق تنسيق الهاتف)
$baseParts = [
$data['id'],
$data['phone'],
];
// نضيف رقم وطني أو سنة الميلاد إن توفروا (كما في الـ migration)
if (!empty($data['national_number'])) {
$baseParts[] = $data['national_number'];
} elseif (!empty($data['birthdate'])) {
// birthdate حالياً أصبح بصيغة YYYY-01-01
$year = substr($data['birthdate'], 0, 4);
if (preg_match('/^\d{4}$/', $year)) {
$baseParts[] = $year;
}
}
$baseString = implode('|', $baseParts);
// نشتق السر الخام باستخدام HMAC-SHA256 مع SECRET_KEY_HMAC
$rawSecret = hash_hmac('sha256', $baseString, $pepper, true);
// نخزّن فقط الهاش الناتج من password_hash في قاعدة البيانات
$pwdHashed = password_hash($rawSecret, PASSWORD_DEFAULT);
/* ================== 5) Start transaction ================== */
$con->beginTransaction();
/* ================== 6) Check duplicate ================== */
$dup = $con->prepare("SELECT id FROM driver WHERE phone = :p OR email = :e");
$dup->execute([':p' => $data['phone'], ':e' => $data['email']]);
if ($dup->rowCount() > 0) {
$con->rollBack();
jsonError("Phone or email already registered.");
exit;
}
/* ================== 7) Insert Driver ================== */
$sqlDriver = "
INSERT INTO driver (
id, phone, email, password, gender, license_type, national_number,
name_arabic, issue_date, expiry_date, license_categories,
address, licenseIssueDate, status, birthdate, site,
first_name, last_name, accountBank, bankCode,
employmentType, maritalStatus, fullNameMaritial, expirationDate,
created_at, updated_at
) VALUES (
:id, :phone, :email, :pwd, :gender, :license_type, :national_number,
:name_arabic, :issue_date, :expiry_date, :license_categories,
:address, :licenseIssueDate, :status, :birthdate, :site,
:first_name, :last_name, :accountBank, :bankCode,
:employmentType, :maritalStatus, :fullNameMaritial, :expirationDate,
NOW(), NOW()
)
";
$insD = $con->prepare($sqlDriver);
$okD = $insD->execute([
':id' => $data['id'],
':phone' => $data['phone'],
':email' => $data['email'],
':pwd' => $pwdHashed,
':gender' => !empty($data['gender']) ? $data['gender'] : 'Male',
':license_type' => !empty($data['license_type']) ? $data['license_type'] : 'yet',
':national_number' => $data['national_number'],
':name_arabic' => $data['name_arabic'],
':issue_date' => !empty($data['issue_date']) ? $data['issue_date'] : '2020-01-01',
':expiry_date' => !empty($data['expiry_date']) ? $data['expiry_date'] : 'yet',
':license_categories' => !empty($data['license_categories']) ? $data['license_categories'] : 'B',
':address' => $data['address'],
':licenseIssueDate' => !empty($data['licenseIssueDate']) ? $data['licenseIssueDate'] : '2020-01-01',
':status' => !empty($data['status']) ? $data['status'] : 'yet',
':birthdate' => $data['birthdate'],
':site' => !empty($data['site']) ? $data['site'] : 'demascus',
':first_name' => $data['first_name'],
':last_name' => $data['last_name'],
':accountBank' => 'yet',
':bankCode' => 'yet',
':employmentType' => !empty($data['employmentType']) ? $data['employmentType'] : 'yet',
':maritalStatus' => !empty($data['maritalStatus']) ? $data['maritalStatus'] : 'yet',
':fullNameMaritial' => !empty($data['fullNameMaritial']) ? $data['fullNameMaritial'] : 'yet',
':expirationDate' => !empty($data['expirationDate']) ? $data['expirationDate'] : 'yet',
]);
if (!$okD) {
$con->rollBack();
jsonError("Failed to insert driver.");
exit;
}
$driverID = $data['id'];
/* ================== 8) Insert Vehicle ================== */
// ✅ استقبال القيم الجديدة (التصنيف والوقود) مع تعيين افتراضي 1
$vCatID = filterRequest("vehicle_category_id");
$vCatID = ($vCatID !== null && $vCatID !== '') ? $vCatID : 1; // 1 = Car
$fTypeID = filterRequest("fuel_type_id");
$fTypeID = ($fTypeID !== null && $fTypeID !== '') ? $fTypeID : 1; // 1 = Petrol
$hasCar = $con->prepare("SELECT 1 FROM CarRegistration WHERE driverID = :d LIMIT 1");
$hasCar->execute([':d' => $driverID]);
$isDefault = $hasCar->rowCount() === 0 ? 1 : 0;
$sqlCar = "
INSERT INTO CarRegistration (
driverID, vin, car_plate, make, model, year, expiration_date,
color, owner, color_hex, fuel,
vehicle_category_id, fuel_type_id,
isDefault, created_at, status
) VALUES (
:driverID, :vin, :car_plate, :make, :model, :year, :expiration_date,
:color, :owner, :color_hex, :fuel,
:vehicle_category_id, :fuel_type_id,
:isDefault, NOW(), 'yet'
)
";
$insC = $con->prepare($sqlCar);
$okC = $insC->execute([
':driverID' => $driverID,
':vin' => $car['vin'],
':car_plate' => $car['car_plate'],
':make' => $car['make'],
':model' => $car['model'],
':year' => $car['year'],
':expiration_date' => $car['expiration_date'],
':color' => $car['color'],
':owner' => $car['owner'],
':color_hex' => $car['color_hex'],
':fuel' => $car['fuel'], // النص القديم (للتوافق)
':vehicle_category_id' => $vCatID, // ✅ العمود الجديد
':fuel_type_id' => $fTypeID, // ✅ العمود الجديد
':isDefault' => $isDefault,
]);
if (!$okC) {
$con->rollBack();
jsonError("Failed to insert car registration.");
exit;
}
$carRegID = $con->lastInsertId();
/* ================== 9) Store document links ================== */
$insDoc = $con->prepare("
INSERT INTO driver_documents (driverID, doc_type, image_name, link, upload_date)
VALUES (:driverID, :doc_type, :image_name, :link, NOW())
");
foreach ($docKeys as $k) {
$url = $docUrls[$k];
$name = basename(parse_url($url, PHP_URL_PATH) ?? '');
if ($name === '') { $name = $k . '_' . time() . '.jpg'; }
$insDoc->execute([
':driverID' => $driverID,
':doc_type' => $k,
':image_name' => $name,
':link' => $url,
]);
}
/* ================== 10) Commit ================== */
$con->commit();
/* ================== 11) Notification ================== */
try {
$fcmSendUrl = 'https://api.intaleq.xyz/intaleq/ride/firebase/send_fcm.php';
$driverFullName = $raw_first_name . ' ' . $raw_last_name;
$notificationTitle = 'تسجيل سائق جديد';
$notificationBody = "سائق جديد ($driverFullName) سجل برقم ID: $driverID وهو بانتظار المراجعة والتفعيل.";
$notificationPayload = json_encode([
'target' => 'service',
'title' => $notificationTitle,
'body' => $notificationBody,
'isTopic' => true,
'category' => 'new_driver_registration'
]);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $fcmSendUrl);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json; charset=UTF-8']);
curl_setopt($ch, CURLOPT_POSTFIELDS, $notificationPayload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_exec($ch);
curl_close($ch);
} catch (Exception $notifyEx) {
error_log("register_driver_and_car NOTIFY ERROR: " . $notifyEx->getMessage());
}
printSuccess([
'status' => 'success',
'driverID' => $driverID,
'carRegID' => $carRegID,
'documents' => $docUrls
]);
} catch (Exception $e) {
if (isset($con) && $con instanceof PDO && $con->inTransaction()) {
$con->rollBack();
}
error_log("register_driver_and_car ERROR: " . $e->getMessage());
jsonError("Server error: " . $e->getMessage());
} catch (PDOException $e) {
if (isset($con) && $con instanceof PDO && $con->inTransaction()) {
$con->rollBack();
}
error_log("register_driver_and_car PDO: " . $e->getMessage());
jsonError("Database error.");
}
?>

View File

@@ -0,0 +1,303 @@
<?php
/**
* Endpoint: register_driver_and_car.php (نسخة محدثة)
* Method: POST (multipart/form-data أو x-www-form-urlencoded)
* الوظيفة: إنشاء سائق + تسجيل مركبة + حفظ روابط الوثائق الموقّعة (من السيرفر السوري)
* ملاحظة: لا نتلقّى ملفات هنا. نتلقى فقط روابط secure_image.php الموقّعة.
*/
$allowRegistration = true;
require_once __DIR__ . '/../../../connect.php';
header('Content-Type: application/json; charset=utf-8');
try {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
jsonError("Invalid method.");
exit;
}
/* ========== إعدادات عامة ========== */
// الدومينات المسموح بها للروابط الموقّعة (السيرفر السوري)
$ALLOWED_SIGNED_HOSTS = [
'syria.intaleq.xyz', // عدّل حسب بيئتك
'applink.syria', // مثال آخر إن كان لديك دومين إضافي
];
// توثيق شكل الروابط: secure_image.php?driver_id=...&doc_type=...&ext=jpg|png|webp&expires=...&signature=...
$allowedDocTypes = [
'driver_license_front',
'driver_license_back',
'car_license_front',
'car_license_back',
];
$allowedExts = ['jpg','png','webp'];
/* ========== 1) جلب الحقول ========== */
$required = ["phone", "password", "first_name", "last_name"];
$optional = [
"id","email","gender","license_type","national_number",
"name_arabic","issue_date","expiry_date","license_categories",
"address","licenseIssueDate","status","birthdate","site",
"employmentType","maritalStatus","fullNameMaritial","expirationDate"
];
// حقول السيارة (مطلوبة)
$carRequired = [
"vin","car_plate","make","model","year","expiration_date",
"color","owner","color_hex","fuel"
];
// روابط الوثائق (مطلوبة)
$docUrlKeys = [
'driver_license_front_url',
'driver_license_back_url',
'car_license_front_url',
'car_license_back_url'
];
$data = [];
foreach ($required as $f) {
$v = filterRequest($f);
if ($v === null || $v === '') {
jsonError("Missing required field: $f");
exit;
}
$data[$f] = $v;
}
foreach ($optional as $f) {
$v = filterRequest($f);
$data[$f] = ($v === null || $v === '' || $v === 'Not specified') ? null : $v;
}
$car = [];
foreach ($carRequired as $f) {
$v = filterRequest($f);
if ($v === null || $v === '') {
jsonError("Missing required field: $f");
exit;
}
$car[$f] = $v;
}
$docUrls = [];
foreach ($docUrlKeys as $k) {
$v = filterRequest($k);
if ($v === null || trim($v) === '') {
jsonError("Missing signed URL: $k");
exit;
}
$docUrls[$k] = trim($v);
}
/* ========== 2) توليد id إذا مفقود + بناء email افتراضي إن لزم ========== */
if (empty($data['id'])) {
$data['id'] = 'DRV' . date('YmdHis') . random_int(1000, 9999);
}
if ($data['email'] === null) {
$data['email'] = $data['phone'] . '@intaleqapp.com';
}
$driverID = $data['id'];
/* ========== 3) تشفير الحقول الحساسة ========== */
$toEncryptDriver = [
"phone","email","first_name","last_name","name_arabic","gender",
"national_number","address","site","fullNameMaritial"
];
foreach ($toEncryptDriver as $f) {
if (!empty($data[$f])) {
$data[$f] = $encryptionHelper->encryptData($data[$f]);
}
}
// حساسات السيارة
$car['vin'] = $encryptionHelper->encryptData($car['vin']);
$car['car_plate'] = $encryptionHelper->encryptData($car['car_plate']);
$car['owner'] = $encryptionHelper->encryptData($car['owner']);
/* ========== 4) هَش كلمة المرور ========== */
$pwdHashed = password_hash(filterRequest('password'), PASSWORD_DEFAULT);
/* ========== 5) بدء معاملة ========== */
$con->beginTransaction();
/* ========== 6) فحص تكرار هاتف/ايميل (المشفّرين) ========== */
$dup = $con->prepare("SELECT id FROM driver WHERE phone = :p OR email = :e");
$dup->execute([':p' => $data['phone'], ':e' => $data['email']]);
if ($dup->rowCount() > 0) {
$con->rollBack();
jsonError("Phone or email already registered.");
exit;
}
/* ========== 7) إدراج السائق ========== */
$sqlDriver = "
INSERT INTO driver (
id, phone, email, password, gender, license_type, national_number,
name_arabic, issue_date, expiry_date, license_categories,
address, licenseIssueDate, status, birthdate, site,
first_name, last_name, accountBank, bankCode,
employmentType, maritalStatus, fullNameMaritial, expirationDate,
created_at, updated_at
) VALUES (
:id, :phone, :email, :pwd, :gender, :license_type, :national_number,
:name_arabic, :issue_date, :expiry_date, :license_categories,
:address, :licenseIssueDate, :status, :birthdate, :site,
:first_name, :last_name, :accountBank, :bankCode,
:employmentType, :maritalStatus, :fullNameMaritial, :expirationDate,
NOW(), NOW()
)
";
$insD = $con->prepare($sqlDriver);
$okD = $insD->execute([
':id' => $driverID,
':phone' => $data['phone'],
':email' => $data['email'],
':pwd' => $pwdHashed,
':gender' => $data['gender'],
':license_type' => $data['license_type'],
':national_number' => $data['national_number'],
':name_arabic' => $data['name_arabic'],
':issue_date' => $data['issue_date'],
':expiry_date' => $data['expiry_date'],
':license_categories'=> !empty($data['license_categories']) ? $data['license_categories'] : 'B',
':address' => $data['address'],
':licenseIssueDate' => $data['licenseIssueDate'],
':status' => !empty($data['status']) ? $data['status'] : 'yet',
':birthdate' => $data['birthdate'],
':site' => $data['site'],
':first_name' => $data['first_name'],
':last_name' => $data['last_name'],
':accountBank' => 'yet',
':bankCode' => 'yet',
':employmentType' => !empty($data['employmentType']) ? $data['employmentType'] : 'yet',
':maritalStatus' => !empty($data['maritalStatus']) ? $data['maritalStatus'] : 'yet',
':fullNameMaritial' => !empty($data['fullNameMaritial']) ? $data['fullNameMaritial'] : 'yet',
':expirationDate' => !empty($data['expirationDate']) ? $data['expirationDate'] : 'yet',
]);
if (!$okD) { $con->rollBack(); jsonError("Failed to insert driver."); exit; }
/* ========== 8) إدراج السيارة ========== */
$hasCar = $con->prepare("SELECT 1 FROM CarRegistration WHERE driverID = :d LIMIT 1");
$hasCar->execute([':d' => $driverID]);
$isDefault = $hasCar->rowCount() === 0 ? 1 : 0;
$sqlCar = "
INSERT INTO CarRegistration (
driverID, vin, car_plate, make, model, year, expiration_date,
color, owner, color_hex, fuel, isDefault, created_at, status
) VALUES (
:driverID, :vin, :car_plate, :make, :model, :year, :expiration_date,
:color, :owner, :color_hex, :fuel, :isDefault, NOW(), 'yet'
)
";
$insC = $con->prepare($sqlCar);
$okC = $insC->execute([
':driverID' => $driverID,
':vin' => $car['vin'],
':car_plate' => $car['car_plate'],
':make' => $car['make'],
':model' => $car['model'],
':year' => $car['year'],
':expiration_date' => $car['expiration_date'],
':color' => $car['color'],
':owner' => $car['owner'],
':color_hex' => $car['color_hex'],
':fuel' => $car['fuel'],
':isDefault' => $isDefault,
]);
if (!$okC) { $con->rollBack(); jsonError("Failed to insert car registration."); exit; }
$carRegID = $con->lastInsertId();
/* ========== 9) التحقّق من الروابط الموقّعة وحفظها ========== */
// دالة مساعدة تتحقّق من شكل الرابط وتستخرج doc_type/ext
$validateSignedUrl = function(string $url) use ($allowedDocTypes, $allowedExts) {
$parts = parse_url($url);
if (!$parts || empty($parts['scheme']) || empty($parts['host']) || empty($parts['path'])) {
throw new Exception("Invalid URL format.");
}
if (!in_array($parts['host'], $ALLOWED_SIGNED_HOSTS, true)) {
throw new Exception("URL host not allowed: {$parts['host']}");
}
if (stripos($parts['path'], 'secure_image.php') === false) {
throw new Exception("URL path not allowed.");
}
if (empty($parts['query'])) {
throw new Exception("URL missing query string.");
}
parse_str($parts['query'], $q);
foreach (['driver_id','doc_type','ext','expires','signature'] as $k) {
if (empty($q[$k])) throw new Exception("URL missing param: $k");
}
if (!in_array($q['doc_type'], $allowedDocTypes, true)) {
throw new Exception("Invalid doc_type in URL.");
}
if (!in_array(strtolower($q['ext']), $allowedExts, true)) {
throw new Exception("Invalid ext in URL.");
}
return [
'doc_type' => $q['doc_type'],
'ext' => strtolower($q['ext']),
// بإمكانك التحقق من driver_id = $driverID إذا تحب تربطهما
'driver_id_in_url' => $q['driver_id'],
];
};
$docsToInsert = []; // [['doc_type'=>..., 'link'=>..., 'image_name'=>...], ...]
foreach ($docUrlKeys as $k) {
$link = $docUrls[$k];
$meta = $validateSignedUrl($link);
// image_name ليس ضروريًا هنا (الرابط موقّع إلى بوابة قراءة)، احفظ doc_type + link فقط
$docsToInsert[] = [
'doc_type' => $meta['doc_type'], // يجب أن يتطابق مع $k منطقيًا
'link' => $link,
'image_name' => $meta['doc_type'] . '.' . $meta['ext'], // اسماً رمزياً فقط
];
}
// إدراج في driver_documents
// CREATE TABLE driver_documents (
// id INT AUTO_INCREMENT PRIMARY KEY,
// driverID VARCHAR(64) NOT NULL,
// doc_type VARCHAR(64) NOT NULL,
// image_name VARCHAR(255) NULL,
// link VARCHAR(1024) NOT NULL,
// upload_date DATETIME NOT NULL,
// INDEX(driverID)
// ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
$insDoc = $con->prepare("
INSERT INTO driver_documents (driverID, doc_type, image_name, link, upload_date)
VALUES (:driverID, :doc_type, :image_name, :link, NOW())
");
foreach ($docsToInsert as $row) {
$insDoc->execute([
':driverID' => $driverID,
':doc_type' => $row['doc_type'],
':image_name' => $row['image_name'],
':link' => $row['link'],
]);
}
/* ========== 10) إنهاء المعاملة ========== */
$con->commit();
printSuccess([
'driverID' => $driverID,
'carRegID' => $carRegID,
'documents' => [
'driver_license_front_url' => $docUrls['driver_license_front_url'],
'driver_license_back_url' => $docUrls['driver_license_back_url'],
'car_license_front_url' => $docUrls['car_license_front_url'],
'car_license_back_url' => $docUrls['car_license_back_url'],
]
]);
} catch (Exception $e) {
if (isset($con) && $con->inTransaction()) { $con->rollBack(); }
error_log("register_driver_and_car ERROR: " . $e->getMessage());
jsonError("Server error: " . $e->getMessage());
} catch (PDOException $e) {
if (isset($con) && $con->inTransaction()) { $con->rollBack(); }
error_log("register_driver_and_car PDO: " . $e->getMessage());
jsonError("Database error.");
}

View File

@@ -0,0 +1,69 @@
<?php
require_once __DIR__ . '/../../../connect.php';
//sendWhatsAppDriver.php
error_log("--- [send_otp_driver.php] Started ---");
/**
* فحص البلاك ليست (خاصة بالسائقين)
* - يشفّر الهاتف الخام ويبحث عنه في جدول blacklist_driver
*/
function is_blacklisted_driver(PDO $con, $encryptionHelper, string $phone): bool {
$raw = trim($phone);
$enc_raw = $encryptionHelper->encryptData($raw);
$sql = "SELECT 1 FROM blacklist_driver WHERE phone = :ph LIMIT 1";
$q = $con->prepare($sql);
$q->execute(['ph' => $enc_raw]);
return (bool)$q->fetchColumn();
}
/* 0) استقبل الرقم وتحقق من البلاك ليست */
$receiver = filterRequest("receiver");
if (!$receiver) {
jsonError('Phone number is required.');
error_log("[send_otp_driver.php] Error: phone empty");
exit();
}
if (is_blacklisted_driver($con, $encryptionHelper, $receiver)) {
jsonError('This driver is blacklisted and cannot receive OTP.');
error_log("[send_otp_driver.php] BLOCKED (blacklisted): $receiver");
exit();
}
/* 1) توليد الـ OTP */
$otp = rand(10000, 99999);
$messageBody = "Your verification code for Intaleq is: " . $otp;
/* 🟢 2) تخطي الإرسال الفعلي */
error_log("[send_otp_driver.php] Skipping actual WhatsApp send. OTP for $receiver: $otp");
/* 3) حفظ الـ OTP في قاعدة البيانات */
$receiver_enc = $encryptionHelper->encryptData($receiver);
$otp_enc = $encryptionHelper->encryptData($otp);
$exp = date('Y-m-d H:i:s', strtotime('+5 minutes'));
$now = date('Y-m-d H:i:s');
try {
// حذف أي رموز سابقة لنفس الرقم
$con->prepare("DELETE FROM phone_verification WHERE phone_number = ?")
->execute([$receiver_enc]);
$stmt = $con->prepare("
INSERT INTO phone_verification
(phone_number, token_code, expiration_time, is_verified, created_at)
VALUES (?, ?, ?, 0, ?)
");
$stmt->execute([$receiver_enc, $otp_enc, $exp, $now]);
jsonSuccess(null, 'OTP generated and saved successfully (no message sent)');
error_log("[send_otp_driver.php] OTP saved for driver $receiver");
} catch (PDOException $e) {
error_log("[send_otp_driver.php] DB error: ".$e->getMessage());
jsonError('OTP generated but failed to save to database');
}
?>

69
auth/syria/driver/verifyOtp.php Executable file
View File

@@ -0,0 +1,69 @@
<?php
require_once __DIR__ . '/../../../connect.php';
$phoneNumber = filterRequest("phone_number");
$email = $phoneNumber . '@intaleqapp.com';
error_log("📥 [verifyOtp.php] Received phone number: $phoneNumber");
// 🔐 تشفير البيانات
$phoneNumber_encrypted = $encryptionHelper->encryptData($phoneNumber);
$email_encrypted = $encryptionHelper->encryptData($email);
try {
// 🧹 حذف أي رموز قديمة لنفس الرقم
$con->prepare("DELETE FROM phone_verification WHERE phone_number = ?")
->execute([$phoneNumber_encrypted]);
// 🧾 توليد driverID فريد
$raw = $phoneNumber;
$driverID = substr(md5($raw), 2, 20);
// 🔐 توليد رمز تجريبي (بدون OTP حقيقي لتجنب Null)
$dummyToken = $encryptionHelper->encryptData('AUTO');
// 🕒 الوقت الحالي
$now = date('Y-m-d H:i:s');
// ✅ إدخال سجل تحقق مباشر
$stmt = $con->prepare("
INSERT INTO phone_verification
(phone_number, token_code, email, driverId, expiration_time, is_verified, created_at)
VALUES (?, ?, ?, ?, NULL, 1, ?)
");
$stmt->execute([$phoneNumber_encrypted, $dummyToken, $email_encrypted, $driverID, $now]);
error_log("✅ [verifyOtp.php] Auto verification record inserted successfully for $phoneNumber");
// 🔍 التحقق إذا السائق موجود مسبقاً
$checkDriverStmt = $con->prepare("SELECT * FROM driver WHERE phone = ?");
$checkDriverStmt->execute([$phoneNumber_encrypted]);
$driver = $checkDriverStmt->fetch(PDO::FETCH_ASSOC);
if ($driver) {
error_log("👤 [verifyOtp.php] Driver already registered. Returning driver info.");
printSuccess([
"message" => "Driver already registered.",
"isRegistered" => true,
"driver" => [
"id" => $driver['id'],
"first_name" => $encryptionHelper->decryptData($driver['first_name']),
"last_name" => $encryptionHelper->decryptData($driver['last_name']),
"email" => $encryptionHelper->decryptData($driver['email']),
"phone" => $phoneNumber
]
]);
} else {
error_log("🆕 [verifyOtp.php] Phone verified automatically. Driver not found.");
printSuccess([
"message" => "Phone number verified automatically (no OTP required).",
"isRegistered" => false,
"driverID" => $driverID
]);
}
} catch (PDOException $e) {
error_log("💥 [verifyOtp.php] PDO ERROR: " . $e->getMessage());
jsonError("Database error: " . $e->getMessage());
}
?>

155
auth/syria/register_passenger.php Executable file
View File

@@ -0,0 +1,155 @@
<?php
// File: register_passenger.php
// إعدادات إظهار الأخطاء
ini_set('display_errors', 0);
error_reporting(E_ALL);
$allowRegistration = true;
require_once __DIR__ . '/../../connect.php';
// تعريف بادئة للوج (Tag) لسهولة البحث عنها في ملف الأخطاء
$logTag = "[Register_Debug_passenger]";
$step = 0;
try {
// ======================================================
// Step 1: استقبال البيانات
// ======================================================
$step = 1;
$phoneNumber = filterRequest("phone_number");
$firstName = filterRequest("first_name");
$lastName = filterRequest("last_name");
$email = filterRequest("email");
// طباعة وصول البيانات (مع إخفاء جزء من الرقم)
error_log("$logTag Step 1: Received request. Phone: " . substr($phoneNumber, 0, 7) . "*****");
// ======================================================
// Step 2: التحقق من المدخلات
// ======================================================
$step = 2;
if (empty($phoneNumber) || empty($firstName) || empty($lastName)) {
error_log("$logTag Step 2 Error: Missing required fields.");
jsonError("Required fields are missing.");
exit();
}
// ======================================================
// Step 3: معالجة الإيميل
// ======================================================
$step = 3;
if (empty($email)) {
$email = $phoneNumber . '@intaleqapp.com';
error_log("$logTag Step 3: Email was empty, generated default: " . substr($email, 0, 5) . "***");
}
// ======================================================
// Step 4: تشفير البيانات
// ======================================================
$step = 4;
error_log("$logTag Step 4: Encrypting data...");
if (!isset($encryptionHelper)) {
throw new Exception("Encryption Helper class is missing.");
}
$phoneNumber_encrypted = $encryptionHelper->encryptData($phoneNumber);
$firstName_encrypted = $encryptionHelper->encryptData($firstName);
$lastName_encrypted = $encryptionHelper->encryptData($lastName);
$email_encrypted = $encryptionHelper->encryptData($email);
$password_hashed = password_hash($email, PASSWORD_DEFAULT);
$unknown_encrypted = $encryptionHelper->encryptData("unknown yet");
// ======================================================
// Step 5: إنشاء ID فريد
// ======================================================
$step = 5;
// $uniqueId = substr(md5(uniqid(mt_rand(), true)), 0, 20);
$uniqueId = substr(md5($phoneNumber_encrypted), 0, 20);
error_log("$logTag Step 5: Generated Unique ID: $uniqueId");
// ======================================================
// Step 6: التحقق من وجود المستخدم (Database Check)
// ======================================================
$step = 6;
$checkStmt = $con->prepare("SELECT id FROM passengers WHERE phone = ?");
$checkStmt->execute([$phoneNumber_encrypted]);
if ($checkStmt->rowCount() > 0) {
error_log("$logTag Step 6 Error: User already exists.");
jsonError("User with this phone number or email already exists.");
exit();
}
// ======================================================
// Step 7: الإضافة (Insert User)
// ======================================================
$step = 7;
error_log("$logTag Step 7: Inserting into passengers table...");
$insertStmt = $con->prepare("
INSERT INTO passengers (id, first_name, last_name, email, phone, password, gender, birthdate, site, sosPhone, education, employmentType, maritalStatus, status, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'active', NOW(), NOW())
");
$success = $insertStmt->execute([
$uniqueId,
$firstName_encrypted,
$lastName_encrypted,
$email_encrypted,
$phoneNumber_encrypted,
$password_hashed,
$unknown_encrypted,
$unknown_encrypted,
$unknown_encrypted,
$unknown_encrypted,
$unknown_encrypted,
$unknown_encrypted,
$unknown_encrypted
]);
if (!$success) {
$errorInfo = $insertStmt->errorInfo();
// طباعة تفاصيل خطأ الـ SQL في اللوج
error_log("$logTag Step 7 Error: SQL Insert Failed. Details: " . json_encode($errorInfo));
jsonError("Failed to create user account.");
exit();
}
// ======================================================
// Step 9: جلب البيانات لإعادتها
// ======================================================
$step = 9;
$userStmt = $con->prepare("SELECT * FROM passengers WHERE id = ?");
$userStmt->execute([$uniqueId]);
$newUser = $userStmt->fetch(PDO::FETCH_ASSOC);
// ======================================================
// Step 10: فك التشفير وإرسال الرد
// ======================================================
$step = 10;
if ($newUser) {
unset($newUser['password']);
foreach ($newUser as $key => &$value) {
if ($key !== 'id' && $key !== 'status' && $key !== 'created_at' && $key !== 'updated_at' && !is_null($value)) {
$value = $encryptionHelper->decryptData($value);
}
}
}
error_log("$logTag Success: User registered successfully.");
jsonSuccess(["status" => "registration_success", "data" => $newUser]);
} catch (PDOException $e) {
// طباعة خطأ قاعدة البيانات في اللوج
error_log("$logTag PDO Exception at Step $step: " . $e->getMessage());
jsonError("Database Error.");
} catch (Exception $e) {
// طباعة الأخطاء العامة في اللوج
error_log("$logTag General Exception at Step $step: " . $e->getMessage());
jsonError("General Error.");
}
?>

72
auth/syria/secure_image.php Executable file
View File

@@ -0,0 +1,72 @@
<?php
// File: secure_image.php
// يعرض الملف فقط إذا كان الرابط موقّع وصالح زمنياً.
// يعتمد نفس الثوابت/المسارات في upload_serial_document.php
require_once __DIR__ . '/../../connect.php';
const UPLOAD_ROOT = __DIR__ . "/../../private_uploads";
const SIGN_SECRET = getenv('SECRET_KEY_HMAC'); // نفس المفتاح
// استلام المعطيات من الرابط
$driverId = $_GET['driver_id'] ?? '';
$docType = $_GET['doc_type'] ?? '';
$extShort = $_GET['ext'] ?? '';
$expires = $_GET['expires'] ?? '';
$signature= $_GET['signature'] ?? '';
if ($driverId === '' || $docType === '' || $extShort === '' || $expires === '' || $signature === '') {
http_response_code(400); echo "Missing parameters."; exit;
}
// صلاحية الوقت
if ((int)$expires < time()) {
http_response_code(403); echo "Link expired."; exit;
}
// تحقق من doc_type
$allowedDocTypes = [
'driver_license_front',
'driver_license_back',
'car_license_front',
'car_license_back',
];
if (!in_array($docType, $allowedDocTypes, true)) {
http_response_code(403); echo "Invalid doc_type."; exit;
}
// تحقق من الامتداد
$allowedExts = ['jpg','png','webp'];
if (!in_array($extShort, $allowedExts, true)) {
http_response_code(403); echo "Invalid ext."; exit;
}
// إعادة توليد التوقيع للمقارنة
$driverIdSafe = preg_replace('/[^A-Za-z0-9_\-]/', '_', $driverId);
$message = $driverIdSafe . ':' . $docType . ':' . $extShort . ':' . $expires;
$expected = hash_hmac('sha256', $message, SIGN_SECRET);
if (!hash_equals($expected, $signature)) {
http_response_code(403); echo "Invalid signature."; exit;
}
// بناء المسار
$h = hash('sha1', $driverIdSafe);
$subdir = substr($h, 0, 2) . '/' . substr($h, 2, 2);
$serverName = "{$driverIdSafe}__{$docType}.{$extShort}";
$path = UPLOAD_ROOT . '/' . $subdir . '/' . $serverName;
if (!is_file($path)) {
http_response_code(404); echo "File not found."; exit;
}
// تحديد النوع
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($path) ?: 'application/octet-stream';
header('Content-Type: ' . $mime);
header('Content-Length: ' . filesize($path));
header('X-Content-Type-Options: nosniff');
// (اختياري) اطلب توكن وصول إضافي عبر Authorization للتحكم الأدق.
// مثال: تحقق من $_SERVER['HTTP_AUTHORIZATION'] هنا إن أردت.
readfile($path);

197
auth/syria/sendWhatsOpt.php Executable file
View File

@@ -0,0 +1,197 @@
<?php
$allowRegistration = true;
require_once __DIR__ . '/../../connect.php';
error_log("--- [send_otp_pass.php] Started ---");
/* Helpers */
function normalize_phone($s) { return preg_replace('/\D+/', '', (string)$s); }
/**
* Check blacklist by encrypted phone
*/
function is_blacklisted(PDO $con, $encryptionHelper, string $phone): bool {
$raw = trim($phone);
$norm = normalize_phone($raw);
$enc_raw = $encryptionHelper->encryptData($raw);
$enc_norm = $encryptionHelper->encryptData($norm);
$sql = "SELECT 1
FROM passenger_blacklist
WHERE phone IN (:enc_raw, :enc_norm)
AND (expires_at IS NULL OR expires_at > NOW())
LIMIT 1";
$q = $con->prepare($sql);
$q->execute([
'enc_raw' => $enc_raw,
'enc_norm' => $enc_norm,
]);
return (bool)$q->fetchColumn();
}
/* 0) Get phone number */
$receiver = filterRequest("receiver");
if (!$receiver) {
jsonError('Phone number is required.');
exit();
}
if (is_blacklisted($con, $encryptionHelper, $receiver)) {
jsonError('This phone is blacklisted and cannot receive OTP.');
error_log("[send_otp] BLOCKED (blacklisted): $receiver");
exit();
}
/* 1) Generate OTP */
$otp = rand(10000, 99999);
$messageBody = "Your verification code for Intaleq is: " . $otp;
/* 🟢 2) Skip sending and log instead */
error_log("[send_otp] Skipping actual send. OTP generated for $receiver: $otp");
/* 3) Save OTP (encrypted) */
$receiver_enc = $encryptionHelper->encryptData($receiver);
$otp_enc = $encryptionHelper->encryptData($otp);
$exp = date('Y-m-d H:i:s', strtotime('+5 minutes'));
$now = date('Y-m-d H:i:s');
try {
$con->prepare("DELETE FROM phone_verification_passenger WHERE phone_number = ?")
->execute([$receiver_enc]);
$stmt = $con->prepare("
INSERT INTO phone_verification_passenger
(phone_number, token, expiration_time, verified, created_at)
VALUES (?, ?, ?, 0, ?)
");
$stmt->execute([$receiver_enc, $otp_enc, $exp, $now]);
jsonSuccess(null, 'OTP generated and saved successfully (no message sent)');
error_log("[send_otp] OTP saved successfully for $receiver");
} catch (PDOException $e) {
error_log("[send_otp] DB error: ".$e->getMessage());
jsonError('OTP generated but failed to save to database');
}
/*
require_once __DIR__ . '/../../connect.php';
error_log("--- [send_otp.php] Started ---");
function normalize_phone($s) { return preg_replace('/\D+/', '', (string)$s); }
function is_blacklisted(PDO $con, $encryptionHelper, string $phone): bool {
$raw = trim($phone);
$norm = normalize_phone($raw);
// شَفِّر قبل السؤال
$enc_raw = $encryptionHelper->encryptData($raw);
$enc_norm = $encryptionHelper->encryptData($norm);
$sql = "SELECT 1
FROM passenger_blacklist
WHERE phone IN (:enc_raw, :enc_norm)
AND (expires_at IS NULL OR expires_at > NOW())
LIMIT 1";
$q = $con->prepare($sql);
$q->execute([
'enc_raw' => $enc_raw,
'enc_norm' => $enc_norm,
]);
return (bool)$q->fetchColumn();
}
$receiver = filterRequest("receiver");
if (!$receiver) { jsonError('Phone number is required.'); exit(); }
if (is_blacklisted($con, $encryptionHelper, $receiver)) {
jsonError('This phone is blacklisted and cannot receive OTP.');
error_log("[send_otp] BLOCKED (blacklisted): $receiver");
exit();
}
$otp = rand(10000, 99999);
$messageBody = "Your verification code for Intaleq is: " . $otp;
function normalize($raw) {
if (is_string($raw)) return json_decode($raw, true) ?: [];
if ($raw instanceof stdClass) return (array)$raw;
return is_array($raw) ? $raw : [];
}
$response = normalize(sendWhatsAppFromServer($receiver, $messageBody));
$sentOK = $response['success'] ?? false;
if (!$sentOK) {
error_log("[send_otp] WA-Server failed ⇒ ".(($response['message'] ?? null) ?: json_encode($response)));
$payload = [
"number" => $receiver,
"type" => "text",
"message" => $messageBody,
"instance_id" => getenv("RASEEL_DRIVER_INSTANCE_ID"),
"access_token" => getenv("RASEEL_DRIVER_ACCESS_TOKEN")
];
$response = callAPI("POST", "https://raseelplus.com/api/send", json_encode($payload));
$response = normalize($response);
$sentOK = ($response['status'] ?? '') === 'success';
if (!$sentOK) {
error_log("[send_otp] RaseelPlus failed ⇒ ".json_encode($response));
jsonError('Failed to send OTP: '.($response['message'] ?? 'Unknown error'));
exit();
}
}
$receiver_enc = $encryptionHelper->encryptData($receiver); // الهاتف المُرسل (خام) مُشفّر
$otp_enc = $encryptionHelper->encryptData($otp);
$exp = date('Y-m-d H:i:s', strtotime('+5 minutes'));
$now = date('Y-m-d H:i:s');
try {
$con->prepare("DELETE FROM phone_verification_passenger WHERE phone_number = ?")
->execute([$receiver_enc]);
$stmt = $con->prepare("
INSERT INTO phone_verification_passenger
(phone_number, token, expiration_time, verified, created_at)
VALUES (?, ?, ?, 0, ?)
");
$stmt->execute([$receiver_enc, $otp_enc, $exp, $now]);
jsonSuccess(null, 'OTP sent and saved successfully');
error_log("[send_otp] OTP saved for $receiver");
} catch (PDOException $e) {
error_log("[send_otp] DB error: ".$e->getMessage());
jsonError('OTP sent but failed to save to database');
}
function callAPI($method, $url, $data) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_POSTFIELDS => $data,
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"Accept: application/json"
],
]);
$body = curl_exec($ch);
$err = curl_error($ch);
curl_close($ch);
return $err ? [] : json_decode($body, true);
}
*/

52
auth/syria/send_survey.php Executable file
View File

@@ -0,0 +1,52 @@
<?php
require_once __DIR__ . '/../../connect.php';
$receiver = filterRequest("receiver");
if (!$receiver) {
jsonError("رقم الهاتف مفقود");
exit;
}
// توليد تأخير عشوائي بين 45 و 90 ثانية
$delay = rand(45, 90);
sleep($delay);
// رسالة الاستطلاع مع أزرار
$surveyMessage = [
"type" => "buttons",
"header" => [
"type" => "text",
"text" => "استطلاع رأي سريع 🌟"
],
"body" => [
"text" => "هل كانت تجربة التسجيل في تطبيق *انطلق* سهلة بالنسبة لك؟\n\n👇 اضغط أحد الخيارات:"
],
"footer" => [
"text" => "للتواصل: +962 7XXXXXXX - رابط التطبيق: https://intaleq.xyz"
],
"buttons" => [
[
"type" => "reply",
"reply" => [
"id" => "feedback_yes",
"title" => "👍 نعم"
]
],
[
"type" => "reply",
"reply" => [
"id" => "feedback_no",
"title" => "👎 لا"
]
]
]
];
// استدعاء الدالة لإرسال الرسالة
$response = sendWhatsAppFromServer($receiver, $surveyMessage);
if ($response && isset($response["status"]) && $response["status"] === "sent") {
jsonSuccess(null, "تم إرسال استطلاع الرأي بنجاح بعد $delay ثانية.");
} else {
jsonError("فشل في إرسال استطلاع الرأي");
}
?>

129
auth/syria/uploadSyrianDocs.php Executable file
View File

@@ -0,0 +1,129 @@
<?php
// File: upload_serial_document.php
// يرفع صورة وثيقة إلى مسار خاص (خارج الويب العام) ويُرجع Signed URL مؤقّت.
// بيئتك
require_once __DIR__ . '/../../connect.php'; // يجب أن يوفّر: $con (اختياري) + printSuccess/printFailure + filterRequest
// --------- إعدادات ---------
const MAX_FILE_MB = 5;
const ALLOWED_MIMES = ['image/jpeg','image/png','image/webp']; // فقط صور
const UPLOAD_ROOT = __DIR__ . "/../../private_uploads"; // مجلد خاص (غير عام)
const SIGN_SECRET = getenv('SECRET_KEY_HMAC'); // غيّرها واقرأها من .env
const PUBLIC_BASE = 'https://syria.intaleq.xyz/intaleq'; // الدومين العلني
const SIGNED_TTL_SEC = 172800; // 2 days = 60*60*24
// أنشئ مجلد الرفع إن لم يكن موجودًا
if (!is_dir(UPLOAD_ROOT)) { @mkdir(UPLOAD_ROOT, 0700, true); }
// (اختياري) هيدرز أمان
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
$hmacHeader = $_SERVER['HTTP_X_HMAC_AUTH'] ?? '';
// TODO: تحقّق حسب منطقك إن أردت فرض المصادقة هنا.
// --------- حقول مطلوبة من Flutter عبر filterRequest ---------
$driverId = filterRequest('driver_id');
$docType = filterRequest('doc_type');
$purpose = filterRequest('purpose'); // اختياري
if (empty($driverId) || empty($docType)) {
jsonError("driver_id and doc_type are required.");
exit;
}
// اسمح فقط بقيم محددة للوثائق
$allowedDocTypes = [
'driver_license_front',
'driver_license_back',
'car_license_front',
'car_license_back',
];
if (!in_array($docType, $allowedDocTypes, true)) {
jsonError("Invalid doc_type.");
exit;
}
// --------- التحقق من الملف ---------
if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
jsonError("No file uploaded or upload error.");
exit;
}
$tmpPath = $_FILES['file']['tmp_name'];
$origName = $_FILES['file']['name'] ?? 'upload.bin';
$size = filesize($tmpPath);
if ($size === false || $size <= 0) {
jsonError("Invalid file size."); exit;
}
if ($size > MAX_FILE_MB * 1024 * 1024) {
jsonError("File too large. Max " . MAX_FILE_MB . " MB."); exit;
}
// MIME دقيق
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($tmpPath) ?: 'application/octet-stream';
if (!in_array($mime, ALLOWED_MIMES, true)) {
jsonError("Unsupported file type: $mime"); exit;
}
// لاحقة الامتداد
$extMap = [
'image/jpeg' => '.jpg',
'image/png' => '.png',
'image/webp' => '.webp',
];
$ext = $extMap[$mime];
// --------- توليد مسار حتمي بدون تاريخ ---------
// تنظيف driver_id لاسم ملف آمن
$driverIdSafe = preg_replace('/[^A-Za-z0-9_\-]/', '_', $driverId);
// شجرة مجلدات ثابتة من hash(driver_id) لتوزيع الملفات
$h = hash('sha1', $driverIdSafe);
$subdir = substr($h, 0, 2) . '/' . substr($h, 2, 2);
$destDir = UPLOAD_ROOT . '/' . $subdir;
if (!is_dir($destDir)) { @mkdir($destDir, 0700, true); }
// الاسم النهائي بدون تاريخ
$serverName = "{$driverIdSafe}__{$docType}{$ext}";
$destPath = $destDir . '/' . $serverName;
// استبدال أي نسخة قديمة عن قصد (overwrite)
if (is_file($destPath)) { @unlink($destPath); }
// نقل الملف
if (!move_uploaded_file($tmpPath, $destPath)) {
jsonError("Failed to save the uploaded file.");
exit;
}
@chmod($destPath, 0600);
// --------- Signed URL ---------
// سنضمّن driver_id و doc_type و ext في الرابط والتوقيع.
// ext بدون النقطة
$extShort = ltrim($ext, '.');
$expires = time() + SIGNED_TTL_SEC;
// الرسالة الموقّعة: driver_id:doc_type:ext:expires
$message = $driverIdSafe . ':' . $docType . ':' . $extShort . ':' . $expires;
$signature = hash_hmac('sha256', $message, SIGN_SECRET);
// رابط القراءة عبر البوابة الآمنة فقط
// ملاحظة: لا نُرجع المسار الحقيقي، فقط معطيات موقّعة
$fileUrl = PUBLIC_BASE . "/secure_image.php"
. "?driver_id={$driverIdSafe}"
. "&doc_type={$docType}"
. "&ext={$extShort}"
. "&expires={$expires}"
. "&signature={$signature}";
// --------- استجابة ---------
printSuccess([
"status" => "success",
"success_file" => true,
"file_url" => $fileUrl,
"file_name" => $serverName, // الاسم الفعلي المحفوظ
"driver_id" => $driverIdSafe,
"doc_type" => $docType,
"mime_type" => $mime,
"size_bytes" => $size,
"expires_at" => date('c', $expires)
]);

93
auth/syria/verifyOtp.php Executable file
View File

@@ -0,0 +1,93 @@
<?php
$allowRegistration = true;
require_once __DIR__ . '/../../connect.php';
// تسجيل بداية الطلب
error_log("[Auth_Debug] Start processing phone verification request.");
$phoneNumber = filterRequest("phone_number");
if (!$phoneNumber) {
error_log("[Auth_Error] Phone number is missing in the request.");
jsonError("Phone number is required");
exit();
}
// تسجيل الرقم (مشفر أو عادي حسب الحاجة، يفضل عدم تسجيله عادي لأسباب الخصوصية لكن هنا للتوضيح)
error_log("[Auth_Debug] Received phone number (Masked): " . substr($phoneNumber, 0, 7) . "*****");
// تشفير رقم الهاتف
$phoneNumber_encrypted = $encryptionHelper->encryptData($phoneNumber);
error_log("[Auth_Debug] Phone number encrypted successfully.");
try {
// ✅ 1. حذف أي رموز قديمة لنفس الرقم
error_log("[Auth_Step_1] Deleting old verification records for this phone...");
$stmtDelete = $con->prepare("DELETE FROM phone_verification_passenger WHERE phone_number = ?");
$stmtDelete->execute([$phoneNumber_encrypted]);
error_log("[Auth_Step_1] Old records deleted (if any).");
// ✅ 2. إدخال سجل جديد مع تحقق مباشر (بدون OTP)
$now = date('Y-m-d H:i:s');
error_log("[Auth_Step_2] Inserting new verified record at: " . $now);
$stmt = $con->prepare("
INSERT INTO phone_verification_passenger (phone_number, token, expiration_time, verified, created_at)
VALUES (?, NULL, NULL, 1, ?)
");
$stmt->execute([$phoneNumber_encrypted, $now]);
error_log("[Auth_Step_2] New record inserted successfully.");
// ✅ 3. فحص هل الراكب موجود مسبقاً
error_log("[Auth_Step_3] Checking if passenger exists in passengers table...");
$checkPassengerStmt = $con->prepare("
SELECT * FROM passengers WHERE phone = ?
");
$checkPassengerStmt->execute([$phoneNumber_encrypted]);
$passenger = $checkPassengerStmt->fetch(PDO::FETCH_ASSOC);
if ($passenger) {
// ✅ الراكب موجود
error_log("[Auth_Result] Passenger Found. ID: " . $passenger['id']);
printSuccess([
"message" => "Passenger already registered.",
"isRegistered" => true,
"passenger" => [
"id" => $passenger['id'],
"first_name" => $encryptionHelper->decryptData($passenger['first_name']),
"last_name" => $encryptionHelper->decryptData($passenger['last_name']),
"email" => $encryptionHelper->decryptData($passenger['email']),
"phone" => $phoneNumber
]
]);
} else {
// ✅ الراكب جديد
error_log("[Auth_Result] Passenger Not Found. Treating as new user.");
printSuccess([
"message" => "Phone number verified automatically (no OTP required).",
"isRegistered" => false
]);
}
} catch (PDOException $e) {
// تسجيل الخطأ بالتفصيل في ملف اللوج
error_log("[Auth_DB_Exception] Error: " . $e->getMessage() . " | File: " . $e->getFile() . " | Line: " . $e->getLine());
// طباعة رسالة الخطأ للمستخدم (يفضل عدم إظهار تفاصيل الـ SQL للمستخدم النهائي لأسباب أمنية)
jsonError("Database error occurred. Please contact support.");
} catch (Exception $e) {
// التقاط أي أخطاء عامة أخرى
error_log("[Auth_General_Exception] Error: " . $e->getMessage());
jsonError("An unexpected error occurred.");
}
// تسجيل نهاية الطلب
error_log("[Auth_Debug] Request processing finished.");
?>

View File

@@ -0,0 +1,67 @@
<?php
// File: send_otp_driver.php (إصدار بدون RaseelPlus)
require_once __DIR__ . '/../../../connect.php';
/* 1) توليد رمز التحقق --------------------------------------------------- */
$otp = rand(10000, 99999);
$receiver = filterRequest("receiver");
if (empty($receiver)) {
jsonError('Phone number is required.');
exit();
}
/* 2) نص الرسالة وإرسالها عبر دالتك الجديدة ------------------------------ */
$messageBody = "رمز التحقق الخاص بك لتطبيق انطلق درايفر هو: " . $otp;
/**
* نفترض أن sendWhatsAppFromServer() تُرجع:
* [
* 'success' => true/false,
* 'message' => 'Message sent successfully!',
* 'details' => ['status' => 'PENDING' | 'SENT' | …]
* ]
*/
$raw = sendWhatsAppFromServer($receiver, $messageBody);
$response = is_string($raw) ? json_decode($raw, true) : (array) $raw;
$sentOK = $response['success'] ?? false;
$waStatus = $response['details']['status'] ?? '';
if ($sentOK ) {
/* 3) تشفير البيانات وحفظها في DB ----------------------------------- */
$receiver_enc = $encryptionHelper->encryptData($receiver);
$otp_enc = $encryptionHelper->encryptData($otp);
$exp = date('Y-m-d H:i:s', strtotime('+5 minutes'));
$now = date('Y-m-d H:i:s');
try {
// حذف رموز قديمة
$con->prepare("DELETE FROM token_verification_driver WHERE phone_number = ?")
->execute([$receiver_enc]);
$stmt = $con->prepare("
INSERT INTO token_verification_driver
(phone_number, token, expiration_time, verified, created_at)
VALUES (?, ?, ?, 0, ?)
");
$stmt->execute([$receiver_enc, $otp_enc, $exp, $now]);
jsonSuccess(null, 'OTP sent and saved successfully');
} catch (PDOException $e) {
jsonError('OTP sent but failed to save to database');
}
} else {
$errMsg = $response['message'] ?? 'Unknown error';
jsonError('Failed to send OTP: ' . $errMsg);
}
/* -----------------------------------------------------------------------
* أبقينا callAPI() فقط إذا كان يُستخدم في ملفات أخرى احذفه إن شئت.
* --------------------------------------------------------------------- */
function callAPI($method, $url, $data) { /* … */ }
?>

View File

@@ -0,0 +1,81 @@
<?php
require_once __DIR__ . '/../../../connect.php';
$phoneNumber = filterRequest("phone_number");
$otp = filterRequest("otp");
if (empty($phoneNumber) || empty($otp)) {
jsonError("Phone number and OTP are required.");
exit();
}
$phoneNumber_encrypted = $encryptionHelper->encryptData($phoneNumber);
$otp_encrypted = $encryptionHelper->encryptData($otp);
try {
$stmt = $con->prepare("
SELECT * FROM token_verification_driver
WHERE phone_number = ? AND token = ?
");
$stmt->execute([$phoneNumber_encrypted, $otp_encrypted]);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if ($result) {
$expiration_time = strtotime($result['expiration_time']);
if (time() <= $expiration_time) {
$con->prepare("UPDATE token_verification_driver SET verified = 1 WHERE id = ?")
->execute([$result['id']]);
$driverStmt = $con->prepare("SELECT id FROM driver WHERE phone = ?");
$driverStmt->execute([$phoneNumber_encrypted]);
$driver = $driverStmt->fetch(PDO::FETCH_ASSOC);
if ($driver) {
$driverID = $driver['id'];
$newToken = filterRequest("token");
$fingerPrint = filterRequest("fingerPrint");
if ($newToken && $fingerPrint) {
$tokenEncrypted = $encryptionHelper->encryptData($newToken);
$checkTokenStmt = $con->prepare("SELECT id FROM driverToken WHERE captain_id = ?");
$checkTokenStmt->execute([$driverID]);
if ($checkTokenStmt->rowCount() > 0) {
$con->prepare("UPDATE driverToken SET token = ?, fingerPrint = ? WHERE captain_id = ?")
->execute([$tokenEncrypted, $fingerPrint, $driverID]);
} else {
$con->prepare("INSERT INTO driverToken (token, fingerPrint, captain_id, created_at) VALUES (?, ?, ?, NOW())")
->execute([$tokenEncrypted, $fingerPrint, $driverID]);
}
$response = [
"message" => "Driver token verified and updated.",
"isRegistered" => true,
"driverID" => $driverID
];
jsonSuccess($response);
} else {
jsonError("Token or fingerprint missing.");
}
} else {
printSuccess([
"message" => "Phone verified, but driver not found.",
"isRegistered" => false
]);
}
} else {
jsonError("OTP expired. Request a new one.");
}
} else {
jsonError("Invalid OTP.");
}
} catch (PDOException $e) {
jsonError("Database error occurred.");
}

View File

@@ -0,0 +1,65 @@
<?php
// File: send_otp.php (بديل عن النسخة المعتمدة على RaseelPlus)
require_once __DIR__ . '/../../connect.php';
/* 1) توليد رمز التحقق */
$otp = rand(10000, 99999);
$receiver = filterRequest("receiver");
if (empty($receiver)) {
jsonError('Phone number is required.');
exit();
}
/* 2) نصّ الرسالة وإرسالها عبر دالتك الجديدة */
$messageBody = "Your verification code for Intaleq is: " . $otp;
$raw = sendWhatsAppFromServer($receiver, $messageBody);
$response = is_string($raw) ? json_decode($raw, true) : (array) $raw;
/*
* نتوقع بنية مثل:
* [
* 'success' => true,
* 'details' => ['status' => 'PENDING' | 'SENT' | …]
* ]
*/
$sentOK = $response['success'] ?? false;
$statusOK = in_array($response['details']['status'] ?? '', ['PENDING', 'SENT', 'DELIVERED'], true);
if ($sentOK ) {
/* 3) تشفير البيانات وحفظ الرمز في قاعدة البيانات */
$receiver_enc = $encryptionHelper->encryptData($receiver);
$otp_enc = $encryptionHelper->encryptData($otp);
$exp = date('Y-m-d H:i:s', strtotime('+5 minutes'));
$now = date('Y-m-d H:i:s');
try {
$con->prepare("DELETE FROM token_verification WHERE phone_number = ?")
->execute([$receiver_enc]);
$stmt = $con->prepare("
INSERT INTO token_verification
(phone_number, token, expiration_time, verified, created_at)
VALUES (?, ?, ?, 0, ?)
");
$stmt->execute([$receiver_enc, $otp_enc, $exp, $now]);
jsonSuccess(null, 'OTP sent and saved successfully');
} catch (PDOException $e) {
jsonError('OTP sent but failed to save to database');
}
} else {
$errMsg = $response['message'] ?? 'Unknown error';
jsonError('Failed to send OTP: ' . $errMsg);
}
/* -----------------------------------------------------------------
* يمكن حذف callAPI() تمامًا إن لم يعد مستخدمًا في أي ملف آخر.
* ---------------------------------------------------------------- */
function callAPI($method, $url, $data) { /* … (أبقِها أو احذفها) */ }
?>

View File

@@ -0,0 +1,80 @@
<?php
// File: verify_otp.php (with enhanced logging)
// intaleq_v1/auth/token_passenger
require_once __DIR__ . '/../../connect.php';
// --- Start of Script Execution ---
error_log("--- [verify_otp.php] Script execution started. ---");
$phoneNumber = filterRequest("phone_number");
$otp = filterRequest("otp");
// Log received data for debugging. Be mindful of logging sensitive data in production.
error_log("[verify_otp.php] Received phone_number: $phoneNumber | Received otp: $otp");
if (empty($phoneNumber) || empty($otp)) {
error_log("[verify_otp.php] Error: Phone number or OTP is empty.");
jsonError("Phone number and OTP are required.");
exit();
}
$phoneNumber_encrypted = $encryptionHelper->encryptData($phoneNumber);
$otp_encrypted = $encryptionHelper->encryptData($otp);
try {
// 1. التحقق من Redis بدلاً من MySQL
if (!$redis) {
jsonError("Security service unavailable");
exit;
}
$cachedOtp = $redis->get("otp:passenger:$phoneNumber");
if ($cachedOtp && $cachedOtp == $otp) {
// ننجح في التحقق ونحذف المفتاح من Redis لمنع استخدامه مرة أخرى (One-time use)
$redis->del("otp:passenger:$phoneNumber");
error_log("[verify_otp.php] OTP verified via Redis for phone: $phoneNumber");
// 2. التحقق من وجود الراكب في قاعدة البيانات
$passengerStmt = $con->prepare("SELECT id FROM passengers WHERE phone = ?");
$passengerStmt->execute([$phoneNumber_encrypted]);
$passenger = $passengerStmt->fetch(PDO::FETCH_ASSOC);
if ($passenger) {
$passengerID = $passenger['id'];
// تحديث التوكن والبصمة إن وجدا
$newToken = filterRequest("token");
$fingerPrint = filterRequest("fingerPrint");
if ($newToken && $fingerPrint) {
$tokenEncrypted = $encryptionHelper->encryptData($newToken);
$updateTokenStmt = $con->prepare("UPDATE tokens SET token = ?, fingerPrint = ? WHERE passengerID = ?");
$updateTokenStmt->execute([$tokenEncrypted, $fingerPrint, $passengerID]);
}
printSuccess([
"message" => "Token verified and updated.",
"isRegistered" => true,
"passengerID" => $passengerID
]);
} else {
printSuccess([
"message" => "Phone verified, passenger not found.",
"isRegistered" => false
]);
}
} else {
error_log("[verify_otp.php] Invalid or expired OTP for phone: $phoneNumber");
jsonError("Invalid or expired OTP.");
}
} catch (Exception $e) {
// Log the detailed database error message for debugging.
error_log("[verify_otp.php] FATAL DATABASE ERROR: " . $e->getMessage());
jsonError("Database error: " . $e->getMessage());
}
?>

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 820 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 895 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 895 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 923 KiB

39
auth/verifyEmail.php Normal file
View File

@@ -0,0 +1,39 @@
<?php
require_once __DIR__ . '/../connect.php';
$email = filterRequest("email");
$token = filterRequest("token");
$sql = "SELECT `id`, `email`, `token`, `created_at`, `updated_at`, `verified` FROM `email_verifications` WHERE `email` = '$email' AND `token` = '$token'";
$stmt = $con->prepare($sql);
$stmt->execute();
$result = $stmt->fetch();
if ($result) {
$id = $result["id"];
$sql = "UPDATE `email_verifications` SET `verified` = 1 WHERE `id` = $id";
$stmt = $con->prepare($sql);
$stmt->execute();
$admin='support@sefer.com';
$headers = "MIME-Version: 1.0" . "\r\n";
$headers .= "Content-type: text/html; charset=UTF-8" . "\r\n";
$headers .= "From: $admin" . "\r\n";
$subject = " Verify your email address";
$bodyEmail="Subject: Verify your email address
Hi [$email],
Your email address has been verified.
Thank you,
SEFER Team";
mail($email, $subject, $bodyEmail, $headers);
jsonSuccess($message = "Your email address has been verified.");
} else {
jsonError($message ="Your email address could not be verified. Please try again.");
}
?>

60
auth/verifyOtpMessage.php Executable file
View File

@@ -0,0 +1,60 @@
<?php
require_once __DIR__ . '/../connect.php';
$phone_number = filterRequest("phone_number");
$token_code = filterRequest("token");
// Check if the phone number and token code match
$sql = "SELECT
`id`,
`phone_number`,
`token`,
`expiration_time`,
`verified`,
`created_at`
FROM
`phone_verification_passenger`
WHERE
`phone_number` = :phone_number AND `token` = :token_code";
$stmt = $con->prepare($sql);
// Log the parameters used in the SQL query for debugging
error_log("Executing SELECT SQL: " . $sql . " with phone_number=" . $phone_number . " and token_code=" . $token_code);
$stmt->bindParam(':phone_number', $phone_number, PDO::PARAM_STR);
$stmt->bindParam(':token_code', $token_code, PDO::PARAM_STR);
if ($stmt->execute()) {
$result = $stmt->fetch();
if ($result) {
// Update the verified status
$sql = "UPDATE `phone_verification_passenger` SET `verified` = 1 WHERE `phone_number` = :phone_number";
$stmt = $con->prepare($sql);
// Log the update query execution
error_log("Executing UPDATE SQL: " . $sql . " with phone_number=" . $phone_number);
$stmt->bindParam(':phone_number', $phone_number, PDO::PARAM_STR);
if ($stmt->execute()) {
jsonSuccess(null, "Your phone number has been verified.");
} else {
// Log if the update query fails
error_log("Error executing UPDATE SQL: " . implode(", ", $stmt->errorInfo()));
jsonError("An error occurred while verifying your phone number. Please try again.");
}
} else {
// Log if no matching record was found
error_log("No matching record found for phone_number=" . $phone_number . " and token_code=" . $token_code);
jsonError("Your phone number could not be verified. Please try again.");
}
} else {
// Log if the select query fails
error_log("Error executing SELECT SQL: " . implode(", ", $stmt->errorInfo()));
jsonError("An error occurred while verifying your phone number. Please try again.");
}
?>