Update: 2026-06-12 20:40:40
This commit is contained in:
0
backend/Admin/AdminCaptain/getDriversPhonesAndTokens.php
Executable file → Normal file
0
backend/Admin/AdminCaptain/getDriversPhonesAndTokens.php
Executable file → Normal file
54
backend/Admin/Staff/activate.php
Normal file
54
backend/Admin/Staff/activate.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* Admin/Staff/activate.php
|
||||
* تفعيل الحسابات المعلقة للمشرفين (Admins) وموظفي خدمة العملاء (Service) من قبل المشرف العام
|
||||
*/
|
||||
require_once __DIR__ . '/../../core/bootstrap.php';
|
||||
require_once __DIR__ . '/../../functions.php';
|
||||
|
||||
$userId = filterRequest('user_id');
|
||||
$type = filterRequest('type'); // 'admin' or 'service'
|
||||
|
||||
if (empty($userId) || empty($type)) {
|
||||
jsonError("رقم المستخدم ونوع الحساب مطلوبان.");
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$con = Database::get('main');
|
||||
|
||||
// التحقق من صلاحية المشرف العام (Super Admin أو Admin فقط)
|
||||
$jwtService = new JwtService($redis);
|
||||
$auth = $jwtService->authenticate();
|
||||
$authRole = $auth->role ?? '';
|
||||
if ($authRole !== 'super_admin' && $authRole !== 'admin') {
|
||||
jsonError("غير مصرح لك. فقط المشرف العام يمكنه تفعيل الحسابات.");
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($type === 'admin') {
|
||||
$stmt = $con->prepare("UPDATE adminUser SET status = 'active' WHERE id = :id AND status = 'pending'");
|
||||
$stmt->execute([':id' => $userId]);
|
||||
|
||||
if ($stmt->rowCount() > 0) {
|
||||
printSuccess(["message" => "تم تفعيل حساب المشرف بنجاح."]);
|
||||
} else {
|
||||
jsonError("لم يتم العثور على حساب مشرف معلق بهذا المعرف.");
|
||||
}
|
||||
} elseif ($type === 'service') {
|
||||
$stmt = $con->prepare("UPDATE users SET status = 'approved' WHERE id = :id AND status = 'pending' AND user_type = 'service'");
|
||||
$stmt->execute([':id' => $userId]);
|
||||
|
||||
if ($stmt->rowCount() > 0) {
|
||||
printSuccess(["message" => "تم تفعيل حساب موظف الخدمة بنجاح."]);
|
||||
} else {
|
||||
jsonError("لم يتم العثور على حساب موظف خدمة معلق بهذا المعرف.");
|
||||
}
|
||||
} else {
|
||||
jsonError("نوع حساب غير صالح.");
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
error_log("[Staff Activate Error] " . $e->getMessage());
|
||||
jsonError("خطأ في السيرفر: " . $e->getMessage());
|
||||
}
|
||||
exit();
|
||||
@@ -7,15 +7,14 @@ require_once __DIR__ . '/../../core/bootstrap.php';
|
||||
|
||||
$con = Database::get('main');
|
||||
|
||||
// التحقق من الصلاحيات: فقط المشرفين يمكنهم الإضافة
|
||||
// إذا لم يكن هناك أي مدير في النظام، نسمح// تم تعطيل التحقق للسماح بإعادة التهيئة في مرحلة التطوير
|
||||
// $count = $con->query("SELECT COUNT(*) FROM adminUser")->fetchColumn();
|
||||
// if ($count > 0) die("Access Denied: Admin already initialized.");
|
||||
// $auth = JwtService::authenticate($redis);
|
||||
// if ($auth['role'] !== 'super_admin' && $auth['role'] !== 'admin') {
|
||||
// jsonError("Unauthorized. Only Admins can add staff.");
|
||||
// exit;
|
||||
// }
|
||||
// التحقق من الصلاحيات: فقط المشرفين (super_admin أو admin) يمكنهم الإضافة
|
||||
$jwtService = new JwtService($redis);
|
||||
$auth = $jwtService->authenticate();
|
||||
$authRole = $auth->role ?? '';
|
||||
if ($authRole !== 'super_admin' && $authRole !== 'admin') {
|
||||
jsonError("غير مصرح لك. فقط المشرفون يمكنهم إضافة موظفين.");
|
||||
exit;
|
||||
}
|
||||
|
||||
$name = filterRequest("name");
|
||||
$phone = filterRequest("phone");
|
||||
@@ -47,14 +46,20 @@ try {
|
||||
|
||||
if ($role === 'admin') {
|
||||
// الإضافة لجدول المديرين
|
||||
$sql = "INSERT INTO adminUser (id, fingerprint, fingerprint_hash, name, password, role, created_at)
|
||||
VALUES (:id, :fp, :fp_hash, :name, :pass, :role, NOW())";
|
||||
// التأكد من وجود عمود phone في الجدول (كإجراء احترازي لتجنب الأخطاء إذا لم يكن موجوداً)
|
||||
try {
|
||||
$con->exec("ALTER TABLE adminUser ADD COLUMN phone VARCHAR(255) NULL AFTER name");
|
||||
} catch (Exception $e) { /* العمود موجود مسبقاً */ }
|
||||
|
||||
$sql = "INSERT INTO adminUser (id, fingerprint, fingerprint_hash, name, phone, password, role, created_at)
|
||||
VALUES (:id, :fp, :fp_hash, :name, :phone, :pass, :role, NOW())";
|
||||
$stmt = $con->prepare($sql);
|
||||
$stmt->execute([
|
||||
':id' => $uniqueId,
|
||||
':fp' => $encFp,
|
||||
':fp_hash' => $fpHash,
|
||||
':name' => $encName,
|
||||
':phone' => $encPhone,
|
||||
':pass' => $hashedPassword,
|
||||
':role' => $role
|
||||
]);
|
||||
|
||||
42
backend/Admin/Staff/pending.php
Normal file
42
backend/Admin/Staff/pending.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* Admin/Staff/pending.php
|
||||
* جلب الحسابات المعلقة للإداريين والخدمة
|
||||
*/
|
||||
require_once __DIR__ . '/../../core/bootstrap.php';
|
||||
require_once __DIR__ . '/../../functions.php';
|
||||
|
||||
try {
|
||||
$con = Database::get('main');
|
||||
|
||||
// جلب الإداريين المعلقين
|
||||
$stmt1 = $con->query("SELECT id, name, phone, role, created_at, 'admin' as type FROM adminUser WHERE status = 'pending'");
|
||||
$admins = $stmt1->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// فك التشفير للأسماء والأرقام للإداريين
|
||||
foreach ($admins as &$admin) {
|
||||
$admin['name'] = $encryptionHelper->decryptData($admin['name']) ?: $admin['name'];
|
||||
$admin['phone'] = $encryptionHelper->decryptData($admin['phone']) ?: $admin['phone'];
|
||||
}
|
||||
|
||||
// جلب موظفي الخدمة المعلقين
|
||||
$stmt2 = $con->query("SELECT id, first_name, last_name, phone, user_type as role, created_at, 'service' as type FROM users WHERE status = 'pending' AND user_type = 'service'");
|
||||
$services = $stmt2->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// فك التشفير لموظفي الخدمة
|
||||
foreach ($services as &$service) {
|
||||
$service['name'] = trim(($encryptionHelper->decryptData($service['first_name']) ?: $service['first_name']) . ' ' . ($encryptionHelper->decryptData($service['last_name']) ?: $service['last_name']));
|
||||
$service['phone'] = $encryptionHelper->decryptData($service['phone']) ?: $service['phone'];
|
||||
}
|
||||
|
||||
$allPending = array_merge($admins, $services);
|
||||
|
||||
printSuccess([
|
||||
"data" => $allPending
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log("[Staff Pending Error] " . $e->getMessage());
|
||||
jsonError("خطأ في السيرفر: " . $e->getMessage());
|
||||
}
|
||||
exit();
|
||||
0
backend/Admin/adminUser/add_invoice.php
Executable file → Normal file
0
backend/Admin/adminUser/add_invoice.php
Executable file → Normal file
0
backend/Admin/adminUser/invoice_total.php
Executable file → Normal file
0
backend/Admin/adminUser/invoice_total.php
Executable file → Normal file
33
backend/Admin/auth/login.php
Executable file → Normal file
33
backend/Admin/auth/login.php
Executable file → Normal file
@@ -8,6 +8,7 @@ require_once __DIR__ . '/../../functions.php';
|
||||
|
||||
$fingerprint = filterRequest('fingerprint');
|
||||
$password = filterRequest('password');
|
||||
$phone = filterRequest('phone');
|
||||
$audience = filterRequest('aud') ?? 'admin';
|
||||
$isRenewal = filterRequest('is_renewal') === '1';
|
||||
|
||||
@@ -16,6 +17,10 @@ if (empty($fingerprint) || empty($password)) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Rate Limiting: 5 محاولات في الدقيقة لكل IP
|
||||
$rateLimiter = new RateLimiter($redis);
|
||||
$rateLimiter->enforce(RateLimiter::identifier(), 'login');
|
||||
|
||||
try {
|
||||
$con = Database::get('main');
|
||||
|
||||
@@ -25,6 +30,28 @@ try {
|
||||
$stmt->execute([':fp' => $fpHash]);
|
||||
$admin = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
// إذا لم يتم العثور بالبصمة، وتم تمرير رقم الهاتف (تسجيل دخول لأول مرة أو جهاز جديد)
|
||||
if (!$admin && !empty($phone)) {
|
||||
$encPhoneInput = $encryptionHelper->encryptData($phone);
|
||||
$stmtPhone = $con->prepare("SELECT * FROM adminUser WHERE phone = :phone LIMIT 1");
|
||||
$stmtPhone->execute([':phone' => $encPhoneInput]);
|
||||
$admin = $stmtPhone->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
// تأكيد كلمة المرور وتحديث بصمة الجهاز إذا تم إيجاد الحساب
|
||||
if ($admin && password_verify($password, $admin['password'])) {
|
||||
$encFpRaw = $encryptionHelper->encryptData($fingerprint);
|
||||
$updateStmt = $con->prepare("UPDATE adminUser SET fingerprint = :fp_raw, fingerprint_hash = :fp WHERE id = :id");
|
||||
$updateStmt->execute([
|
||||
':fp_raw' => $encFpRaw,
|
||||
':fp' => $fpHash,
|
||||
':id' => $admin['id']
|
||||
]);
|
||||
$admin['fingerprint_hash'] = $fpHash; // Update locally
|
||||
} else if ($admin) {
|
||||
// Password incorrect, fail later.
|
||||
}
|
||||
}
|
||||
|
||||
if ($admin) {
|
||||
// 1. التحقق من حالة الحساب
|
||||
if ($admin['status'] === 'pending') {
|
||||
@@ -69,8 +96,8 @@ try {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 3. توليد رمز تحقق OTP وإرساله عبر WhatsApp
|
||||
$otp = rand(10000, 99999);
|
||||
// 3. توليد رمز تحقق OTP (6 أرقام) وإرساله عبر WhatsApp
|
||||
$otp = rand(100000, 999999);
|
||||
$encryptedPhone = $admin['phone'] ?? '';
|
||||
|
||||
if (empty($encryptedPhone)) {
|
||||
@@ -112,7 +139,7 @@ try {
|
||||
jsonError("كلمة المرور غير صحيحة.");
|
||||
}
|
||||
} else {
|
||||
jsonError("الجهاز غير مسجل كمشرف.");
|
||||
jsonError("الحساب أو الجهاز غير مسجل. يرجى إدخال رقم هاتفك وكلمة المرور إذا كان هذا أول تسجيل دخول لك.");
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
error_log("[Admin Login Error] " . $e->getMessage());
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<?php
|
||||
/**
|
||||
* Admin/auth/register.php
|
||||
* التسجيل الذاتي للمشرفين - الحساب يكون بحالة pending بانتظار موافقة السوبر أدمن
|
||||
* التسجيل الذاتي للمشرفين (Admins) مع التحقق من الصلاحيات من ملف .env
|
||||
*/
|
||||
require_once __DIR__ . '/../../core/bootstrap.php';
|
||||
require_once __DIR__ . '/../../functions.php';
|
||||
|
||||
$name = filterRequest('name');
|
||||
$phone = filterRequest('phone');
|
||||
@@ -11,49 +12,75 @@ $password = filterRequest('password');
|
||||
$fingerprint = filterRequest('fingerprint');
|
||||
|
||||
if (empty($name) || empty($phone) || empty($password) || empty($fingerprint)) {
|
||||
jsonError("All fields are required.");
|
||||
jsonError("جميع الحقول مطلوبة بما فيها بصمة الجهاز.");
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$con = Database::get('main');
|
||||
|
||||
// 1. التحقق من عدم وجود الحساب مسبقاً (عن طريق الهاتف أو البصمة)
|
||||
$fpHash = hash('sha256', $fingerprint);
|
||||
$check = $con->prepare("SELECT id FROM adminUser WHERE phone = ? OR fingerprint_hash = ? LIMIT 1");
|
||||
$check->execute([$phone, $fpHash]);
|
||||
// 1. التحقق من البيئة (Environment Whitelist)
|
||||
$allowedPhonesStr = getenv('AUTHORIZED_ADMIN_PHONES');
|
||||
if (!$allowedPhonesStr) {
|
||||
// في حال لم يتم إعداد المتغير، نرفض الجميع للأمان
|
||||
jsonError("غير مصرح لك بالتسجيل كمشرف (القائمة البيضاء غير معدة).");
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($check->rowCount() > 0) {
|
||||
jsonError("هذا الحساب أو الجهاز مسجل مسبقاً.");
|
||||
$allowedPhones = array_map('trim', explode(',', $allowedPhonesStr));
|
||||
if (!in_array($phone, $allowedPhones)) {
|
||||
jsonError("أنت غير مصرح لك بالتسجيل كمشرف. يرجى مراجعة الإدارة.");
|
||||
exit;
|
||||
}
|
||||
|
||||
// 2. تجهيز البيانات
|
||||
$id = bin2hex(random_bytes(16));
|
||||
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
||||
$encName = $encryptionHelper->encryptData($name);
|
||||
$encFp = $encryptionHelper->encryptData($fingerprint);
|
||||
$con = Database::get('main');
|
||||
|
||||
// 3. الإدخال في قاعدة البيانات (الحالة الافتراضية هي pending)
|
||||
$sql = "INSERT INTO adminUser (id, name, phone, password, fingerprint, fingerprint_hash, role, status, created_at)
|
||||
VALUES (:id, :name, :phone, :pass, :fp, :fp_hash, 'admin', 'pending', NOW())";
|
||||
// 2. التحقق من عدم وجود الحساب مسبقاً (عن طريق الهاتف أو البصمة)
|
||||
$fpHash = hash('sha256', $fingerprint);
|
||||
$encPhoneInput = $encryptionHelper->encryptData($phone);
|
||||
|
||||
$check = $con->prepare("SELECT id FROM adminUser WHERE phone = ? OR fingerprint_hash = ? LIMIT 1");
|
||||
$check->execute([$encPhoneInput, $fpHash]);
|
||||
|
||||
if ($check->rowCount() > 0) {
|
||||
jsonError("رقم الهاتف أو الجهاز مسجل مسبقاً.");
|
||||
exit;
|
||||
}
|
||||
|
||||
// 3. تجهيز البيانات
|
||||
$uniqueId = bin2hex(random_bytes(16)); // UUID آمن (32 حرف hex عشوائي)
|
||||
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
$encName = $encryptionHelper->encryptData($name);
|
||||
$encPhone = $encPhoneInput;
|
||||
$encFp = $encryptionHelper->encryptData($fingerprint);
|
||||
|
||||
// التأكد من وجود عمود phone و status في الجدول
|
||||
try {
|
||||
$con->exec("ALTER TABLE adminUser ADD COLUMN phone VARCHAR(255) NULL AFTER name");
|
||||
$con->exec("ALTER TABLE adminUser ADD COLUMN status VARCHAR(50) DEFAULT 'pending' AFTER role");
|
||||
} catch (Exception $e) { /* الأعمدة موجودة مسبقاً */ }
|
||||
|
||||
// 4. الإدخال في قاعدة البيانات بحالة pending
|
||||
$sql = "INSERT INTO adminUser (id, fingerprint, fingerprint_hash, name, phone, password, role, status, created_at)
|
||||
VALUES (:id, :fp, :fp_hash, :name, :phone, :pass, 'admin', 'pending', NOW())";
|
||||
|
||||
$stmt = $con->prepare($sql);
|
||||
$stmt->execute([
|
||||
':id' => $id,
|
||||
':name' => $encName,
|
||||
':phone' => $phone,
|
||||
':pass' => $hashedPassword,
|
||||
':id' => $uniqueId,
|
||||
':fp' => $encFp,
|
||||
':fp_hash' => $fpHash
|
||||
':fp_hash' => $fpHash,
|
||||
':name' => $encName,
|
||||
':phone' => $encPhone,
|
||||
':pass' => $hashedPassword
|
||||
]);
|
||||
|
||||
printSuccess([
|
||||
"status" => "pending",
|
||||
"message" => "تم تقديم طلب التسجيل بنجاح. يرجى انتظار موافقة الإدارة."
|
||||
"message" => "تم تسجيل حسابك بنجاح وهو الآن قيد المراجعة. يرجى انتظار تفعيل المشرف العام."
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log("[Admin Register Error] " . $e->getMessage());
|
||||
jsonError("خطأ في السيرفر: " . $e->getMessage());
|
||||
}
|
||||
|
||||
exit();
|
||||
|
||||
0
backend/Admin/auth/send_otp_admin.php
Executable file → Normal file
0
backend/Admin/auth/send_otp_admin.php
Executable file → Normal file
@@ -15,6 +15,10 @@ if (empty($otp) || empty($fingerprint)) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Rate Limiting: 3 محاولات OTP في 5 دقائق لكل IP
|
||||
$rateLimiter = new RateLimiter($redis);
|
||||
$rateLimiter->enforce(RateLimiter::identifier(), 'otp');
|
||||
|
||||
try {
|
||||
$con = Database::get('main');
|
||||
|
||||
|
||||
0
backend/Admin/auth/verify_otp_admin.php
Executable file → Normal file
0
backend/Admin/auth/verify_otp_admin.php
Executable file → Normal file
0
backend/Admin/driver/deleteCaptain.php
Executable file → Normal file
0
backend/Admin/driver/deleteCaptain.php
Executable file → Normal file
0
backend/Admin/driver/deleteRecord.php
Executable file → Normal file
0
backend/Admin/driver/deleteRecord.php
Executable file → Normal file
0
backend/Admin/driver/find_driver_by_phone.php
Executable file → Normal file
0
backend/Admin/driver/find_driver_by_phone.php
Executable file → Normal file
0
backend/Admin/driver/getBestDriver.php
Executable file → Normal file
0
backend/Admin/driver/getBestDriver.php
Executable file → Normal file
0
backend/Admin/driver/getDriverGiftPayment.php
Executable file → Normal file
0
backend/Admin/driver/getDriverGiftPayment.php
Executable file → Normal file
0
backend/Admin/driver/remove_from_blacklist.php
Executable file → Normal file
0
backend/Admin/driver/remove_from_blacklist.php
Executable file → Normal file
0
backend/Admin/driver/updateDriverFromAdmin.php
Executable file → Normal file
0
backend/Admin/driver/updateDriverFromAdmin.php
Executable file → Normal file
0
backend/Admin/employee/add.php
Executable file → Normal file
0
backend/Admin/employee/add.php
Executable file → Normal file
0
backend/Admin/employee/get.php
Executable file → Normal file
0
backend/Admin/employee/get.php
Executable file → Normal file
0
backend/Admin/error/error_list_last20.php
Executable file → Normal file
0
backend/Admin/error/error_list_last20.php
Executable file → Normal file
0
backend/Admin/error/error_search_by_phone.php
Executable file → Normal file
0
backend/Admin/error/error_search_by_phone.php
Executable file → Normal file
0
backend/Admin/errorApp.php
Executable file → Normal file
0
backend/Admin/errorApp.php
Executable file → Normal file
0
backend/Admin/facebook.php
Executable file → Normal file
0
backend/Admin/facebook.php
Executable file → Normal file
4
backend/Admin/jwtService.php
Executable file → Normal file
4
backend/Admin/jwtService.php
Executable file → Normal file
@@ -45,8 +45,8 @@ try {
|
||||
|
||||
$startTime = microtime(true);
|
||||
|
||||
// دعم password_verify مع البقاء على التوافق مع كلمات السر القديمة (Plain Text)
|
||||
if ($user && (password_verify($password, $user['password']) || $user['password'] === $password)) {
|
||||
// التحقق من كلمة المرور باستخدام password_hash فقط (الأمان)
|
||||
if ($user && password_verify($password, $user['password'])) {
|
||||
|
||||
$limiter->reset(RateLimiter::identifier(), 'login');
|
||||
|
||||
|
||||
0
backend/Admin/passenger/admin_delete_and_blacklist_passenger.php
Executable file → Normal file
0
backend/Admin/passenger/admin_delete_and_blacklist_passenger.php
Executable file → Normal file
0
backend/Admin/passenger/admin_unblacklist.php
Executable file → Normal file
0
backend/Admin/passenger/admin_unblacklist.php
Executable file → Normal file
0
backend/Admin/passenger/admin_update_passenger.php
Executable file → Normal file
0
backend/Admin/passenger/admin_update_passenger.php
Executable file → Normal file
0
backend/Admin/rides/admin_get_rides_by_phone.php
Executable file → Normal file
0
backend/Admin/rides/admin_get_rides_by_phone.php
Executable file → Normal file
0
backend/Admin/rides/admin_update_ride_status.php
Executable file → Normal file
0
backend/Admin/rides/admin_update_ride_status.php
Executable file → Normal file
0
backend/Admin/rides/get_driver_live_pos.php
Executable file → Normal file
0
backend/Admin/rides/get_driver_live_pos.php
Executable file → Normal file
0
backend/Admin/rides/get_rides_by_status.php
Executable file → Normal file
0
backend/Admin/rides/get_rides_by_status.php
Executable file → Normal file
0
backend/Admin/rides/monitorRide.php
Executable file → Normal file
0
backend/Admin/rides/monitorRide.php
Executable file → Normal file
0
backend/Admin/send_whatsapp_message.php
Executable file → Normal file
0
backend/Admin/send_whatsapp_message.php
Executable file → Normal file
0
backend/Admin/view_errors.php
Executable file → Normal file
0
backend/Admin/view_errors.php
Executable file → Normal file
@@ -1,15 +0,0 @@
|
||||
[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
|
||||
@@ -1,39 +0,0 @@
|
||||
<?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");
|
||||
}
|
||||
?>
|
||||
0
backend/auth/captin/loginFromGoogle.php
Executable file → Normal file
0
backend/auth/captin/loginFromGoogle.php
Executable file → Normal file
0
backend/auth/captin/loginUsingCredentialsWithoutGoogle.php
Executable file → Normal file
0
backend/auth/captin/loginUsingCredentialsWithoutGoogle.php
Executable file → Normal file
@@ -1,132 +0,0 @@
|
||||
<?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.");
|
||||
}
|
||||
?>
|
||||
@@ -1,140 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
// Rate Limiting للحماية من هجمات استنزاف الرسائل
|
||||
if (isset($redis)) {
|
||||
$redisKey = "otp_limit:driver:$phone_number";
|
||||
if ($redis->exists($redisKey)) {
|
||||
jsonError("Please wait before requesting a new OTP.");
|
||||
exit;
|
||||
}
|
||||
$redis->setex($redisKey, 60, "1"); // حظر لمدة 60 ثانية
|
||||
}
|
||||
|
||||
// توليد رمز تحقق مكوّن من 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;
|
||||
}
|
||||
?>
|
||||
0
backend/auth/captin/updateDriverClaim.php
Executable file → Normal file
0
backend/auth/captin/updateDriverClaim.php
Executable file → Normal file
@@ -1,56 +0,0 @@
|
||||
<?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());
|
||||
}
|
||||
?>
|
||||
0
backend/auth/captin/updateShamCashDriver.php
Executable file → Normal file
0
backend/auth/captin/updateShamCashDriver.php
Executable file → Normal file
@@ -1,39 +0,0 @@
|
||||
<?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.");
|
||||
}
|
||||
?>
|
||||
0
backend/auth/checkPhoneNumberISVerfiedPassenger.php
Executable file → Normal file
0
backend/auth/checkPhoneNumberISVerfiedPassenger.php
Executable file → Normal file
@@ -1,23 +0,0 @@
|
||||
<?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 +0,0 @@
|
||||
["3","7","1","9","0","5","2","6","4","8"]
|
||||
0
backend/auth/document_syria/ai_document.php
Executable file → Normal file
0
backend/auth/document_syria/ai_document.php
Executable file → Normal file
@@ -1,115 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* upload_document.php
|
||||
* الغرض: رفع صورة وثيقة فقط وإرجاع رابطها (بدون ذكاء صناعي)
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
uploadLog("🚀 [uploadDocSyria.php] Document upload script started.");
|
||||
|
||||
$driverId = trim((string) filterRequest("driver_id"));
|
||||
$type = trim((string) filterRequest("type"));
|
||||
|
||||
// ✅ التحقق من الحقول الاختيارية
|
||||
if ($driverId === "") { $driverId = "unknown"; }
|
||||
if ($type === "") { $type = "generic"; }
|
||||
|
||||
uploadLog("📥 Request parameters: driver_id=$driverId, type=$type");
|
||||
|
||||
// ✅ التحقق من ملف الصورة
|
||||
if (isset($_FILES['image'])) {
|
||||
uploadLog("$_FILES['image'] metadata", 'INFO', [
|
||||
'name' => $_FILES['image']['name'] ?? 'unknown',
|
||||
'type' => $_FILES['image']['type'] ?? 'unknown',
|
||||
'size' => $_FILES['image']['size'] ?? 0,
|
||||
'upload_error_code' => $_FILES['image']['error'] ?? UPLOAD_ERR_OK
|
||||
]);
|
||||
} else {
|
||||
uploadLog("No 'image' file was sent in the request.", 'WARNING');
|
||||
}
|
||||
|
||||
if (!isset($_FILES['image']) || $_FILES['image']['error'] !== UPLOAD_ERR_OK) {
|
||||
$err = $_FILES['image']['error'] ?? 'missing_file';
|
||||
uploadLog("❌ File upload validation failed. Code: $err", 'ERROR');
|
||||
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)) {
|
||||
uploadLog("❌ Unsupported file extension: $extension", 'ERROR');
|
||||
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 = "/siro/auth/uploads/documents/" . $uniqueName;
|
||||
$imageUrl = rtrim(BASE_URL, '/') . $publicPath;
|
||||
|
||||
// ✅ نتيجة نهائية: فقط رابط الصورة وبعض البيانات المفيدة
|
||||
uploadLog("✅ Document upload succeeded. URL: $imageUrl");
|
||||
printSuccess([
|
||||
$imageUrl,
|
||||
]);
|
||||
@@ -1,64 +0,0 @@
|
||||
<?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();
|
||||
?>
|
||||
@@ -1,38 +0,0 @@
|
||||
<?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();
|
||||
?>
|
||||
@@ -1,55 +0,0 @@
|
||||
<?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);
|
||||
@@ -1,41 +0,0 @@
|
||||
<?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();
|
||||
?>
|
||||
0
backend/auth/loginFromGooglePassenger.php
Executable file → Normal file
0
backend/auth/loginFromGooglePassenger.php
Executable file → Normal file
229
backend/auth/otp/providers.php
Normal file
229
backend/auth/otp/providers.php
Normal file
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
// File: backend/auth/otp/providers.php
|
||||
// Encapsulates external OTP gateway API calls for Kazumi, Intaleq, and Nabeh.
|
||||
|
||||
/**
|
||||
* Send SMS OTP via Kazumi SMS Gateway (Egypt)
|
||||
*
|
||||
* @param string $receiver Recipient phone number (e.g. +2010xxxxxxxx)
|
||||
* @param string $otp 3-digit verification code
|
||||
* @return bool True if OTP was sent successfully
|
||||
*/
|
||||
function sendKazumiSms(string $receiver, string $otp): bool {
|
||||
$username = getenv('SMS_USERNAME');
|
||||
$password = getenv('SMS_PASSWORD_EGYPT');
|
||||
$sender = getenv('SMS_SENDER');
|
||||
|
||||
if (!$username || !$password || !$sender) {
|
||||
error_log("⚠️ [Kazumi OTP] Missing credentials in environment variables.");
|
||||
return false;
|
||||
}
|
||||
|
||||
$message = "Siro app code is " . $otp;
|
||||
$apiUrl = 'https://sms.kazumi.me/api/sms/send-sms';
|
||||
|
||||
$payload = [
|
||||
'username' => $username,
|
||||
'password' => $password,
|
||||
'language' => 'e',
|
||||
'sender' => $sender,
|
||||
'receiver' => $receiver,
|
||||
'message' => $message
|
||||
];
|
||||
|
||||
$response = curlCall("POST", $apiUrl, json_encode($payload), [
|
||||
"Content-Type: application/json"
|
||||
]);
|
||||
|
||||
if ($response) {
|
||||
$decoded = json_decode($response, true);
|
||||
if (isset($decoded['message']) && $decoded['message'] === 'Success') {
|
||||
return true;
|
||||
}
|
||||
error_log("❌ [Kazumi OTP] API returned failure response: " . $response);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve Nabeh JWT Bearer Token, caching it in Redis for 24 hours.
|
||||
*
|
||||
* @return string|null The Bearer token, or null on failure.
|
||||
*/
|
||||
function getNabehBearerToken(): ?string {
|
||||
global $redis;
|
||||
|
||||
// 1. Try to read cached token from Redis (TTL 24 hours)
|
||||
if ($redis) {
|
||||
try {
|
||||
$cachedToken = $redis->get('nabeh_bearer_token');
|
||||
if ($cachedToken) {
|
||||
return $cachedToken;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
error_log("⚠️ [Nabeh Auth Redis] Error reading token: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Token not cached, authenticate via Nabeh Login API
|
||||
$email = getenv('NABEH_EMAIL');
|
||||
$password = getenv('NABEH_PASSWORD');
|
||||
|
||||
if (!$email || !$password) {
|
||||
error_log("⚠️ [Nabeh Auth] Missing NABEH_EMAIL or NABEH_PASSWORD environment variables.");
|
||||
return null;
|
||||
}
|
||||
|
||||
$apiUrl = 'https://nabeh.intaleqapp.com/api/auth/login';
|
||||
$payload = [
|
||||
'email' => $email,
|
||||
'password' => $password
|
||||
];
|
||||
|
||||
$response = curlCall("POST", $apiUrl, json_encode($payload), [
|
||||
'Content-Type: application/json'
|
||||
]);
|
||||
|
||||
if ($response) {
|
||||
$decoded = json_decode($response, true);
|
||||
$token = $decoded['token'] ?? $decoded['message']['token'] ?? $decoded['jwt'] ?? $decoded['access_token'] ?? null;
|
||||
|
||||
if ($token) {
|
||||
// Cache token in Redis for 24 hours (86400 seconds)
|
||||
if ($redis) {
|
||||
try {
|
||||
$redis->setex('nabeh_bearer_token', 86400, $token);
|
||||
} catch (Exception $e) {
|
||||
error_log("⚠️ [Nabeh Auth Redis Cache Save] Error saving token: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
return $token;
|
||||
}
|
||||
error_log("❌ [Nabeh Auth] Failed to extract token from login response: " . $response);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send OTP via Nabeh JWT Auth Gateway (WhatsApp, Voice, etc.)
|
||||
*
|
||||
* @param string $receiver Recipient phone number
|
||||
* @param string $otp 3-digit verification code
|
||||
* @param string $method text | voice | image | whatsapp
|
||||
* @return bool True if OTP was sent successfully
|
||||
*/
|
||||
function sendNabehOtp(string $receiver, string $otp, string $method = 'text'): bool {
|
||||
$bearerToken = getNabehBearerToken();
|
||||
if (!$bearerToken) {
|
||||
error_log("⚠️ [Nabeh OTP] Failed to obtain dynamic JWT Bearer token.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Strip symbols for Nabeh endpoint
|
||||
$phoneRaw = preg_replace('/\D+/', '', $receiver);
|
||||
|
||||
// Map method/type
|
||||
$type = 'text';
|
||||
if ($method === 'voice') {
|
||||
$type = 'voice';
|
||||
} elseif ($method === 'image') {
|
||||
$type = 'image';
|
||||
}
|
||||
// elseif ($method === 'flash_call') {
|
||||
// $type = 'flash_call';
|
||||
// }
|
||||
|
||||
$apiUrl = 'https://nabeh.intaleqapp.com/api/otp/send';
|
||||
$payload = [
|
||||
'phone' => $phoneRaw,
|
||||
'type' => $type,
|
||||
'code' => $otp
|
||||
];
|
||||
|
||||
$response = curlCall("POST", $apiUrl, json_encode($payload), [
|
||||
'Content-Type: application/json',
|
||||
"Authorization: Bearer $bearerToken"
|
||||
]);
|
||||
|
||||
if ($response) {
|
||||
$decoded = json_decode($response, true);
|
||||
if ($decoded && ($decoded['success'] ?? false)) {
|
||||
return true;
|
||||
}
|
||||
error_log("❌ [Nabeh OTP] API returned failure response: " . $response);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send OTP via Intaleq Static OTP Gateway (using body app_key parameter)
|
||||
*
|
||||
* @param string $receiver Recipient phone number
|
||||
* @param string $otp 3-digit verification code
|
||||
* @param string $method whatsapp | sms | voice | flash_call
|
||||
* @return bool True if OTP was sent successfully
|
||||
*/
|
||||
function sendIntaleqOtp(string $receiver, string $otp, string $method = 'whatsapp'): bool {
|
||||
$appKey = getenv('NABEH_OTP_APP_KEY');
|
||||
|
||||
if (!$appKey) {
|
||||
error_log("⚠️ [Intaleq OTP] Missing NABEH_OTP_APP_KEY in environment.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Normalize receiver to start with +
|
||||
$phoneWithPlus = (strpos($receiver, '+') === 0) ? $receiver : '+' . $receiver;
|
||||
|
||||
$apiUrl = 'https://otp.intaleqapp.com/api/request-otp.php';
|
||||
$payload = [
|
||||
'phone' => $phoneWithPlus,
|
||||
'app_key' => $appKey,
|
||||
'device_type' => 'android',
|
||||
'method' => $method,
|
||||
'code' => $otp
|
||||
];
|
||||
|
||||
$response = curlCall("POST", $apiUrl, json_encode($payload), [
|
||||
'Content-Type: application/json'
|
||||
]);
|
||||
|
||||
if ($response) {
|
||||
$decoded = json_decode($response, true);
|
||||
if ($decoded && ($decoded['success'] ?? false)) {
|
||||
return true;
|
||||
}
|
||||
error_log("❌ [Intaleq OTP] API returned failure response: " . $response);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic cURL execution helper
|
||||
*/
|
||||
function curlCall(string $method, string $url, string $data, array $headers): ?string {
|
||||
$ch = curl_init($url);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_CUSTOMREQUEST => $method,
|
||||
CURLOPT_POSTFIELDS => $data,
|
||||
CURLOPT_HTTPHEADER => $headers,
|
||||
CURLOPT_TIMEOUT => 15,
|
||||
CURLOPT_CONNECTTIMEOUT => 5
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$error = curl_error($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
if ($error) {
|
||||
error_log("⚠️ [OTP cURL] Error calling $url: $error");
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($httpCode !== 200) {
|
||||
error_log("⚠️ [OTP cURL] Non-200 HTTP code $httpCode from $url. Response: $response");
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
260
backend/auth/otp/request.php
Normal file
260
backend/auth/otp/request.php
Normal file
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
// File: backend/auth/otp/request.php
|
||||
// Unified OTP request endpoint with geographical routing (Syria, Egypt, Jordan)
|
||||
|
||||
require_once __DIR__ . '/../../core/bootstrap.php';
|
||||
require_once __DIR__ . '/../../functions.php';
|
||||
require_once __DIR__ . '/providers.php';
|
||||
|
||||
// 1. Rate Limiting check (max 3 requests per 5 minutes per IP)
|
||||
$limiter = new RateLimiter($redis);
|
||||
$limiter->enforce(RateLimiter::identifier(), 'otp');
|
||||
|
||||
// 2. Fetch input parameters
|
||||
$receiver = filterRequest("receiver");
|
||||
if (empty($receiver)) {
|
||||
$receiver = filterRequest("phone_number");
|
||||
}
|
||||
|
||||
$user_type = filterRequest("user_type");
|
||||
|
||||
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? (function_exists('apache_request_headers') ? (apache_request_headers()['Authorization'] ?? null) : null);
|
||||
if (!empty($authHeader) && preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) {
|
||||
$jwtToken = $matches[1];
|
||||
$tokenParts = explode('.', $jwtToken);
|
||||
if (count($tokenParts) === 3) {
|
||||
$payload = json_decode(base64_decode($tokenParts[1]), true);
|
||||
if (isset($payload['role'])) {
|
||||
$user_type = $payload['role'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$country = filterRequest("country"); // Egypt | Syria | Jordan
|
||||
$method = filterRequest("method"); // whatsapp | sms | voice | flash_call | bearer_send
|
||||
$context = filterRequest("context"); // token_change | login (default)
|
||||
|
||||
// For driver registration context
|
||||
$driverId = filterRequest("driverId");
|
||||
$email = filterRequest("email");
|
||||
|
||||
if (empty($receiver)) {
|
||||
jsonError("Phone number (receiver) is required.");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Auto-detect country if empty
|
||||
if (empty($country)) {
|
||||
$cleanReceiver = preg_replace('/\D+/', '', $receiver);
|
||||
if (strpos($cleanReceiver, '20') === 0 || (strlen($cleanReceiver) === 11 && strpos($cleanReceiver, '01') === 0)) {
|
||||
$country = 'Egypt';
|
||||
} elseif (strpos($cleanReceiver, '962') === 0 || (strlen($cleanReceiver) === 9 && strpos($cleanReceiver, '7') === 0)) {
|
||||
$country = 'Jordan';
|
||||
} elseif (strpos($cleanReceiver, '963') === 0 || (strlen($cleanReceiver) === 9 && strpos($cleanReceiver, '9') === 0)) {
|
||||
$country = 'Syria';
|
||||
} else {
|
||||
$country = 'Jordan'; // Default fallback
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-detect user_type if empty
|
||||
if (empty($user_type)) {
|
||||
if (!empty($driverId) || strpos($_SERVER['REQUEST_URI'], 'driver') !== false) {
|
||||
$user_type = 'driver';
|
||||
} else {
|
||||
$user_type = 'passenger';
|
||||
}
|
||||
}
|
||||
if (empty($user_type) || !in_array($user_type, ['passenger', 'driver', 'admin', 'service'])) {
|
||||
jsonError("User type must be 'passenger', 'driver', 'admin', or 'service'.");
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($user_type === 'admin') {
|
||||
$allowedPhones = explode(',', getenv('ADMIN_PHONE_NUMBERS'));
|
||||
if (!in_array($receiver, $allowedPhones)) {
|
||||
error_log("⚠️ [Admin OTP] Unauthorized phone number attempted: $receiver");
|
||||
jsonError("رقم الهاتف غير مصرح له.");
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Establish DB Connection
|
||||
try {
|
||||
$con = Database::get('main');
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
exit(json_encode(['error' => 'Database connection failed']));
|
||||
}
|
||||
|
||||
// 4. Generate 3-digit OTP code
|
||||
$otp = str_pad((string)random_int(0, 999), 3, '0', STR_PAD_LEFT);
|
||||
|
||||
// 5. Geographical Routing & Dispatch
|
||||
$sentSuccessfully = false;
|
||||
|
||||
switch (strtolower($country)) {
|
||||
case 'egypt':
|
||||
$sentSuccessfully = sendKazumiSms($receiver, $otp);
|
||||
if (!$sentSuccessfully) {
|
||||
error_log("⚠️ [Egypt OTP Failover 1] Kazumi SMS failed. Falling back to Intaleq OTP WhatsApp.");
|
||||
$sentSuccessfully = sendIntaleqOtp($receiver, $otp, 'whatsapp');
|
||||
if (!$sentSuccessfully) {
|
||||
error_log("⚠️ [Egypt OTP Failover 2] Intaleq OTP WhatsApp failed. Falling back to Nabeh JWT OTP text.");
|
||||
$sentSuccessfully = sendNabehOtp($receiver, $otp, 'text');
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'syria':
|
||||
// Syria uses dynamic Nabeh JWT for voice/image, static Intaleq app_key for whatsapp/sms
|
||||
if ($method === 'bearer_send' || $method === 'voice' || $method === 'image') {
|
||||
$sentSuccessfully = sendNabehOtp($receiver, $otp, $method);
|
||||
if (!$sentSuccessfully) {
|
||||
error_log("⚠️ [Syria OTP Failover] Nabeh JWT method failed. Falling back to Intaleq OTP WhatsApp.");
|
||||
$sentSuccessfully = sendIntaleqOtp($receiver, $otp, 'whatsapp');
|
||||
}
|
||||
} else {
|
||||
$sentSuccessfully = sendIntaleqOtp($receiver, $otp, $method ?: 'whatsapp');
|
||||
if (!$sentSuccessfully) {
|
||||
error_log("⚠️ [Syria OTP Failover] Intaleq OTP WhatsApp failed. Falling back to Nabeh JWT OTP text.");
|
||||
$sentSuccessfully = sendNabehOtp($receiver, $otp, 'text');
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'jordan':
|
||||
// Jordan uses dynamic Nabeh JWT for voice/image, static Intaleq app_key for sms/whatsapp
|
||||
if ($method === 'bearer_send' || $method === 'voice' || $method === 'image') {
|
||||
$sentSuccessfully = sendNabehOtp($receiver, $otp, $method);
|
||||
if (!$sentSuccessfully) {
|
||||
error_log("⚠️ [Jordan OTP Failover] Nabeh JWT method failed. Falling back to Intaleq OTP SMS.");
|
||||
$sentSuccessfully = sendIntaleqOtp($receiver, $otp, 'sms');
|
||||
}
|
||||
} else {
|
||||
$sentSuccessfully = sendIntaleqOtp($receiver, $otp, $method ?: 'sms');
|
||||
if (!$sentSuccessfully) {
|
||||
error_log("⚠️ [Jordan OTP Failover] Intaleq OTP SMS failed. Falling back to Nabeh JWT OTP text.");
|
||||
$sentSuccessfully = sendNabehOtp($receiver, $otp, 'text');
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Default fallback to Kazumi SMS
|
||||
$sentSuccessfully = sendKazumiSms($receiver, $otp);
|
||||
if (!$sentSuccessfully) {
|
||||
error_log("⚠️ [Default OTP Failover] Kazumi SMS failed. Falling back to Intaleq OTP WhatsApp.");
|
||||
$sentSuccessfully = sendIntaleqOtp($receiver, $otp, 'whatsapp');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// 6. DB Storage on Success
|
||||
if ($sentSuccessfully) {
|
||||
$encryptedPhone = $encryptionHelper->encryptData($receiver);
|
||||
$encryptedOtp = $encryptionHelper->encryptData($otp);
|
||||
$encryptedEmail = !empty($email) ? $encryptionHelper->encryptData($email) : '';
|
||||
|
||||
$expirationTime = date('Y-m-d H:i:s', strtotime('+5 minutes'));
|
||||
|
||||
try {
|
||||
if ($user_type === 'admin') {
|
||||
$stmt = $con->prepare("INSERT INTO token_verification_admin (phone_number, token, expiration_time)
|
||||
VALUES (?, ?, DATE_ADD(NOW(), INTERVAL 5 MINUTE))
|
||||
ON DUPLICATE KEY UPDATE token = VALUES(token), expiration_time = VALUES(expiration_time)");
|
||||
$stmt->execute([$encryptedPhone, $encryptedOtp]);
|
||||
} elseif ($user_type === 'service') {
|
||||
$stmtDel = $con->prepare("DELETE FROM `phone_verification_service` WHERE `phone_number` = ?");
|
||||
$stmtDel->execute([$encryptedPhone]);
|
||||
|
||||
$stmtIns = $con->prepare("
|
||||
INSERT INTO `phone_verification_service`
|
||||
(`phone_number`, `token_code`, `expiration_time`, `is_verified`, `created_at`)
|
||||
VALUES (?, ?, ?, 0, NOW())
|
||||
");
|
||||
$stmtIns->execute([
|
||||
$encryptedPhone,
|
||||
$encryptedOtp,
|
||||
$expirationTime
|
||||
]);
|
||||
} elseif ($user_type === 'driver') {
|
||||
if ($context === 'token_change') {
|
||||
// Delete old verification attempts
|
||||
$stmtDel = $con->prepare("DELETE FROM `token_verification_driver` WHERE `phone_number` = ?");
|
||||
$stmtDel->execute([$encryptedPhone]);
|
||||
|
||||
// Insert new attempt
|
||||
$stmtIns = $con->prepare("
|
||||
INSERT INTO `token_verification_driver`
|
||||
(`phone_number`, `token`, `expiration_time`, `verified`, `created_at`)
|
||||
VALUES (?, ?, ?, 0, NOW())
|
||||
");
|
||||
$stmtIns->execute([
|
||||
$encryptedPhone,
|
||||
$encryptedOtp,
|
||||
$expirationTime
|
||||
]);
|
||||
} else {
|
||||
// Delete old verification attempts
|
||||
$stmtDel = $con->prepare("DELETE FROM `phone_verification` WHERE `phone_number` = ?");
|
||||
$stmtDel->execute([$encryptedPhone]);
|
||||
|
||||
// Insert new attempt
|
||||
$stmtIns = $con->prepare("
|
||||
INSERT INTO `phone_verification`
|
||||
(`phone_number`, `driverId`, `email`, `token_code`, `expiration_time`, `is_verified`, `created_at`)
|
||||
VALUES (?, ?, ?, ?, ?, 0, NOW())
|
||||
");
|
||||
$stmtIns->execute([
|
||||
$encryptedPhone,
|
||||
$driverId ?: '',
|
||||
$encryptedEmail,
|
||||
$encryptedOtp,
|
||||
$expirationTime
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
if ($context === 'token_change') {
|
||||
// Delete old verification attempts
|
||||
$stmtDel = $con->prepare("DELETE FROM `token_verification` WHERE `phone_number` = ?");
|
||||
$stmtDel->execute([$encryptedPhone]);
|
||||
|
||||
// Insert new attempt
|
||||
$stmtIns = $con->prepare("
|
||||
INSERT INTO `token_verification`
|
||||
(`phone_number`, `token`, `expiration_time`, `verified`, `created_at`)
|
||||
VALUES (?, ?, ?, 0, NOW())
|
||||
");
|
||||
$stmtIns->execute([
|
||||
$encryptedPhone,
|
||||
$encryptedOtp,
|
||||
$expirationTime
|
||||
]);
|
||||
} else {
|
||||
// Delete old verification attempts
|
||||
$stmtDel = $con->prepare("DELETE FROM `phone_verification_passenger` WHERE `phone_number` = ?");
|
||||
$stmtDel->execute([$encryptedPhone]);
|
||||
|
||||
// Insert new attempt
|
||||
$stmtIns = $con->prepare("
|
||||
INSERT INTO `phone_verification_passenger`
|
||||
(`phone_number`, `token`, `expiration_time`, `verified`, `created_at`)
|
||||
VALUES (?, ?, ?, 0, NOW())
|
||||
");
|
||||
$stmtIns->execute([
|
||||
$encryptedPhone,
|
||||
$encryptedOtp,
|
||||
$expirationTime
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
jsonSuccess(null, "OTP sent and saved successfully");
|
||||
} catch (PDOException $e) {
|
||||
error_log("⚠️ [OTP DB Save] Error: " . $e->getMessage());
|
||||
jsonError("OTP sent but failed to save verification data");
|
||||
}
|
||||
} else {
|
||||
jsonError("Failed to send verification code. Please try again.");
|
||||
}
|
||||
222
backend/auth/otp/verify.php
Normal file
222
backend/auth/otp/verify.php
Normal file
@@ -0,0 +1,222 @@
|
||||
<?php
|
||||
// File: backend/auth/otp/verify.php
|
||||
// Unified OTP verification endpoint
|
||||
|
||||
require_once __DIR__ . '/../../core/bootstrap.php';
|
||||
require_once __DIR__ . '/../../functions.php';
|
||||
|
||||
// 0. Rate Limiting: 3 محاولات OTP كل 5 دقائق لكل IP
|
||||
$rateLimiter = new RateLimiter($redis);
|
||||
$rateLimiter->enforce(RateLimiter::identifier(), 'otp');
|
||||
|
||||
// 1. Fetch input parameters
|
||||
$phone_number = filterRequest("phone_number");
|
||||
if (empty($phone_number)) {
|
||||
$phone_number = filterRequest("receiver");
|
||||
}
|
||||
|
||||
$token_code = filterRequest("token_code");
|
||||
if (empty($token_code)) {
|
||||
$token_code = filterRequest("token");
|
||||
}
|
||||
|
||||
$user_type = filterRequest("user_type");
|
||||
$context = filterRequest("context"); // token_change | login (default)
|
||||
|
||||
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? (function_exists('apache_request_headers') ? (apache_request_headers()['Authorization'] ?? null) : null);
|
||||
if (!empty($authHeader) && preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) {
|
||||
$jwtToken = $matches[1];
|
||||
$tokenParts = explode('.', $jwtToken);
|
||||
if (count($tokenParts) === 3) {
|
||||
$payload = json_decode(base64_decode($tokenParts[1]), true);
|
||||
if (isset($payload['role'])) {
|
||||
$user_type = $payload['role'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($phone_number)) {
|
||||
jsonError("Phone number is required.");
|
||||
exit;
|
||||
}
|
||||
|
||||
if (empty($token_code)) {
|
||||
jsonError("Verification token code is required.");
|
||||
exit;
|
||||
}
|
||||
|
||||
if (empty($user_type)) {
|
||||
if (strpos($_SERVER['REQUEST_URI'], 'driver') !== false) {
|
||||
$user_type = 'driver';
|
||||
} else {
|
||||
$user_type = 'passenger';
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($user_type) || !in_array($user_type, ['passenger', 'driver', 'admin', 'service'])) {
|
||||
jsonError("User type must be 'passenger', 'driver', 'admin', or 'service'.");
|
||||
exit;
|
||||
}
|
||||
|
||||
// 2. Establish DB Connection
|
||||
try {
|
||||
$con = Database::get('main');
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
exit(json_encode(['error' => 'Database connection failed']));
|
||||
}
|
||||
|
||||
// 3. Encrypt data to query
|
||||
$encryptedPhone = $encryptionHelper->encryptData($phone_number);
|
||||
$encryptedToken = $encryptionHelper->encryptData($token_code);
|
||||
|
||||
// 4. Verify based on user type
|
||||
try {
|
||||
if ($user_type === 'admin') {
|
||||
$sql = "SELECT * FROM token_verification_admin
|
||||
WHERE phone_number = :phone AND token = :token
|
||||
AND expiration_time >= NOW()";
|
||||
$stmt = $con->prepare($sql);
|
||||
$stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
||||
$stmt->bindParam(':token', $encryptedToken, PDO::PARAM_STR);
|
||||
$stmt->execute();
|
||||
|
||||
if ($stmt->rowCount() > 0) {
|
||||
$deviceNumber = filterRequest("device_number") ?? '';
|
||||
// adminUser stores unencrypted phone
|
||||
$checkAdmin = $con->prepare("SELECT * FROM adminUser WHERE name = ?");
|
||||
$checkAdmin->execute([$phone_number]);
|
||||
$now = date("Y-m-d H:i:s");
|
||||
|
||||
if ($checkAdmin->rowCount() > 0) {
|
||||
$update = $con->prepare("UPDATE adminUser SET device_number = ?, updated_at = ? WHERE name = ?");
|
||||
$update->execute([$deviceNumber, $now, $phone_number]);
|
||||
jsonSuccess(["message" => "verified and updated existing admin"]);
|
||||
} else {
|
||||
$insert = $con->prepare("INSERT INTO adminUser (device_number, name, created_at, updated_at) VALUES (?, ?, ?, ?)");
|
||||
$insert->execute([$deviceNumber, $phone_number, $now, $now]);
|
||||
jsonSuccess(["message" => "verified and new admin created"]);
|
||||
}
|
||||
} else {
|
||||
jsonError("Your phone number could not be verified or the code is expired. Please try again.");
|
||||
}
|
||||
} elseif ($user_type === 'service') {
|
||||
$sql = "SELECT `id` FROM `phone_verification_service`
|
||||
WHERE `phone_number` = :phone AND `token_code` = :token
|
||||
AND `expiration_time` > NOW()";
|
||||
$stmt = $con->prepare($sql);
|
||||
$stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
||||
$stmt->bindParam(':token', $encryptedToken, PDO::PARAM_STR);
|
||||
$stmt->execute();
|
||||
$result = $stmt->fetch();
|
||||
|
||||
if ($result) {
|
||||
$sqlUpdate = "UPDATE `phone_verification_service` SET `is_verified` = 1 WHERE `phone_number` = :phone";
|
||||
$stmtUpd = $con->prepare($sqlUpdate);
|
||||
$stmtUpd->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
||||
$stmtUpd->execute();
|
||||
jsonSuccess(null, "Your phone number has been verified.");
|
||||
} else {
|
||||
jsonError("Your phone number could not be verified or the code is expired. Please try again.");
|
||||
}
|
||||
} elseif ($user_type === 'driver') {
|
||||
if ($context === 'token_change') {
|
||||
$sql = "SELECT `id` FROM `token_verification_driver`
|
||||
WHERE `phone_number` = :phone
|
||||
AND `token` = :token
|
||||
AND `expiration_time` > NOW()";
|
||||
|
||||
$stmt = $con->prepare($sql);
|
||||
$stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
||||
$stmt->bindParam(':token', $encryptedToken, PDO::PARAM_STR);
|
||||
$stmt->execute();
|
||||
$result = $stmt->fetch();
|
||||
|
||||
if ($result) {
|
||||
// Update driver verified status
|
||||
$sqlUpdate = "UPDATE `token_verification_driver` SET `verified` = 1 WHERE `phone_number` = :phone";
|
||||
$stmtUpd = $con->prepare($sqlUpdate);
|
||||
$stmtUpd->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
||||
$stmtUpd->execute();
|
||||
|
||||
jsonSuccess(null, "Your phone number has been verified.");
|
||||
} else {
|
||||
jsonError("Your phone number could not be verified or the code is expired. Please try again.");
|
||||
}
|
||||
} else {
|
||||
$sql = "SELECT `id` FROM `phone_verification`
|
||||
WHERE `phone_number` = :phone
|
||||
AND `token_code` = :token
|
||||
AND `expiration_time` > NOW()";
|
||||
|
||||
$stmt = $con->prepare($sql);
|
||||
$stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
||||
$stmt->bindParam(':token', $encryptedToken, PDO::PARAM_STR);
|
||||
$stmt->execute();
|
||||
$result = $stmt->fetch();
|
||||
|
||||
if ($result) {
|
||||
// Update driver is_verified status
|
||||
$sqlUpdate = "UPDATE `phone_verification` SET `is_verified` = 1 WHERE `phone_number` = :phone";
|
||||
$stmtUpd = $con->prepare($sqlUpdate);
|
||||
$stmtUpd->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
||||
$stmtUpd->execute();
|
||||
|
||||
jsonSuccess(null, "Your phone number has been verified.");
|
||||
} else {
|
||||
jsonError("Your phone number could not be verified or the code is expired. Please try again.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($context === 'token_change') {
|
||||
$sql = "SELECT `id` FROM `token_verification`
|
||||
WHERE `phone_number` = :phone
|
||||
AND `token` = :token
|
||||
AND `expiration_time` > NOW()";
|
||||
|
||||
$stmt = $con->prepare($sql);
|
||||
$stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
||||
$stmt->bindParam(':token', $encryptedToken, PDO::PARAM_STR);
|
||||
$stmt->execute();
|
||||
$result = $stmt->fetch();
|
||||
|
||||
if ($result) {
|
||||
// Update passenger verified status
|
||||
$sqlUpdate = "UPDATE `token_verification` SET `verified` = 1 WHERE `phone_number` = :phone";
|
||||
$stmtUpd = $con->prepare($sqlUpdate);
|
||||
$stmtUpd->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
||||
$stmtUpd->execute();
|
||||
|
||||
jsonSuccess(null, "Your phone number has been verified.");
|
||||
} else {
|
||||
jsonError("Your phone number could not be verified or the code is expired. Please try again.");
|
||||
}
|
||||
} else {
|
||||
$sql = "SELECT `id` FROM `phone_verification_passenger`
|
||||
WHERE `phone_number` = :phone
|
||||
AND `token` = :token
|
||||
AND `expiration_time` > NOW()";
|
||||
|
||||
$stmt = $con->prepare($sql);
|
||||
$stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
||||
$stmt->bindParam(':token', $encryptedToken, PDO::PARAM_STR);
|
||||
$stmt->execute();
|
||||
$result = $stmt->fetch();
|
||||
|
||||
if ($result) {
|
||||
// Update passenger verified status
|
||||
$sqlUpdate = "UPDATE `phone_verification_passenger` SET `verified` = 1 WHERE `phone_number` = :phone";
|
||||
$stmtUpd = $con->prepare($sqlUpdate);
|
||||
$stmtUpd->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
||||
$stmtUpd->execute();
|
||||
|
||||
jsonSuccess(null, "Your phone number has been verified.");
|
||||
} else {
|
||||
jsonError("Your phone number could not be verified or the code is expired. Please try again.");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
error_log("⚠️ [OTP DB Verify] Error: " . $e->getMessage());
|
||||
jsonError("An error occurred during verification. Please try again.");
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
?>
|
||||
@@ -1,42 +0,0 @@
|
||||
<?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");
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,28 +0,0 @@
|
||||
<?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.");
|
||||
}
|
||||
?>
|
||||
6
backend/auth/sendEmail.php
Executable file → Normal file
6
backend/auth/sendEmail.php
Executable file → Normal file
@@ -4,7 +4,7 @@ require_once __DIR__ . '/../connect.php';
|
||||
$email = filterRequest("email");
|
||||
$token = filterRequest("token");
|
||||
|
||||
$admin='support@sefer.live';
|
||||
$admin='support@siromove.com';
|
||||
$headers = "MIME-Version: 1.0" . "\r\n";
|
||||
$headers .= "Content-type: text/html; charset=UTF-8" . "\r\n";
|
||||
$headers .= "From: $admin" . "\r\n";
|
||||
@@ -18,7 +18,7 @@ $bodyEmail = "
|
||||
<body>
|
||||
<p>Hi [$email],</p>
|
||||
|
||||
<p>We recently received a request to verify your email address for your account on SEFER App.</p>
|
||||
<p>We recently received a request to verify your email address for your account on Siro App.</p>
|
||||
|
||||
<p>To verify your email address, please write this to app .</p>
|
||||
$token
|
||||
@@ -26,7 +26,7 @@ $token
|
||||
<p>If you did not request to verify your email address, please ignore this email.</p>
|
||||
|
||||
<p>Thank you,</p>
|
||||
SEFER Team.
|
||||
Siro Team.
|
||||
</body>
|
||||
</html>
|
||||
";
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
<?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");
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,68 +0,0 @@
|
||||
<?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"]);
|
||||
?>
|
||||
@@ -1,27 +0,0 @@
|
||||
<?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");
|
||||
}
|
||||
?>
|
||||
@@ -1,23 +0,0 @@
|
||||
<?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");
|
||||
}
|
||||
?>
|
||||
@@ -1,134 +0,0 @@
|
||||
<?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)
|
||||
|
||||
|
||||
?>
|
||||
@@ -1,107 +0,0 @@
|
||||
<?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");
|
||||
|
||||
// Rate Limiting للحماية من هجمات استنزاف الرسائل
|
||||
if (isset($redis) && !empty($receiver)) {
|
||||
$redisKey = "otp_limit:passenger:$receiver";
|
||||
if ($redis->exists($redisKey)) {
|
||||
jsonError("Please wait before requesting a new OTP.");
|
||||
exit;
|
||||
}
|
||||
$redis->setex($redisKey, 60, "1"); // حظر لمدة 60 ثانية
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,75 +0,0 @@
|
||||
<?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 = 'siroapp://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();
|
||||
}
|
||||
?>
|
||||
@@ -1,85 +0,0 @@
|
||||
<?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);
|
||||
0
backend/auth/syria/driver/driver_details.php
Executable file → Normal file
0
backend/auth/syria/driver/driver_details.php
Executable file → Normal file
0
backend/auth/syria/driver/drivers_pending_list.php
Executable file → Normal file
0
backend/auth/syria/driver/drivers_pending_list.php
Executable file → Normal file
0
backend/auth/syria/driver/isPhoneVerified.php
Executable file → Normal file
0
backend/auth/syria/driver/isPhoneVerified.php
Executable file → Normal file
0
backend/auth/syria/driver/register_driver_and_car.php
Executable file → Normal file
0
backend/auth/syria/driver/register_driver_and_car.php
Executable file → Normal file
0
backend/auth/syria/driver/register_driver_and_car_signed.php
Executable file → Normal file
0
backend/auth/syria/driver/register_driver_and_car_signed.php
Executable file → Normal file
@@ -1,109 +0,0 @@
|
||||
<?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 (3 خانات) */
|
||||
$otp = (string)rand(100, 999);
|
||||
|
||||
/* 2) إرسال الرمز عبر بوابة الفلاش كول / واتساب */
|
||||
$nabehUrl = 'https://otp.intaleqapp.com/api/request-otp.php';
|
||||
$appKey = getenv('NABEH_OTP_APP_KEY');
|
||||
|
||||
$phoneWithPlus = (strpos($receiver, '+') === 0) ? $receiver : '+' . $receiver;
|
||||
|
||||
$payload = [
|
||||
'phone' => $phoneWithPlus,
|
||||
'device_type' => 'android',
|
||||
'method' => 'whatsapp',
|
||||
'code' => $otp
|
||||
];
|
||||
|
||||
$ch = curl_init($nabehUrl);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_POSTFIELDS => json_encode($payload),
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Content-Type: application/json',
|
||||
"X-App-Key: $appKey"
|
||||
],
|
||||
CURLOPT_TIMEOUT => 15,
|
||||
CURLOPT_CONNECTTIMEOUT => 5
|
||||
]);
|
||||
|
||||
$res = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$error = curl_error($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ($error) {
|
||||
error_log("⚠️ [Flash Call OTP Driver] Curl Error: $error");
|
||||
jsonError('Failed to connect to OTP service');
|
||||
exit;
|
||||
}
|
||||
|
||||
$decoded = json_decode((string)$res, true);
|
||||
if ($httpCode !== 200 || !($decoded['success'] ?? false)) {
|
||||
error_log("❌ [Flash Call OTP Driver] Failed response: Code $httpCode | Body: " . (string)$res);
|
||||
jsonError($decoded['message'] ?? 'Failed to request verification code');
|
||||
exit;
|
||||
}
|
||||
|
||||
/* 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 sent and saved successfully');
|
||||
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');
|
||||
}
|
||||
?>
|
||||
@@ -1,96 +0,0 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../../connect.php';
|
||||
|
||||
$phoneNumber = filterRequest("phone_number");
|
||||
$otp = filterRequest("otp");
|
||||
$email = $phoneNumber . '@intaleqapp.com';
|
||||
|
||||
error_log("📥 [verifyOtp.php] Received phone number: $phoneNumber | OTP: $otp");
|
||||
|
||||
if (empty($phoneNumber) || empty($otp)) {
|
||||
jsonError("Phone number and OTP are required.");
|
||||
exit();
|
||||
}
|
||||
|
||||
// 🔐 تشفير البيانات
|
||||
$phoneNumber_encrypted = $encryptionHelper->encryptData($phoneNumber);
|
||||
$email_encrypted = $encryptionHelper->encryptData($email);
|
||||
|
||||
try {
|
||||
// 🔍 1. التحقق من السجل المخزن في قاعدة البيانات
|
||||
$stmtSelect = $con->prepare("SELECT * FROM phone_verification WHERE phone_number = ? ORDER BY created_at DESC LIMIT 1");
|
||||
$stmtSelect->execute([$phoneNumber_encrypted]);
|
||||
$record = $stmtSelect->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$record) {
|
||||
jsonError("Verification session not found. Please request a new code.");
|
||||
exit();
|
||||
}
|
||||
|
||||
// 🔍 2. فك تشفير ومقارنة الرمز
|
||||
$decryptedOtp = $encryptionHelper->decryptData($record['token_code']);
|
||||
if ($decryptedOtp !== $otp) {
|
||||
jsonError("Invalid verification code.");
|
||||
exit();
|
||||
}
|
||||
|
||||
// 🔍 3. التحقق من الصلاحية
|
||||
$now = date('Y-m-d H:i:s');
|
||||
if ($record['expiration_time'] && $record['expiration_time'] < $now) {
|
||||
jsonError("Verification code has expired. Please request a new one.");
|
||||
exit();
|
||||
}
|
||||
|
||||
// 🧹 حذف أي رموز قديمة لنفس الرقم
|
||||
$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');
|
||||
|
||||
// ✅ إدخال سجل تحقق مباشر
|
||||
$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] 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. Driver not found.");
|
||||
printSuccess([
|
||||
"message" => "Phone number verified successfully.",
|
||||
"isRegistered" => false,
|
||||
"driverID" => $driverID
|
||||
]);
|
||||
}
|
||||
|
||||
} catch (PDOException $e) {
|
||||
error_log("💥 [verifyOtp.php] PDO ERROR: " . $e->getMessage());
|
||||
jsonError("Database error: " . $e->getMessage());
|
||||
}
|
||||
?>
|
||||
0
backend/auth/syria/register_passenger.php
Executable file → Normal file
0
backend/auth/syria/register_passenger.php
Executable file → Normal file
@@ -1,72 +0,0 @@
|
||||
<?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);
|
||||
@@ -1,119 +0,0 @@
|
||||
<?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 (3 digits) */
|
||||
$otp = (string)rand(100, 999);
|
||||
|
||||
/* 2) Send via Flash Call / WhatsApp Gateway */
|
||||
$nabehUrl = 'https://otp.intaleqapp.com/api/request-otp.php';
|
||||
$appKey = getenv('NABEH_OTP_APP_KEY');
|
||||
|
||||
$phoneWithPlus = (strpos($receiver, '+') === 0) ? $receiver : '+' . $receiver;
|
||||
|
||||
$payload = [
|
||||
'phone' => $phoneWithPlus,
|
||||
'device_type' => 'android',
|
||||
'method' => 'whatsapp',
|
||||
'code' => $otp
|
||||
];
|
||||
|
||||
$ch = curl_init($nabehUrl);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_POSTFIELDS => json_encode($payload),
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Content-Type: application/json',
|
||||
"X-App-Key: $appKey"
|
||||
],
|
||||
CURLOPT_TIMEOUT => 15,
|
||||
CURLOPT_CONNECTTIMEOUT => 5
|
||||
]);
|
||||
|
||||
$res = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$error = curl_error($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ($error) {
|
||||
error_log("⚠️ [Flash Call OTP Passenger] Curl Error: $error");
|
||||
jsonError('Failed to connect to OTP service');
|
||||
exit;
|
||||
}
|
||||
|
||||
$decoded = json_decode((string)$res, true);
|
||||
if ($httpCode !== 200 || !($decoded['success'] ?? false)) {
|
||||
error_log("❌ [Flash Call OTP Passenger] Failed response: Code $httpCode | Body: " . (string)$res);
|
||||
jsonError($decoded['message'] ?? 'Failed to request verification code');
|
||||
exit;
|
||||
}
|
||||
|
||||
/* 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 sent and saved successfully');
|
||||
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');
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
<?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("فشل في إرسال استطلاع الرأي");
|
||||
}
|
||||
?>
|
||||
0
backend/auth/syria/uploadSyrianDocs.php
Executable file → Normal file
0
backend/auth/syria/uploadSyrianDocs.php
Executable file → Normal file
@@ -1,114 +0,0 @@
|
||||
<?php
|
||||
$allowRegistration = true;
|
||||
require_once __DIR__ . '/../../connect.php';
|
||||
|
||||
// تسجيل بداية الطلب
|
||||
error_log("[Auth_Debug] Start processing phone verification request.");
|
||||
|
||||
$phoneNumber = filterRequest("phone_number");
|
||||
$otp = filterRequest("otp");
|
||||
|
||||
if (!$phoneNumber) {
|
||||
error_log("[Auth_Error] Phone number is missing in the request.");
|
||||
jsonError("Phone number is required");
|
||||
exit();
|
||||
}
|
||||
|
||||
if (!$otp) {
|
||||
error_log("[Auth_Error] OTP is missing in the request.");
|
||||
jsonError("OTP is required");
|
||||
exit();
|
||||
}
|
||||
|
||||
// تسجيل الرقم
|
||||
error_log("[Auth_Debug] Received phone number (Masked): " . substr($phoneNumber, 0, 7) . "***** | OTP: " . $otp);
|
||||
|
||||
// تشفير رقم الهاتف
|
||||
$phoneNumber_encrypted = $encryptionHelper->encryptData($phoneNumber);
|
||||
error_log("[Auth_Debug] Phone number encrypted successfully.");
|
||||
|
||||
try {
|
||||
// ✅ 1. التحقق من السجل المخزن في قاعدة البيانات
|
||||
$stmtSelect = $con->prepare("SELECT * FROM phone_verification_passenger WHERE phone_number = ? ORDER BY created_at DESC LIMIT 1");
|
||||
$stmtSelect->execute([$phoneNumber_encrypted]);
|
||||
$record = $stmtSelect->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$record) {
|
||||
error_log("[Auth_Error] No verification record found for this number.");
|
||||
jsonError("Verification session not found. Please request a new code.");
|
||||
exit();
|
||||
}
|
||||
|
||||
// ✅ 2. فك تشفير ومقارنة الرمز
|
||||
$decryptedOtp = $encryptionHelper->decryptData($record['token']);
|
||||
if ($decryptedOtp !== $otp) {
|
||||
error_log("[Auth_Error] OTP mismatch. Expected: $decryptedOtp, Got: $otp");
|
||||
jsonError("Invalid verification code.");
|
||||
exit();
|
||||
}
|
||||
|
||||
// ✅ 3. التحقق من الصلاحية (خلال 5 دقائق)
|
||||
$now = date('Y-m-d H:i:s');
|
||||
if ($record['expiration_time'] && $record['expiration_time'] < $now) {
|
||||
error_log("[Auth_Error] OTP expired.");
|
||||
jsonError("Verification code has expired. Please request a new one.");
|
||||
exit();
|
||||
}
|
||||
|
||||
// ✅ 4. حذف السجلات القديمة وإدخال سجل مؤكد (verified = 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]);
|
||||
|
||||
$stmtInsert = $con->prepare("
|
||||
INSERT INTO phone_verification_passenger (phone_number, token, expiration_time, verified, created_at)
|
||||
VALUES (?, NULL, NULL, 1, ?)
|
||||
");
|
||||
$stmtInsert->execute([$phoneNumber_encrypted, $now]);
|
||||
error_log("[Auth_Step_1] Inserted verified record.");
|
||||
|
||||
// ✅ 5. فحص هل الراكب موجود مسبقاً
|
||||
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 successfully.",
|
||||
"isRegistered" => false
|
||||
]);
|
||||
}
|
||||
|
||||
} catch (PDOException $e) {
|
||||
error_log("[Auth_DB_Exception] Error: " . $e->getMessage() . " | File: " . $e->getFile() . " | Line: " . $e->getLine());
|
||||
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.");
|
||||
?>
|
||||
0
backend/auth/token_passenger/driver/send_otp_driver.php
Executable file → Normal file
0
backend/auth/token_passenger/driver/send_otp_driver.php
Executable file → Normal file
0
backend/auth/token_passenger/driver/verify_otp_driver.php
Executable file → Normal file
0
backend/auth/token_passenger/driver/verify_otp_driver.php
Executable file → Normal file
0
backend/auth/token_passenger/send_otp.php
Executable file → Normal file
0
backend/auth/token_passenger/send_otp.php
Executable file → Normal file
0
backend/auth/token_passenger/verify_otp.php
Executable file → Normal file
0
backend/auth/token_passenger/verify_otp.php
Executable file → Normal file
@@ -15,7 +15,7 @@ if ($result) {
|
||||
$stmt = $con->prepare($sql);
|
||||
$stmt->execute([':id' => $id]);
|
||||
|
||||
$admin='support@sefer.com';
|
||||
$admin='support@siromove.com';
|
||||
$headers = "MIME-Version: 1.0" . "\r\n";
|
||||
$headers .= "Content-type: text/html; charset=UTF-8" . "\r\n";
|
||||
$headers .= "From: $admin" . "\r\n";
|
||||
@@ -28,7 +28,7 @@ Hi [$email],
|
||||
Your email address has been verified.
|
||||
|
||||
Thank you,
|
||||
SEFER Team";
|
||||
Siro Team";
|
||||
|
||||
mail($email, $subject, $bodyEmail, $headers);
|
||||
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
<?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.");
|
||||
}
|
||||
?>
|
||||
0
backend/composer.json
Executable file → Normal file
0
backend/composer.json
Executable file → Normal file
0
backend/composer.lock
generated
Executable file → Normal file
0
backend/composer.lock
generated
Executable file → Normal file
0
backend/connect.php
Executable file → Normal file
0
backend/connect.php
Executable file → Normal file
0
backend/driver_assurance/add.php
Executable file → Normal file
0
backend/driver_assurance/add.php
Executable file → Normal file
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user