Compare commits
24 Commits
28d30e3359
...
752bbf3a63
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
752bbf3a63 | ||
|
|
a8748cf4c9 | ||
|
|
3543fdd2cd | ||
|
|
50a5308f43 | ||
|
|
2d607d9e90 | ||
|
|
790d58aaa2 | ||
|
|
72eeb24cd7 | ||
|
|
e51d266a0f | ||
|
|
f528e1d3c5 | ||
|
|
0e28814e7d | ||
|
|
16331bd35d | ||
|
|
623d66a3d8 | ||
|
|
1a9619f9f8 | ||
|
|
70c06edd71 | ||
|
|
75aeb73f27 | ||
|
|
1d3ea597f4 | ||
|
|
3dad979eb5 | ||
|
|
81376a2245 | ||
|
|
c82b0071bb | ||
|
|
0ceb67ee56 | ||
|
|
8c6dea5d96 | ||
|
|
d6f29802e0 | ||
|
|
4a9e6b22c5 | ||
|
|
9bbda24d4a |
97
.gitignore
vendored
Normal file
97
.gitignore
vendored
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
# ============================================================
|
||||||
|
# Siro Project - .gitignore
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
# --- Environment & Secrets ---
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
**/*.env
|
||||||
|
**/private_key.pem
|
||||||
|
**/public_key.pem
|
||||||
|
*.pem
|
||||||
|
service-account.json
|
||||||
|
**/service-account.json
|
||||||
|
|
||||||
|
# --- IDE & OS ---
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
.ruby-lsp/
|
||||||
|
.kilo/
|
||||||
|
|
||||||
|
# --- Build Artifacts ---
|
||||||
|
node_modules/
|
||||||
|
vendor/
|
||||||
|
**/vendor/
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
*.js.map
|
||||||
|
*.css.map
|
||||||
|
|
||||||
|
# --- Flutter/Dart ---
|
||||||
|
.dart_tool/
|
||||||
|
.packages
|
||||||
|
.pub-cache/
|
||||||
|
pubspec.lock
|
||||||
|
*.g.dart
|
||||||
|
**/env.g.dart
|
||||||
|
*.freezed.dart
|
||||||
|
*.config.dart
|
||||||
|
|
||||||
|
# --- Android ---
|
||||||
|
*.apk
|
||||||
|
*.aab
|
||||||
|
*.dex
|
||||||
|
*.class
|
||||||
|
*.keystore
|
||||||
|
local.properties
|
||||||
|
android/.gradle/
|
||||||
|
android/captures/
|
||||||
|
|
||||||
|
# --- iOS ---
|
||||||
|
*.ipa
|
||||||
|
*.dSYM.zip
|
||||||
|
*.dSYM
|
||||||
|
Pods/
|
||||||
|
DerivedData/
|
||||||
|
*.xcworkspace
|
||||||
|
xcuserdata/
|
||||||
|
|
||||||
|
# --- Composer / PHP ---
|
||||||
|
/composer.lock
|
||||||
|
**/composer.lock
|
||||||
|
|
||||||
|
# --- Logs ---
|
||||||
|
*.log
|
||||||
|
logs/
|
||||||
|
**/logs/
|
||||||
|
|
||||||
|
# --- Uploads ---
|
||||||
|
uploads/
|
||||||
|
**/uploads/
|
||||||
|
portrate_captain_image/
|
||||||
|
card_image/
|
||||||
|
imageForUsingApp/
|
||||||
|
new_driver_car/
|
||||||
|
upload_audio/
|
||||||
|
|
||||||
|
# --- Python ---
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
|
||||||
|
# --- Firebase ---
|
||||||
|
google-services.json
|
||||||
|
.google-services.json
|
||||||
|
GoogleService-Info.plist
|
||||||
|
|
||||||
|
# --- Audit/Scan Output ---
|
||||||
|
semgrep_*.json
|
||||||
|
nuclei_results.txt
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../../connect.php';
|
require_once __DIR__ . '/../../connect.php';
|
||||||
|
|
||||||
|
if ($role !== 'admin' && $role !== 'super_admin') {
|
||||||
|
http_response_code(403);
|
||||||
|
echo json_encode(['error' => 'Unauthorized: Admin access required']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
$sql = "SELECT
|
$sql = "SELECT
|
||||||
`driver`.`id`,
|
`driver`.`id`,
|
||||||
`driver`.`phone`,
|
`driver`.`phone`,
|
||||||
@@ -48,9 +54,14 @@ $sql = "SELECT
|
|||||||
) AS passengerToken
|
) AS passengerToken
|
||||||
FROM `driver`
|
FROM `driver`
|
||||||
ORDER BY passengerAverageRating DESC
|
ORDER BY passengerAverageRating DESC
|
||||||
LIMIT 10";
|
LIMIT :lim OFFSET :off";
|
||||||
|
|
||||||
$stmt = $con->prepare($sql);
|
$stmt = $con->prepare($sql);
|
||||||
|
$page = max(1, (int) filterRequest('page'));
|
||||||
|
$limit = 10;
|
||||||
|
$offset = ($page - 1) * $limit;
|
||||||
|
$stmt->bindValue(':lim', $limit, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':off', $offset, PDO::PARAM_INT);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
@@ -67,8 +78,16 @@ foreach ($result as &$row) {
|
|||||||
$row['maritalStatus'] = $encryptionHelper->decryptData($row['maritalStatus']);
|
$row['maritalStatus'] = $encryptionHelper->decryptData($row['maritalStatus']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$countStmt = $con->query("SELECT COUNT(*) FROM `driver`");
|
||||||
|
$total = $countStmt->fetchColumn();
|
||||||
|
|
||||||
if (count($result) > 0) {
|
if (count($result) > 0) {
|
||||||
jsonSuccess($result);
|
jsonSuccess([
|
||||||
|
'data' => $result,
|
||||||
|
'total' => (int) $total,
|
||||||
|
'page' => $page,
|
||||||
|
'pages' => (int) ceil($total / $limit),
|
||||||
|
]);
|
||||||
} else {
|
} else {
|
||||||
jsonError("No records found");
|
jsonError("No records found");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../../connect.php';
|
require_once __DIR__ . '/../../connect.php';
|
||||||
|
|
||||||
|
if ($role !== 'admin' && $role !== 'super_admin') {
|
||||||
|
http_response_code(403);
|
||||||
|
echo json_encode(['error' => 'Unauthorized: Admin access required']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$page = max(1, (int) filterRequest('page'));
|
||||||
|
$limit = 50;
|
||||||
|
$offset = ($page - 1) * $limit;
|
||||||
|
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT
|
SELECT
|
||||||
d.phone,
|
d.phone,
|
||||||
@@ -11,13 +21,18 @@ FROM
|
|||||||
`driver` d
|
`driver` d
|
||||||
LEFT JOIN driverToken dt ON
|
LEFT JOIN driverToken dt ON
|
||||||
dt.captain_id = d.id
|
dt.captain_id = d.id
|
||||||
|
LIMIT :lim OFFSET :off
|
||||||
";
|
";
|
||||||
|
|
||||||
$stmt = $con->prepare($sql);
|
$stmt = $con->prepare($sql);
|
||||||
|
$stmt->bindValue(':lim', $limit, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':off', $offset, PDO::PARAM_INT);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
// فك التشفير للحقول الحساسة
|
$countStmt = $con->query("SELECT COUNT(*) FROM `driver`");
|
||||||
|
$total = $countStmt->fetchColumn();
|
||||||
|
|
||||||
foreach ($result as &$row) {
|
foreach ($result as &$row) {
|
||||||
$row['phone'] = $encryptionHelper->decryptData($row['phone']);
|
$row['phone'] = $encryptionHelper->decryptData($row['phone']);
|
||||||
if (!empty($row['token'])) {
|
if (!empty($row['token'])) {
|
||||||
@@ -26,8 +41,12 @@ foreach ($result as &$row) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($stmt->rowCount() > 0) {
|
if ($stmt->rowCount() > 0) {
|
||||||
jsonSuccess($result);
|
jsonSuccess([
|
||||||
|
'data' => $result,
|
||||||
|
'total' => (int) $total,
|
||||||
|
'page' => $page,
|
||||||
|
'pages' => (int) ceil($total / $limit),
|
||||||
|
]);
|
||||||
} else {
|
} else {
|
||||||
jsonError("No records found");
|
jsonError("No records found");
|
||||||
}
|
}
|
||||||
?>
|
|
||||||
@@ -49,6 +49,6 @@ try {
|
|||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("[Staff Activate Error] " . $e->getMessage());
|
error_log("[Staff Activate Error] " . $e->getMessage());
|
||||||
jsonError("خطأ في السيرفر: " . $e->getMessage());
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
exit();
|
exit();
|
||||||
|
|||||||
@@ -96,5 +96,5 @@ try {
|
|||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("[Staff Add Error] " . $e->getMessage());
|
error_log("[Staff Add Error] " . $e->getMessage());
|
||||||
jsonError("Server error: " . $e->getMessage());
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,6 @@ try {
|
|||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("[Staff Pending Error] " . $e->getMessage());
|
error_log("[Staff Pending Error] " . $e->getMessage());
|
||||||
jsonError("خطأ في السيرفر: " . $e->getMessage());
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
exit();
|
exit();
|
||||||
|
|||||||
@@ -61,5 +61,5 @@ try {
|
|||||||
}
|
}
|
||||||
echo "<h1>Initialization Successful</h1>";
|
echo "<h1>Initialization Successful</h1>";
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
echo "Error: " . $e->getMessage();
|
echo "An internal error occurred";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ try {
|
|||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("[Admin Add Error] " . $e->getMessage());
|
error_log("[Admin Add Error] " . $e->getMessage());
|
||||||
jsonError("Database error: " . $e->getMessage());
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
// عرض كافة الأخطاء
|
// عرض كافة الأخطاء
|
||||||
ini_set('display_errors', 1);
|
ini_set('display_errors', 0);
|
||||||
ini_set('display_startup_errors', 1);
|
ini_set('display_startup_errors', 1);
|
||||||
error_reporting(E_ALL);
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
@@ -83,6 +83,6 @@ try {
|
|||||||
|
|
||||||
echo json_encode([
|
echo json_encode([
|
||||||
'status' => 'error',
|
'status' => 'error',
|
||||||
'message' => "Database error: $errorMsg"
|
'message' => "Database error occurred"
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,7 @@ try {
|
|||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
echo json_encode([
|
echo json_encode([
|
||||||
"status" => "error",
|
"status" => "error",
|
||||||
"message" => "Database error: " . $e->getMessage()
|
"message" => "An internal error occurred"
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -44,5 +44,5 @@ try {
|
|||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("[Approve Admin Error] " . $e->getMessage());
|
error_log("[Approve Admin Error] " . $e->getMessage());
|
||||||
jsonError("Server Error: " . $e->getMessage());
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,5 +29,5 @@ try {
|
|||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("[List Pending Admins Error] " . $e->getMessage());
|
error_log("[List Pending Admins Error] " . $e->getMessage());
|
||||||
jsonError("Server Error: " . $e->getMessage());
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,11 +140,12 @@ try {
|
|||||||
$success = sendWhatsAppFromServer($phone, $messageBody);
|
$success = sendWhatsAppFromServer($phone, $messageBody);
|
||||||
|
|
||||||
if ($success) {
|
if ($success) {
|
||||||
// حفظ الرمز كما هو في قاعدة البيانات (بدون تشفير)
|
// تخزين هاش للـ OTP بدلاً من النص الصريح
|
||||||
|
$otpHash = hash('sha256', (string)$otp);
|
||||||
$stmt = $con->prepare("INSERT INTO token_verification_admin (phone_number, token, expiration_time)
|
$stmt = $con->prepare("INSERT INTO token_verification_admin (phone_number, token, expiration_time)
|
||||||
VALUES (?, ?, DATE_ADD(NOW(), INTERVAL 10 MINUTE))
|
VALUES (?, ?, DATE_ADD(NOW(), INTERVAL 10 MINUTE))
|
||||||
ON DUPLICATE KEY UPDATE token = VALUES(token), expiration_time = VALUES(expiration_time)");
|
ON DUPLICATE KEY UPDATE token = VALUES(token), expiration_time = VALUES(expiration_time)");
|
||||||
$stmt->execute([$encryptedPhone, $otp]);
|
$stmt->execute([$encryptedPhone, $otpHash]);
|
||||||
|
|
||||||
// إخفاء جزء من الرقم في الاستجابة للأمان
|
// إخفاء جزء من الرقم في الاستجابة للأمان
|
||||||
$maskedPhone = substr($phone, 0, 4) . '****' . substr($phone, -3);
|
$maskedPhone = substr($phone, 0, 4) . '****' . substr($phone, -3);
|
||||||
|
|||||||
@@ -22,12 +22,13 @@ if ($admin->role !== 'admin' && $admin->role !== 'super_admin') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// جلب المفتاح المشترك لسيرفر المحفظة
|
// جلب المفتاح المشترك لسيرفر المحفظة من متغير البيئة أو الملف
|
||||||
$payKeyPath = '/home/siro-api/.secret_key_pay';
|
$payKeyPath = getenv('SECRET_KEY_PAY_PATH');
|
||||||
$payKey = file_exists($payKeyPath) ? trim(file_get_contents($payKeyPath)) : getenv('SECRET_KEY_PAY');
|
$payKey = ($payKeyPath && file_exists($payKeyPath)) ? trim(file_get_contents($payKeyPath)) : getenv('SECRET_KEY_PAY');
|
||||||
|
|
||||||
if (empty($payKey)) {
|
if (empty($payKey)) {
|
||||||
$payKey = trim(@file_get_contents('/home/siro-api/.secret_key'));
|
$fallbackPath = getenv('SECRET_KEY_PATH');
|
||||||
|
$payKey = ($fallbackPath && file_exists($fallbackPath)) ? trim(file_get_contents($fallbackPath)) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($payKey)) {
|
if (empty($payKey)) {
|
||||||
@@ -89,5 +90,5 @@ try {
|
|||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("[Admin Wallet SSO Error] " . $e->getMessage());
|
error_log("[Admin Wallet SSO Error] " . $e->getMessage());
|
||||||
jsonError("Server Error: " . $e->getMessage());
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,5 +24,5 @@ try {
|
|||||||
echo json_encode(["status" => "success", "message" => "Columns already exist."]);
|
echo json_encode(["status" => "success", "message" => "Columns already exist."]);
|
||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
echo json_encode(["status" => "error", "message" => $e->getMessage()]);
|
echo json_encode(["status" => "error", "message" => "An internal error occurred"]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ foreach ($tables as $table => $columns) {
|
|||||||
}
|
}
|
||||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
echo "Skipped $table due to error: " . $e->getMessage() . "\n";
|
echo "An internal error occurred" . "\n";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,12 +53,6 @@ try {
|
|||||||
$encPhone = $encPhoneInput;
|
$encPhone = $encPhoneInput;
|
||||||
$encFp = $encryptionHelper->encryptData($fingerprint);
|
$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
|
// 4. الإدخال في قاعدة البيانات بحالة pending
|
||||||
$sql = "INSERT INTO adminUser (id, fingerprint, fingerprint_hash, name, phone, password, role, status, created_at)
|
$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())";
|
VALUES (:id, :fp, :fp_hash, :name, :phone, :pass, 'admin', 'pending', NOW())";
|
||||||
@@ -80,7 +74,7 @@ try {
|
|||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("[Admin Register Error] " . $e->getMessage());
|
error_log("[Admin Register Error] " . $e->getMessage());
|
||||||
jsonError("خطأ في السيرفر: " . $e->getMessage());
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
|
|
||||||
exit();
|
exit();
|
||||||
|
|||||||
@@ -39,14 +39,14 @@ try {
|
|||||||
// فك تشفيره لو احتجنا إرساله أو عرضه، لكن هنا نحن نحتاج المشفر للبحث
|
// فك تشفيره لو احتجنا إرساله أو عرضه، لكن هنا نحن نحتاج المشفر للبحث
|
||||||
// $phone = $encryptionHelper->decryptData($encryptedPhone);
|
// $phone = $encryptionHelper->decryptData($encryptedPhone);
|
||||||
|
|
||||||
// تشفير الرمز (OTP) القادم من التطبيق للمقارنة
|
// هاش الرمز (OTP) القادم من التطبيق للمقارنة
|
||||||
$encryptedOtp = $encryptionHelper->encryptData((string)$otp);
|
$otpHash = hash('sha256', (string)$otp);
|
||||||
|
|
||||||
// 3. التحقق من الـ OTP (باستخدام القيم المشفرة)
|
// 3. التحقق من الـ OTP
|
||||||
$stmt = $con->prepare("SELECT * FROM token_verification_admin
|
$stmt = $con->prepare("SELECT * FROM token_verification_admin
|
||||||
WHERE phone_number = ? AND token = ?
|
WHERE phone_number = ? AND token = ?
|
||||||
AND expiration_time >= NOW()");
|
AND expiration_time >= NOW()");
|
||||||
$stmt->execute([$encryptedPhone, $encryptedOtp]);
|
$stmt->execute([$encryptedPhone, $otpHash]);
|
||||||
|
|
||||||
if ($stmt->rowCount() === 0) {
|
if ($stmt->rowCount() === 0) {
|
||||||
jsonError("رمز التحقق غير صالح أو منتهي الصلاحية.");
|
jsonError("رمز التحقق غير صالح أو منتهي الصلاحية.");
|
||||||
@@ -83,5 +83,5 @@ try {
|
|||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error_log("[Admin Verify OTP Error] " . $e->getMessage());
|
error_log("[Admin Verify OTP Error] " . $e->getMessage());
|
||||||
jsonError("خطأ في السيرفر: " . $e->getMessage());
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
# 🔒 SECURITY: Block all access to debug files
|
|
||||||
# This directory contains sensitive debugging scripts
|
|
||||||
# DO NOT remove this file in production
|
|
||||||
|
|
||||||
<RequireAll>
|
|
||||||
Require all denied
|
|
||||||
</RequireAll>
|
|
||||||
|
|
||||||
# Alternative for older Apache:
|
|
||||||
# Deny from all
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<?php
|
|
||||||
require_once 'connect.php';
|
|
||||||
|
|
||||||
try {
|
|
||||||
$stmt = $con->query("SELECT phone FROM driver LIMIT 10");
|
|
||||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
foreach ($rows as $row) {
|
|
||||||
echo "Raw: " . $row['phone'] . " | Decrypted: " . $encryptionHelper->decryptData($row['phone']) . "\n";
|
|
||||||
}
|
|
||||||
} catch (Exception $e) {
|
|
||||||
echo "An error occurred.";
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
<?php
|
|
||||||
require_once 'connect.php';
|
|
||||||
|
|
||||||
try {
|
|
||||||
$stmt = $con->query("DESCRIBE users");
|
|
||||||
$cols = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
echo json_encode($cols, JSON_PRETTY_PRINT);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
echo "An error occurred.";
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<?php
|
|
||||||
require_once __DIR__ . '/connect.php';
|
|
||||||
|
|
||||||
$searchPhone = '0992952235';
|
|
||||||
echo "Searching for: $searchPhone\n";
|
|
||||||
|
|
||||||
$variants = [$searchPhone, '963' . substr($searchPhone, 1), '+963' . substr($searchPhone, 1)];
|
|
||||||
|
|
||||||
foreach ($variants as $v) {
|
|
||||||
echo "Checking variant: $v\n";
|
|
||||||
$enc = $encryptionHelper->encryptData($v);
|
|
||||||
|
|
||||||
$stmt = $con->prepare("SELECT id, phone, first_name FROM driver WHERE phone = ? OR phone = ?");
|
|
||||||
$stmt->execute([$v, $enc]);
|
|
||||||
$res = $stmt->fetch();
|
|
||||||
|
|
||||||
if ($res) {
|
|
||||||
echo "FOUND! ID: {$res['id']}, Name: {$res['first_name']}, Phone in DB: {$res['phone']}\n";
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "NOT FOUND in driver table.\n";
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
<?php
|
|
||||||
// env_test.php - أداة مخصصة لاختبار جميع متغيرات البيئة
|
|
||||||
require_once __DIR__ . '/core/bootstrap.php'; // لتحميل الـ .env
|
|
||||||
|
|
||||||
header('Content-Type: text/plain; charset=utf-8');
|
|
||||||
|
|
||||||
echo "=== فحص متغيرات البيئة (Environment Variables) ===\n\n";
|
|
||||||
|
|
||||||
$keysToCheck = [
|
|
||||||
'PASSENGER_SOCKET_URL',
|
|
||||||
'LOCATION_SOCKET_URL',
|
|
||||||
'INTERNAL_SOCKET_KEY_PATH',
|
|
||||||
'SECRET_KEY_PAY_PATH',
|
|
||||||
'SECRET_KEY_HMAC',
|
|
||||||
'allowed1',
|
|
||||||
'allowed2',
|
|
||||||
'passwordnewpassenger',
|
|
||||||
'FP_PEPPER'
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($keysToCheck as $key) {
|
|
||||||
$val = getenv($key);
|
|
||||||
if ($val !== false && $val !== '') {
|
|
||||||
// إخفاء جزء من القيم الحساسة مثل كلمات المرور
|
|
||||||
if (strpos(strtolower($key), 'password') !== false || strpos(strtolower($key), 'secret') !== false || strpos(strtolower($key), 'hmac') !== false) {
|
|
||||||
$hiddenVal = substr($val, 0, 3) . '***' . substr($val, -3);
|
|
||||||
echo "[OK] $key = $hiddenVal\n";
|
|
||||||
} else {
|
|
||||||
echo "[OK] $key = $val\n";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
echo "[ERROR] $key = (مفقود أو فارغ!)\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "\n\n=== فحص الملفات المباشرة ===\n\n";
|
|
||||||
|
|
||||||
$filesToCheck = [
|
|
||||||
'/home/siro-api/.internal_socket_key',
|
|
||||||
'/home/siro-api/.secret_key_pay'
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($filesToCheck as $file) {
|
|
||||||
if (file_exists($file)) {
|
|
||||||
$content = trim(file_get_contents($file));
|
|
||||||
if (!empty($content)) {
|
|
||||||
$hidden = substr($content, 0, 3) . '***' . substr($content, -3);
|
|
||||||
echo "[OK] File ($file) exists and has content: $hidden\n";
|
|
||||||
} else {
|
|
||||||
echo "[WARNING] File ($file) exists but is EMPTY!\n";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
echo "[ERROR] File ($file) DOES NOT EXIST!\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "\n=== انتهى الفحص ===\n";
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
<?php
|
|
||||||
include 'connect.php';
|
|
||||||
|
|
||||||
// نضمن أن الرد دائماً JSON
|
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
|
||||||
|
|
||||||
// 1) قراءة الـ body كـ JSON (من Flutter)
|
|
||||||
$raw = file_get_contents('php://input');
|
|
||||||
$data = json_decode($raw, true);
|
|
||||||
|
|
||||||
if (!is_array($data)) {
|
|
||||||
// fallback لو أرسلت form-data أو x-www-form-urlencoded
|
|
||||||
$data = $_POST;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2) التحقق من رقم هاتف الأدمن المصرّح له
|
|
||||||
|
|
||||||
// قراءة الأرقام المسموح لها من الـ ENV
|
|
||||||
$phonesRaw = getenv('ADMIN_PHONE_NUMBERS') ?: '';
|
|
||||||
$ALLOWED_TOOL_PHONES = array_values(
|
|
||||||
array_filter(
|
|
||||||
array_map(function ($p) {
|
|
||||||
// إزالة أي رموز غير رقمية (مسافات، +، - إلخ)
|
|
||||||
return preg_replace('/\D+/', '', $p);
|
|
||||||
}, explode(',', $phonesRaw))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// رقم الهاتف القادم من Flutter (parameter جديد)
|
|
||||||
$adminPhoneParam = isset($data['admin_phone'])
|
|
||||||
? preg_replace('/\D+/', '', $data['admin_phone'])
|
|
||||||
: '';
|
|
||||||
|
|
||||||
// إذا لم يُرسل رقم أو لم يكن ضمن القائمة → منع الوصول
|
|
||||||
if ($adminPhoneParam === '' || !in_array($adminPhoneParam, $ALLOWED_TOOL_PHONES, true)) {
|
|
||||||
http_response_code(403);
|
|
||||||
echo json_encode([
|
|
||||||
'status' => 'error',
|
|
||||||
'message' => 'Access denied for this admin phone.',
|
|
||||||
]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3) التحقق من بقية المدخلات (action + text)
|
|
||||||
$action = $data['action'] ?? '';
|
|
||||||
$text = trim($data['text'] ?? '');
|
|
||||||
|
|
||||||
if ($text === '' || ($action !== 'encrypt' && $action !== 'decrypt')) {
|
|
||||||
http_response_code(400);
|
|
||||||
echo json_encode([
|
|
||||||
'status' => 'error',
|
|
||||||
'message' => 'Invalid input: need action=encrypt|decrypt and non-empty text.',
|
|
||||||
]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4) تنفيذ التشفير / الفك
|
|
||||||
try {
|
|
||||||
// require_once __DIR__ . '/encrypt_decrypt.php';
|
|
||||||
|
|
||||||
if ($action === 'encrypt') {
|
|
||||||
$result = $encryptionHelper->encryptData($text);
|
|
||||||
} else { // decrypt
|
|
||||||
$result = $encryptionHelper->decryptData($text);
|
|
||||||
}
|
|
||||||
|
|
||||||
echo json_encode([
|
|
||||||
'status' => 'success',
|
|
||||||
'action' => $action,
|
|
||||||
'result' => (string) $result,
|
|
||||||
]);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
http_response_code(500);
|
|
||||||
echo json_encode([
|
|
||||||
'status' => 'error',
|
|
||||||
'message' => 'Operation failed.',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<?php
|
|
||||||
require_once 'connect.php';
|
|
||||||
|
|
||||||
echo "--- ADMIN TABLE ---\n";
|
|
||||||
try {
|
|
||||||
$stmt = $con->prepare("SELECT id, name, role FROM admin");
|
|
||||||
$stmt->execute();
|
|
||||||
$admins = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
print_r($admins);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
echo "Error: " . $e->getMessage() . "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "\n--- DATABASES ---\n";
|
|
||||||
try {
|
|
||||||
$stmt = $con->prepare("SHOW DATABASES");
|
|
||||||
$stmt->execute();
|
|
||||||
$dbs = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
|
||||||
print_r($dbs);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
echo "Error: " . $e->getMessage() . "\n";
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
<?php
|
|
||||||
echo ini_get('error_log');
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<?php
|
|
||||||
require_once __DIR__ . '/../core/bootstrap.php';
|
|
||||||
require_once __DIR__ . '/../functions.php';
|
|
||||||
|
|
||||||
$con = Database::get('main');
|
|
||||||
$lat = 32.11171;
|
|
||||||
$lng = 36.06737;
|
|
||||||
$carType = 'Fixed Price';
|
|
||||||
|
|
||||||
echo "Testing findBestDrivers...\n";
|
|
||||||
$drivers = findBestDrivers($con, $lat, $lng, $carType);
|
|
||||||
print_r($drivers);
|
|
||||||
echo "Done.\n";
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?php
|
|
||||||
require_once __DIR__ . '/../core/bootstrap.php';
|
|
||||||
$redis = getRedis(); // or however it's connected in bootstrap
|
|
||||||
if (!$redis) {
|
|
||||||
echo "No redis\n"; exit;
|
|
||||||
}
|
|
||||||
$redis->geoadd('geo:rides:waiting', 36.0, 32.0, 'test_ride');
|
|
||||||
$res = $redis->georadius('geo:rides:waiting', 36.0, 32.0, 10, 'km', ['WITHDIST' => true]);
|
|
||||||
print_r($res);
|
|
||||||
echo json_encode($res) . "\n";
|
|
||||||
@@ -37,5 +37,6 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("Error: " . $e->getMessage());
|
error_log("[deleteCaptain.php] " . $e->getMessage());
|
||||||
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ try {
|
|||||||
}
|
}
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
// Handle any SQL errors
|
// Handle any SQL errors
|
||||||
jsonError("Error deleting records: " . $e->getMessage());
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
@@ -51,5 +51,6 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("Error searching driver: " . $e->getMessage());
|
error_log("[find_driver_by_phone.php] " . $e->getMessage());
|
||||||
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
@@ -23,5 +23,6 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("Error removing from blacklist: " . $e->getMessage());
|
error_log("[remove_from_blacklist.php] " . $e->getMessage());
|
||||||
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
@@ -72,6 +72,7 @@ try {
|
|||||||
jsonError("No records updated or driver not found.");
|
jsonError("No records updated or driver not found.");
|
||||||
}
|
}
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("Error updating record: " . $e->getMessage());
|
error_log("[updateDriverFromAdmin.php] " . $e->getMessage());
|
||||||
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -1,16 +1,22 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../connect.php';
|
require_once __DIR__ . '/../connect.php';
|
||||||
|
|
||||||
// استلام البيانات من الطلب
|
// Allow any authenticated user to report errors, but validate input
|
||||||
$error = filterRequest("error");
|
$error = filterRequest("error");
|
||||||
$userId = filterRequest("userId");
|
$userId = filterRequest("userId");
|
||||||
$userType = filterRequest("userType");
|
$userType = filterRequest("userType");
|
||||||
$phone = filterRequest("phone");
|
$phone = filterRequest("phone");
|
||||||
$device = filterRequest("device");
|
$device = filterRequest("device");
|
||||||
$details = filterRequest("details");
|
$details = filterRequest("details");
|
||||||
|
|
||||||
// تسجيل الخطأ في ملف logs/app.log للمتابعة السريعة
|
// Sanitize log input to prevent log injection
|
||||||
$logMsg = "[$userType ID: $userId] Error: $error | Where: $device | Details: $details";
|
$safeError = str_replace(["\r", "\n"], ' ', substr($error ?? '', 0, 500));
|
||||||
|
$safeUserId = str_replace(["\r", "\n"], ' ', substr($userId ?? '', 0, 50));
|
||||||
|
$safeUserType = str_replace(["\r", "\n"], ' ', substr($userType ?? '', 0, 50));
|
||||||
|
$safeDevice = str_replace(["\r", "\n"], ' ', substr($device ?? '', 0, 200));
|
||||||
|
$safeDetails = str_replace(["\r", "\n"], ' ', substr($details ?? '', 0, 1000));
|
||||||
|
|
||||||
|
$logMsg = "[$safeUserType ID: $safeUserId] Error: $safeError | Where: $safeDevice | Details: $safeDetails";
|
||||||
appLog($logMsg, "APP_ERROR");
|
appLog($logMsg, "APP_ERROR");
|
||||||
|
|
||||||
// جملة SQL لإدخال البيانات، مع إضافة الحقل الجديد
|
// جملة SQL لإدخال البيانات، مع إضافة الحقل الجديد
|
||||||
|
|||||||
@@ -31,7 +31,9 @@ try {
|
|||||||
echo "The token does not have an expiration time.\n";
|
echo "The token does not have an expiration time.\n";
|
||||||
}
|
}
|
||||||
} catch (Facebook\Exceptions\FacebookResponseException $e) {
|
} catch (Facebook\Exceptions\FacebookResponseException $e) {
|
||||||
echo 'Graph API Error: ' . $e->getMessage();
|
error_log("[facebook.php] Graph API Error: " . $e->getMessage());
|
||||||
|
echo 'An error occurred while fetching Facebook data';
|
||||||
} catch (Facebook\Exceptions\FacebookSDKException $e) {
|
} catch (Facebook\Exceptions\FacebookSDKException $e) {
|
||||||
echo 'SDK Error: ' . $e->getMessage();
|
error_log("[facebook.php] SDK Error: " . $e->getMessage());
|
||||||
|
echo 'An error occurred while processing Facebook data';
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../../connect.php';
|
require_once __DIR__ . '/../../connect.php';
|
||||||
|
|
||||||
|
if ($role !== 'admin' && $role !== 'super_admin') {
|
||||||
|
http_response_code(403);
|
||||||
|
echo json_encode(['error' => 'Unauthorized: Admin access required']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
function normalize_phone($s) { return preg_replace('/\D+/', '', (string)$s); }
|
function normalize_phone($s) { return preg_replace('/\D+/', '', (string)$s); }
|
||||||
|
|
||||||
$id = filterRequest("id"); // أو
|
$id = filterRequest("id"); // أو
|
||||||
@@ -48,5 +54,5 @@ try {
|
|||||||
jsonSuccess(null, "Passenger deleted and blacklisted");
|
jsonSuccess(null, "Passenger deleted and blacklisted");
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
$con->rollBack();
|
$con->rollBack();
|
||||||
jsonError("Failed: ".$e->getMessage());
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../../connect.php';
|
require_once __DIR__ . '/../../connect.php';
|
||||||
|
|
||||||
|
if ($role !== 'admin' && $role !== 'super_admin') {
|
||||||
|
http_response_code(403);
|
||||||
|
echo json_encode(['error' => 'Unauthorized: Admin access required']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
$id = filterRequest("id"); // مفضّل
|
$id = filterRequest("id"); // مفضّل
|
||||||
|
|
||||||
@@ -9,38 +13,41 @@ $first_name = filterRequest("first_name");
|
|||||||
$last_name = filterRequest("last_name");
|
$last_name = filterRequest("last_name");
|
||||||
$new_phone = filterRequest("phone");
|
$new_phone = filterRequest("phone");
|
||||||
|
|
||||||
if (empty($id) ) { jsonError("Provide id or phone_lookup"); exit; }
|
if (empty($id)) { jsonError("Passenger ID is required"); exit; }
|
||||||
if ($first_name === null && $last_name === null && $new_phone === null) {
|
if ($first_name === null && $last_name === null && $new_phone === null) {
|
||||||
jsonError("Nothing to update"); exit;
|
jsonError("Nothing to update"); exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sets = [];
|
$sets = [];
|
||||||
$params = [];
|
$params = [];
|
||||||
$new_phone = $encryptionHelper->encryptData($new_phone);
|
|
||||||
$first_name = $encryptionHelper->encryptData($first_name);
|
|
||||||
$last_name = $encryptionHelper->encryptData($last_name);
|
|
||||||
|
|
||||||
$enc_norm = $encryptionHelper->encryptData($norm);
|
if ($first_name !== null) {
|
||||||
if ($first_name !== null) { $sets[] = "first_name = :first_name"; $params['first_name'] = trim($first_name); }
|
$encFirst = $encryptionHelper->encryptData($first_name);
|
||||||
if ($last_name !== null) { $sets[] = "last_name = :last_name"; $params['last_name'] = trim($last_name); }
|
$sets[] = "first_name = :first_name";
|
||||||
if ($new_phone !== null) {
|
$params['first_name'] = trim($encFirst);
|
||||||
$sets[] = "phone = :phone";
|
}
|
||||||
$params['phone'] = trim($new_phone);
|
if ($last_name !== null) {
|
||||||
|
$encLast = $encryptionHelper->encryptData($last_name);
|
||||||
|
$sets[] = "last_name = :last_name";
|
||||||
|
$params['last_name'] = trim($encLast);
|
||||||
|
}
|
||||||
|
if ($new_phone !== null) {
|
||||||
|
$encPhone = $encryptionHelper->encryptData($new_phone);
|
||||||
|
$sets[] = "phone = :phone";
|
||||||
|
$params['phone'] = trim($encPhone);
|
||||||
|
|
||||||
// منع تكرار الهاتف على راكب آخر
|
// منع تكرار الهاتف على راكب آخر
|
||||||
$q = $con->prepare("SELECT id FROM passengers WHERE phone = :ph LIMIT 1");
|
$q = $con->prepare("SELECT id FROM passengers WHERE phone = :ph LIMIT 1");
|
||||||
$q->execute(['ph' => $params['phone']]);
|
$q->execute(['ph' => $params['phone']]);
|
||||||
$row = $q->fetch(PDO::FETCH_ASSOC);
|
$row = $q->fetch(PDO::FETCH_ASSOC);
|
||||||
if ($row) {
|
if ($row && $row['id'] != $id) {
|
||||||
if (!empty($id) && $row['id'] != $id) { jsonError("Phone already used by another passenger"); exit; }
|
jsonError("Phone already used by another passenger");
|
||||||
if (empty($id) && $row['id'] != $phoneLookup) { jsonError("Phone already used by another passenger"); exit; }
|
exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$whereSql = "";
|
$whereSql = "id = :pid";
|
||||||
$whereParams = [];
|
$whereParams = ['pid' => $id];
|
||||||
if (!empty($id)) { $whereSql = "id = :pid"; $whereParams['pid'] = $id; }
|
|
||||||
else { $whereSql = "phone = :plk"; $whereParams['plk'] = $phoneLookup; }
|
|
||||||
|
|
||||||
$sql = "UPDATE passengers SET ".implode(", ", $sets).", updated_at = CURRENT_TIMESTAMP WHERE $whereSql";
|
$sql = "UPDATE passengers SET ".implode(", ", $sets).", updated_at = CURRENT_TIMESTAMP WHERE $whereSql";
|
||||||
$stmt = $con->prepare($sql);
|
$stmt = $con->prepare($sql);
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../../connect.php';
|
require_once __DIR__ . '/../../connect.php';
|
||||||
|
|
||||||
|
if ($role !== 'admin' && $role !== 'super_admin') {
|
||||||
|
http_response_code(403);
|
||||||
|
echo json_encode(['error' => 'Unauthorized: Admin access required']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* تطبيع رقم الهاتف ليتوافق مع التخزين في قاعدة البيانات
|
* تطبيع رقم الهاتف ليتوافق مع التخزين في قاعدة البيانات
|
||||||
*/
|
*/
|
||||||
@@ -174,5 +180,5 @@ try {
|
|||||||
|
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
error_log("[get_last_ride] Exception: " . $e->getMessage());
|
error_log("[get_last_ride] Exception: " . $e->getMessage());
|
||||||
jsonError("Error: " . $e->getMessage());
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
@@ -84,5 +84,5 @@ try {
|
|||||||
jsonSuccess(['ride' => $ride, 'message' => 'Status updated']);
|
jsonSuccess(['ride' => $ride, 'message' => 'Status updated']);
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
if ($con->inTransaction()) $con->rollBack();
|
if ($con->inTransaction()) $con->rollBack();
|
||||||
jsonError("Error: ".$e->getMessage());
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
@@ -45,6 +45,7 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("Database Error: " . $e->getMessage());
|
error_log("[get_driver_live_pos.php] " . $e->getMessage());
|
||||||
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -104,6 +104,7 @@ try {
|
|||||||
jsonSuccess($data);
|
jsonSuccess($data);
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("Database Error: " . $e->getMessage());
|
error_log("[get_rides_by_status.php] " . $e->getMessage());
|
||||||
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../../connect.php';
|
require_once __DIR__ . '/../../connect.php';
|
||||||
|
|
||||||
|
if ($role !== 'admin' && $role !== 'super_admin') {
|
||||||
|
http_response_code(403);
|
||||||
|
echo json_encode(['error' => 'Unauthorized: Admin access required']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* تطبيع رقم الهاتف ليتوافق مع التخزين في قاعدة البيانات
|
* تطبيع رقم الهاتف ليتوافق مع التخزين في قاعدة البيانات
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -2,7 +2,13 @@
|
|||||||
// File: send_whatsapp_message.php
|
// File: send_whatsapp_message.php
|
||||||
// هذا السكربت يرسل رسالة واتساب فقط باستخدام RaseelPlus API
|
// هذا السكربت يرسل رسالة واتساب فقط باستخدام RaseelPlus API
|
||||||
|
|
||||||
require_once __DIR__ . '/../connect.php'; // فقط إذا كنت تحتاج للوصول إلى environment
|
require_once __DIR__ . '/../connect.php';
|
||||||
|
|
||||||
|
if ($role !== 'admin' && $role !== 'super_admin') {
|
||||||
|
http_response_code(403);
|
||||||
|
echo json_encode(['error' => 'Unauthorized: Admin access required']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
error_log("--- [send_whatsapp_message.php] Script execution started ---");
|
error_log("--- [send_whatsapp_message.php] Script execution started ---");
|
||||||
|
|
||||||
@@ -16,6 +22,18 @@ if (empty($receiver) || empty($message)) {
|
|||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate phone number format (basic international format)
|
||||||
|
if (!preg_match('/^\+?[1-9]\d{6,14}$/', $receiver)) {
|
||||||
|
jsonError('Invalid phone number format.');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit message length to prevent abuse
|
||||||
|
if (strlen($message) > 4096) {
|
||||||
|
jsonError('Message too long. Maximum 4096 characters.');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
// بيانات Raseel
|
// بيانات Raseel
|
||||||
$instanceId = getenv("RASEEL_DRIVER_INSTANCE_ID");
|
$instanceId = getenv("RASEEL_DRIVER_INSTANCE_ID");
|
||||||
$accessToken = getenv("RASEEL_DRIVER_ACCESS_TOKEN");
|
$accessToken = getenv("RASEEL_DRIVER_ACCESS_TOKEN");
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ try {
|
|||||||
]);
|
]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
|
error_log("[driver_ranking.php] " . $e->getMessage());
|
||||||
|
echo json_encode(['status' => 'error', 'message' => 'An internal error occurred']);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ try {
|
|||||||
]);
|
]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
|
error_log("[growth.php] " . $e->getMessage());
|
||||||
|
echo json_encode(['status' => 'error', 'message' => 'An internal error occurred']);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ try {
|
|||||||
]);
|
]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
|
error_log("[revenue.php] " . $e->getMessage());
|
||||||
|
echo json_encode(['status' => 'error', 'message' => 'An internal error occurred']);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ try {
|
|||||||
]);
|
]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
|
error_log("[settlements.php] " . $e->getMessage());
|
||||||
|
echo json_encode(['status' => 'error', 'message' => 'An internal error occurred']);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ try {
|
|||||||
]);
|
]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
|
error_log("[stats.php] " . $e->getMessage());
|
||||||
|
echo json_encode(['status' => 'error', 'message' => 'An internal error occurred']);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ try {
|
|||||||
jsonError("Invalid action_type", 400);
|
jsonError("Invalid action_type", 400);
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
jsonError("Blacklist action failed: " . $e->getMessage(), 500);
|
error_log("[blacklist_manager.php] " . $e->getMessage());
|
||||||
|
jsonError("Blacklist action failed. Please try again later.", 500);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ try {
|
|||||||
jsonSuccess($scorecard);
|
jsonSuccess($scorecard);
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
jsonError("Failed to fetch scorecard: " . $e->getMessage(), 500);
|
error_log("[driver_scorecard.php] " . $e->getMessage());
|
||||||
|
jsonError("Failed to fetch scorecard. Please try again later.", 500);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ try {
|
|||||||
echo json_encode($response);
|
echo json_encode($response);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
|
error_log("[realtime_dashboard.php] " . $e->getMessage());
|
||||||
|
echo json_encode(['status' => 'error', 'message' => 'An internal error occurred']);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ try {
|
|||||||
]);
|
]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
|
error_log("[smart_alerts.php] " . $e->getMessage());
|
||||||
|
echo json_encode(['status' => 'error', 'message' => 'An internal error occurred']);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -5,13 +5,16 @@ header('Content-Type: application/json');
|
|||||||
|
|
||||||
uploadLog("🚀 [EgyptDocuments/uploadEgyptIdBack.php] Egyptian ID back upload started.");
|
uploadLog("🚀 [EgyptDocuments/uploadEgyptIdBack.php] Egyptian ID back upload started.");
|
||||||
|
|
||||||
$driverID = filterRequest("driverID");
|
$rawDriverID = filterRequest("driverID");
|
||||||
if (empty($driverID)) {
|
if (empty($rawDriverID)) {
|
||||||
uploadLog("❌ Missing driverID parameter.", 'ERROR');
|
uploadLog("❌ Missing driverID parameter.", 'ERROR');
|
||||||
jsonError("driverID is required.");
|
jsonError("driverID is required.");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// منع path traversal
|
||||||
|
$driverID = basename($rawDriverID);
|
||||||
|
|
||||||
if (isset($_FILES['image'])) {
|
if (isset($_FILES['image'])) {
|
||||||
uploadLog("$_FILES['image'] metadata", 'INFO', [
|
uploadLog("$_FILES['image'] metadata", 'INFO', [
|
||||||
'name' => $_FILES['image']['name'] ?? 'unknown',
|
'name' => $_FILES['image']['name'] ?? 'unknown',
|
||||||
@@ -33,19 +36,16 @@ if (!isset($_FILES['image']) || $_FILES['image']['error'] !== UPLOAD_ERR_OK) {
|
|||||||
$image_file = $_FILES['image'];
|
$image_file = $_FILES['image'];
|
||||||
$allowed_extensions = ['jpg', 'jpeg', 'png'];
|
$allowed_extensions = ['jpg', 'jpeg', 'png'];
|
||||||
|
|
||||||
// Get file information
|
|
||||||
$image_name = $image_file['name'];
|
$image_name = $image_file['name'];
|
||||||
$image_size = $image_file['size'];
|
$image_size = $image_file['size'];
|
||||||
$image_extension = strtolower(pathinfo($image_name, PATHINFO_EXTENSION));
|
$image_extension = strtolower(pathinfo($image_name, PATHINFO_EXTENSION));
|
||||||
|
|
||||||
// Validate file extension
|
|
||||||
if (!in_array($image_extension, $allowed_extensions, true)) {
|
if (!in_array($image_extension, $allowed_extensions, true)) {
|
||||||
uploadLog("❌ Invalid image format extension: .$image_extension", 'ERROR');
|
uploadLog("❌ Invalid image format extension: .$image_extension", 'ERROR');
|
||||||
jsonError("Invalid image format");
|
jsonError("Invalid image format");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate MIME type
|
|
||||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||||
$mime_type = finfo_file($finfo, $image_file['tmp_name']);
|
$mime_type = finfo_file($finfo, $image_file['tmp_name']);
|
||||||
finfo_close($finfo);
|
finfo_close($finfo);
|
||||||
@@ -57,29 +57,25 @@ if (!in_array($mime_type, $allowed_mime_types, true)) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a unique filename using driverID
|
|
||||||
$new_filename = $driverID . '.' . $image_extension;
|
$new_filename = $driverID . '.' . $image_extension;
|
||||||
|
|
||||||
// Set target directory for uploads
|
|
||||||
$target_dir = __DIR__ . "/card_image/";
|
$target_dir = __DIR__ . "/card_image/";
|
||||||
if (!is_dir($target_dir)) {
|
if (!is_dir($target_dir)) {
|
||||||
mkdir($target_dir, 0755, true);
|
mkdir($target_dir, 0755, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct target file path
|
|
||||||
$target_file = $target_dir . $new_filename;
|
$target_file = $target_dir . $new_filename;
|
||||||
|
|
||||||
// Move the image file to the target location
|
|
||||||
if (!move_uploaded_file($image_file['tmp_name'], $target_file)) {
|
if (!move_uploaded_file($image_file['tmp_name'], $target_file)) {
|
||||||
uploadLog("❌ Failed to save image to target file: $target_file", 'ERROR');
|
uploadLog("❌ Failed to save image to target file: $target_file", 'ERROR');
|
||||||
jsonError("Failed to save image");
|
jsonError("Failed to save image");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve dynamic URL
|
// استخدام النطاق من البيئة بدلاً من Host header
|
||||||
$host = $_SERVER['HTTP_HOST'] ?? 'api.siromove.com';
|
$domain = getenv('APP_DOMAIN') ?: 'api.siromove.com';
|
||||||
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http";
|
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http";
|
||||||
$image_url = "$protocol://$host/siro/EgyptDocuments/card_image/" . $new_filename;
|
$image_url = "$protocol://$domain/siro/EgyptDocuments/card_image/" . $new_filename;
|
||||||
|
|
||||||
uploadLog("✅ Egypt ID back uploaded successfully. URL: $image_url");
|
uploadLog("✅ Egypt ID back uploaded successfully. URL: $image_url");
|
||||||
|
|
||||||
@@ -89,4 +85,3 @@ printSuccess([
|
|||||||
"file_link" => $image_url,
|
"file_link" => $image_url,
|
||||||
"image_url" => $image_url
|
"image_url" => $image_url
|
||||||
]);
|
]);
|
||||||
?>
|
|
||||||
|
|||||||
@@ -5,13 +5,16 @@ header('Content-Type: application/json');
|
|||||||
|
|
||||||
uploadLog("🚀 [EgyptDocuments/uploadEgyptidFront.php] Egyptian ID front upload started.");
|
uploadLog("🚀 [EgyptDocuments/uploadEgyptidFront.php] Egyptian ID front upload started.");
|
||||||
|
|
||||||
$driverID = filterRequest("driverID");
|
$rawDriverID = filterRequest("driverID");
|
||||||
if (empty($driverID)) {
|
if (empty($rawDriverID)) {
|
||||||
uploadLog("❌ Missing driverID parameter.", 'ERROR');
|
uploadLog("❌ Missing driverID parameter.", 'ERROR');
|
||||||
jsonError("driverID is required.");
|
jsonError("driverID is required.");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// منع path traversal
|
||||||
|
$driverID = basename($rawDriverID);
|
||||||
|
|
||||||
if (isset($_FILES['image'])) {
|
if (isset($_FILES['image'])) {
|
||||||
uploadLog("$_FILES['image'] metadata", 'INFO', [
|
uploadLog("$_FILES['image'] metadata", 'INFO', [
|
||||||
'name' => $_FILES['image']['name'] ?? 'unknown',
|
'name' => $_FILES['image']['name'] ?? 'unknown',
|
||||||
@@ -33,19 +36,16 @@ if (!isset($_FILES['image']) || $_FILES['image']['error'] !== UPLOAD_ERR_OK) {
|
|||||||
$image_file = $_FILES['image'];
|
$image_file = $_FILES['image'];
|
||||||
$allowed_extensions = ['jpg', 'jpeg', 'png'];
|
$allowed_extensions = ['jpg', 'jpeg', 'png'];
|
||||||
|
|
||||||
// Get file information
|
|
||||||
$image_name = $image_file['name'];
|
$image_name = $image_file['name'];
|
||||||
$image_size = $image_file['size'];
|
$image_size = $image_file['size'];
|
||||||
$image_extension = strtolower(pathinfo($image_name, PATHINFO_EXTENSION));
|
$image_extension = strtolower(pathinfo($image_name, PATHINFO_EXTENSION));
|
||||||
|
|
||||||
// Validate file extension
|
|
||||||
if (!in_array($image_extension, $allowed_extensions, true)) {
|
if (!in_array($image_extension, $allowed_extensions, true)) {
|
||||||
uploadLog("❌ Invalid image format extension: .$image_extension", 'ERROR');
|
uploadLog("❌ Invalid image format extension: .$image_extension", 'ERROR');
|
||||||
jsonError("Invalid image format");
|
jsonError("Invalid image format");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate MIME type
|
|
||||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||||
$mime_type = finfo_file($finfo, $image_file['tmp_name']);
|
$mime_type = finfo_file($finfo, $image_file['tmp_name']);
|
||||||
finfo_close($finfo);
|
finfo_close($finfo);
|
||||||
@@ -57,29 +57,25 @@ if (!in_array($mime_type, $allowed_mime_types, true)) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a unique filename using driverID
|
|
||||||
$new_filename = $driverID . '.' . $image_extension;
|
$new_filename = $driverID . '.' . $image_extension;
|
||||||
|
|
||||||
// Set target directory for uploads
|
|
||||||
$target_dir = __DIR__ . "/egypt/idFront/";
|
$target_dir = __DIR__ . "/egypt/idFront/";
|
||||||
if (!is_dir($target_dir)) {
|
if (!is_dir($target_dir)) {
|
||||||
mkdir($target_dir, 0755, true);
|
mkdir($target_dir, 0755, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct target file path
|
|
||||||
$target_file = $target_dir . $new_filename;
|
$target_file = $target_dir . $new_filename;
|
||||||
|
|
||||||
// Move the image file to the target location
|
|
||||||
if (!move_uploaded_file($image_file['tmp_name'], $target_file)) {
|
if (!move_uploaded_file($image_file['tmp_name'], $target_file)) {
|
||||||
uploadLog("❌ Failed to save image to target file: $target_file", 'ERROR');
|
uploadLog("❌ Failed to save image to target file: $target_file", 'ERROR');
|
||||||
jsonError("Failed to save image");
|
jsonError("Failed to save image");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve dynamic URL
|
// استخدام النطاق من البيئة بدلاً من Host header
|
||||||
$host = $_SERVER['HTTP_HOST'] ?? 'api.siromove.com';
|
$domain = getenv('APP_DOMAIN') ?: 'api.siromove.com';
|
||||||
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http";
|
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http";
|
||||||
$image_url = "$protocol://$host/siro/EgyptDocuments/egypt/idFront/" . $new_filename;
|
$image_url = "$protocol://$domain/siro/EgyptDocuments/egypt/idFront/" . $new_filename;
|
||||||
|
|
||||||
uploadLog("✅ Egypt ID front uploaded successfully. URL: $image_url");
|
uploadLog("✅ Egypt ID front uploaded successfully. URL: $image_url");
|
||||||
|
|
||||||
@@ -89,4 +85,3 @@ printSuccess([
|
|||||||
"file_link" => $image_url,
|
"file_link" => $image_url,
|
||||||
"image_url" => $image_url
|
"image_url" => $image_url
|
||||||
]);
|
]);
|
||||||
?>
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ if (!move_uploaded_file($file['tmp_name'], $uploadPath)) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$host = $_SERVER['HTTP_HOST'] ?? 'api-syria.siromove.com';
|
$host = getenv('APP_DOMAIN') ?: 'api-syria.siromove.com';
|
||||||
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http";
|
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http";
|
||||||
$imageUrl = "$protocol://$host/siro/auth/uploads/documents/" . $uniqueName ;
|
$imageUrl = "$protocol://$host/siro/auth/uploads/documents/" . $uniqueName ;
|
||||||
$imageData = file_get_contents($uploadPath);
|
$imageData = file_get_contents($uploadPath);
|
||||||
|
|||||||
@@ -6,8 +6,23 @@ $email = filterRequest('email');
|
|||||||
$phone = filterRequest('phone');
|
$phone = filterRequest('phone');
|
||||||
$password = filterRequest('password');
|
$password = filterRequest('password');
|
||||||
|
|
||||||
// Hash the password
|
if (empty($phone) && empty($email)) {
|
||||||
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
echo json_encode(["status" => "Failure", "data" => "Phone or email is required."]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build WHERE dynamically: support phone-only, email-only, or both
|
||||||
|
$conditions = [];
|
||||||
|
$params = [':password' => $password];
|
||||||
|
if (!empty($phone)) {
|
||||||
|
$conditions[] = "passengers.phone = :phone";
|
||||||
|
$params[':phone'] = $phone;
|
||||||
|
}
|
||||||
|
if (!empty($email)) {
|
||||||
|
$conditions[] = "passengers.email = :email";
|
||||||
|
$params[':email'] = $email;
|
||||||
|
}
|
||||||
|
$where = implode(' OR ', $conditions);
|
||||||
|
|
||||||
$sql = "SELECT
|
$sql = "SELECT
|
||||||
passengers.`id`,
|
passengers.`id`,
|
||||||
@@ -29,11 +44,9 @@ FROM
|
|||||||
`passengers`
|
`passengers`
|
||||||
LEFT JOIN email_verifications ON email_verifications.email = passengers.email
|
LEFT JOIN email_verifications ON email_verifications.email = passengers.email
|
||||||
WHERE
|
WHERE
|
||||||
passengers.phone = :phone AND passengers.email = :email ";
|
$where";
|
||||||
$stmt = $con->prepare($sql);
|
$stmt = $con->prepare($sql);
|
||||||
$stmt->bindParam(':email', $email);
|
$stmt->execute($params);
|
||||||
$stmt->bindParam(':phone', $phone);
|
|
||||||
$stmt->execute();
|
|
||||||
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
$count = $stmt->rowCount();
|
$count = $stmt->rowCount();
|
||||||
|
|
||||||
@@ -54,14 +67,12 @@ if ($count > 0) {
|
|||||||
]);
|
]);
|
||||||
// jsonError("Incorrect password.");
|
// jsonError("Incorrect password.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The user does not exist
|
echo json_encode([
|
||||||
echo json_encode([
|
"status" => "Failure",
|
||||||
"status" => "Failure",
|
"data" => "Invalid credentials."
|
||||||
"data" => "User does not exist."
|
]);
|
||||||
]);
|
}
|
||||||
// jsonError("User does not exist.");
|
$con = null;
|
||||||
}
|
|
||||||
$conn->close();
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -18,17 +18,7 @@ if (empty($receiver)) {
|
|||||||
|
|
||||||
$user_type = filterRequest("user_type");
|
$user_type = filterRequest("user_type");
|
||||||
|
|
||||||
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? (function_exists('apache_request_headers') ? (apache_request_headers()['Authorization'] ?? null) : null);
|
// user_type is taken from request only (JWT not trusted without signature verification)
|
||||||
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
|
$country = filterRequest("country"); // Egypt | Syria | Jordan
|
||||||
$method = filterRequest("method"); // whatsapp | sms | voice | flash_call | bearer_send
|
$method = filterRequest("method"); // whatsapp | sms | voice | flash_call | bearer_send
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ require_once __DIR__ . '/../../functions.php';
|
|||||||
|
|
||||||
// 0. Rate Limiting: 3 محاولات OTP كل 5 دقائق لكل IP
|
// 0. Rate Limiting: 3 محاولات OTP كل 5 دقائق لكل IP
|
||||||
$rateLimiter = new RateLimiter($redis);
|
$rateLimiter = new RateLimiter($redis);
|
||||||
$rateLimiter->enforce(RateLimiter::identifier(), 'otp');
|
$rateLimiter->enforce(RateLimiter::identifier(), 'otp_verify');
|
||||||
|
|
||||||
// 1. Fetch input parameters
|
// 1. Fetch input parameters
|
||||||
$phone_number = filterRequest("phone_number");
|
$phone_number = filterRequest("phone_number");
|
||||||
@@ -23,17 +23,7 @@ if (empty($token_code)) {
|
|||||||
$user_type = filterRequest("user_type");
|
$user_type = filterRequest("user_type");
|
||||||
$context = filterRequest("context"); // token_change | login (default)
|
$context = filterRequest("context"); // token_change | login (default)
|
||||||
|
|
||||||
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? (function_exists('apache_request_headers') ? (apache_request_headers()['Authorization'] ?? null) : null);
|
// user_type is taken from request only (JWT not trusted without signature verification)
|
||||||
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)) {
|
if (empty($phone_number)) {
|
||||||
jsonError("Phone number is required.");
|
jsonError("Phone number is required.");
|
||||||
@@ -75,7 +65,7 @@ try {
|
|||||||
if ($user_type === 'admin') {
|
if ($user_type === 'admin') {
|
||||||
$sql = "SELECT * FROM token_verification_admin
|
$sql = "SELECT * FROM token_verification_admin
|
||||||
WHERE phone_number = :phone AND token = :token
|
WHERE phone_number = :phone AND token = :token
|
||||||
AND expiration_time >= NOW()";
|
AND expiration_time >= NOW() AND verified = 0";
|
||||||
$stmt = $con->prepare($sql);
|
$stmt = $con->prepare($sql);
|
||||||
$stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
$stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
||||||
$stmt->bindParam(':token', $encryptedToken, PDO::PARAM_STR);
|
$stmt->bindParam(':token', $encryptedToken, PDO::PARAM_STR);
|
||||||
@@ -103,7 +93,7 @@ try {
|
|||||||
} elseif ($user_type === 'service') {
|
} elseif ($user_type === 'service') {
|
||||||
$sql = "SELECT `id` FROM `phone_verification_service`
|
$sql = "SELECT `id` FROM `phone_verification_service`
|
||||||
WHERE `phone_number` = :phone AND `token_code` = :token
|
WHERE `phone_number` = :phone AND `token_code` = :token
|
||||||
AND `expiration_time` > NOW()";
|
AND `expiration_time` > NOW() AND `is_verified` = 0";
|
||||||
$stmt = $con->prepare($sql);
|
$stmt = $con->prepare($sql);
|
||||||
$stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
$stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
||||||
$stmt->bindParam(':token', $encryptedToken, PDO::PARAM_STR);
|
$stmt->bindParam(':token', $encryptedToken, PDO::PARAM_STR);
|
||||||
@@ -124,7 +114,7 @@ try {
|
|||||||
$sql = "SELECT `id` FROM `token_verification_driver`
|
$sql = "SELECT `id` FROM `token_verification_driver`
|
||||||
WHERE `phone_number` = :phone
|
WHERE `phone_number` = :phone
|
||||||
AND `token` = :token
|
AND `token` = :token
|
||||||
AND `expiration_time` > NOW()";
|
AND `expiration_time` > NOW() AND `verified` = 0";
|
||||||
|
|
||||||
$stmt = $con->prepare($sql);
|
$stmt = $con->prepare($sql);
|
||||||
$stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
$stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
||||||
@@ -147,7 +137,7 @@ try {
|
|||||||
$sql = "SELECT `id` FROM `phone_verification`
|
$sql = "SELECT `id` FROM `phone_verification`
|
||||||
WHERE `phone_number` = :phone
|
WHERE `phone_number` = :phone
|
||||||
AND `token_code` = :token
|
AND `token_code` = :token
|
||||||
AND `expiration_time` > NOW()";
|
AND `expiration_time` > NOW() AND `is_verified` = 0";
|
||||||
|
|
||||||
$stmt = $con->prepare($sql);
|
$stmt = $con->prepare($sql);
|
||||||
$stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
$stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
||||||
@@ -172,7 +162,7 @@ try {
|
|||||||
$sql = "SELECT `id` FROM `token_verification`
|
$sql = "SELECT `id` FROM `token_verification`
|
||||||
WHERE `phone_number` = :phone
|
WHERE `phone_number` = :phone
|
||||||
AND `token` = :token
|
AND `token` = :token
|
||||||
AND `expiration_time` > NOW()";
|
AND `expiration_time` > NOW() AND `verified` = 0";
|
||||||
|
|
||||||
$stmt = $con->prepare($sql);
|
$stmt = $con->prepare($sql);
|
||||||
$stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
$stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
||||||
@@ -195,7 +185,7 @@ try {
|
|||||||
$sql = "SELECT `id` FROM `phone_verification_passenger`
|
$sql = "SELECT `id` FROM `phone_verification_passenger`
|
||||||
WHERE `phone_number` = :phone
|
WHERE `phone_number` = :phone
|
||||||
AND `token` = :token
|
AND `token` = :token
|
||||||
AND `expiration_time` > NOW()";
|
AND `expiration_time` > NOW() AND `verified` = 0";
|
||||||
|
|
||||||
$stmt = $con->prepare($sql);
|
$stmt = $con->prepare($sql);
|
||||||
$stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
$stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR);
|
||||||
|
|||||||
@@ -11,7 +11,24 @@ $password = filterRequest("password");
|
|||||||
$gender = filterRequest("gender");
|
$gender = filterRequest("gender");
|
||||||
$birthdate = filterRequest("birthdate");
|
$birthdate = filterRequest("birthdate");
|
||||||
$site = filterRequest("site");
|
$site = filterRequest("site");
|
||||||
$id = filterRequest("id");
|
|
||||||
|
// --- Input Validation ---
|
||||||
|
if (empty($phone) || strlen(preg_replace('/\D+/', '', $phone)) < 8) {
|
||||||
|
jsonError("Valid phone number is required.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
if (!empty($email) && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
jsonError("Valid email address is required.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
if (empty($password) || strlen($password) < 6) {
|
||||||
|
jsonError("Password must be at least 6 characters.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
if (empty($first_name) || empty($last_name)) {
|
||||||
|
jsonError("First name and last name are required.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
// تشفير البيانات الحساسة
|
// تشفير البيانات الحساسة
|
||||||
$phone = $encryptionHelper->encryptData($phone);
|
$phone = $encryptionHelper->encryptData($phone);
|
||||||
@@ -39,14 +56,13 @@ try {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// إدخال البيانات الجديدة
|
// إدخال البيانات الجديدة (مع ID تلقائي)
|
||||||
$sql = "INSERT INTO passengers (
|
$sql = "INSERT INTO passengers (
|
||||||
id, phone, email, password, gender, birthdate, site, first_name, last_name
|
id, phone, email, password, gender, birthdate, site, first_name, last_name
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:id, :phone, :email, :password, :gender, :birthdate, :site, :first_name, :last_name
|
UUID_SHORT(), :phone, :email, :password, :gender, :birthdate, :site, :first_name, :last_name
|
||||||
)";
|
)";
|
||||||
$stmt = $con->prepare($sql);
|
$stmt = $con->prepare($sql);
|
||||||
$stmt->bindParam(":id", $id);
|
|
||||||
$stmt->bindParam(":phone", $phone);
|
$stmt->bindParam(":phone", $phone);
|
||||||
$stmt->bindParam(":email", $email);
|
$stmt->bindParam(":email", $email);
|
||||||
$stmt->bindParam(":password", $hashedPassword);
|
$stmt->bindParam(":password", $hashedPassword);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ try {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$host = $_SERVER['HTTP_HOST'] ?? 'api-syria.siromove.com';
|
$host = getenv('APP_DOMAIN') ?: 'api-syria.siromove.com';
|
||||||
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http";
|
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http";
|
||||||
$PUBLIC_BASE = "$protocol://$host/siro/auth/uploads/documents";
|
$PUBLIC_BASE = "$protocol://$host/siro/auth/uploads/documents";
|
||||||
|
|
||||||
@@ -230,7 +230,7 @@ Therefore, do NOT assume a specific field is on the front or the back of a card.
|
|||||||
$urlHost = parse_url($url, PHP_URL_HOST);
|
$urlHost = parse_url($url, PHP_URL_HOST);
|
||||||
$allowed = false;
|
$allowed = false;
|
||||||
foreach ($allowedHosts as $host) {
|
foreach ($allowedHosts as $host) {
|
||||||
if ($host && str_ends_with($urlHost, $host)) {
|
if ($host && $urlHost === $host) {
|
||||||
$allowed = true;
|
$allowed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const MAX_FILE_MB = 5;
|
|||||||
const ALLOWED_MIMES = ['image/jpeg','image/png','image/webp']; // فقط صور
|
const ALLOWED_MIMES = ['image/jpeg','image/png','image/webp']; // فقط صور
|
||||||
const UPLOAD_ROOT = __DIR__ . "/../../private_uploads"; // مجلد خاص (غير عام)
|
const UPLOAD_ROOT = __DIR__ . "/../../private_uploads"; // مجلد خاص (غير عام)
|
||||||
const SIGN_SECRET = getenv('SECRET_KEY_HMAC'); // غيّرها واقرأها من .env
|
const SIGN_SECRET = getenv('SECRET_KEY_HMAC'); // غيّرها واقرأها من .env
|
||||||
$host = $_SERVER['HTTP_HOST'] ?? 'api-syria.siromove.com';
|
$host = getenv('APP_DOMAIN') ?: 'api-syria.siromove.com';
|
||||||
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http";
|
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http";
|
||||||
define('PUBLIC_BASE', "$protocol://$host/siro");
|
define('PUBLIC_BASE', "$protocol://$host/siro");
|
||||||
const SIGNED_TTL_SEC = 172800; // 2 days = 60*60*24
|
const SIGNED_TTL_SEC = 172800; // 2 days = 60*60*24
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
require_once __DIR__ . '/../../../connect.php';
|
require_once __DIR__ . '/../../../connect.php';
|
||||||
|
|
||||||
/* 1) توليد رمز التحقق (3 خانات) --------------------------------------------------- */
|
/* 1) توليد رمز التحقق (3 خانات) --------------------------------------------------- */
|
||||||
$otp = (string)rand(100, 999);
|
$otp = (string)random_int(100, 999);
|
||||||
$receiver = filterRequest("receiver");
|
$receiver = filterRequest("receiver");
|
||||||
|
|
||||||
if (empty($receiver)) {
|
if (empty($receiver)) {
|
||||||
@@ -69,19 +69,19 @@ if ($sentOK) {
|
|||||||
");
|
");
|
||||||
$stmt->execute([$receiver_enc, $otp_enc, $exp, $now]);
|
$stmt->execute([$receiver_enc, $otp_enc, $exp, $now]);
|
||||||
|
|
||||||
|
// Also save to Redis for verify_otp compatibility
|
||||||
|
if ($redis) {
|
||||||
|
$redis->setex("otp:driver:$receiver", 300, $otp);
|
||||||
|
}
|
||||||
|
|
||||||
jsonSuccess(null, 'OTP sent and saved successfully');
|
jsonSuccess(null, 'OTP sent and saved successfully');
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
|
error_log("[send_otp_driver.php] " . $e->getMessage());
|
||||||
jsonError('OTP sent but failed to save to database');
|
jsonError('OTP sent but failed to save to database');
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$errMsg = $decoded['message'] ?? 'Unknown error';
|
jsonError('Failed to send OTP');
|
||||||
jsonError('Failed to send OTP: ' . $errMsg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------
|
|
||||||
* أبقينا callAPI() فقط إذا كان يُستخدم في ملفات أخرى – احذفه إن شئت.
|
|
||||||
* --------------------------------------------------------------------- */
|
|
||||||
function callAPI($method, $url, $data) { /* … */ }
|
|
||||||
?>
|
?>
|
||||||
@@ -77,5 +77,6 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
|
error_log("[verify_otp_driver.php] " . $e->getMessage());
|
||||||
jsonError("Database error occurred.");
|
jsonError("Database error occurred.");
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
require_once __DIR__ . '/../../connect.php';
|
require_once __DIR__ . '/../../connect.php';
|
||||||
|
|
||||||
/* 1) توليد رمز التحقق (3 خانات) */
|
/* 1) توليد رمز التحقق (3 خانات) */
|
||||||
$otp = (string)rand(100, 999);
|
$otp = (string)random_int(100, 999);
|
||||||
$receiver = filterRequest("receiver");
|
$receiver = filterRequest("receiver");
|
||||||
|
|
||||||
if (empty($receiver)) {
|
if (empty($receiver)) {
|
||||||
@@ -50,7 +50,7 @@ $decoded = json_decode((string)$res, true);
|
|||||||
$sentOK = ($httpCode === 200 && ($decoded['success'] ?? false));
|
$sentOK = ($httpCode === 200 && ($decoded['success'] ?? false));
|
||||||
|
|
||||||
if ($sentOK) {
|
if ($sentOK) {
|
||||||
/* 3) تشفير البيانات وحفظ الرمز في قاعدة البيانات */
|
/* 3) حفظ الرمز في Redis + قاعدة البيانات */
|
||||||
$receiver_enc = $encryptionHelper->encryptData($receiver);
|
$receiver_enc = $encryptionHelper->encryptData($receiver);
|
||||||
$otp_enc = $encryptionHelper->encryptData($otp);
|
$otp_enc = $encryptionHelper->encryptData($otp);
|
||||||
|
|
||||||
@@ -58,6 +58,7 @@ if ($sentOK) {
|
|||||||
$now = date('Y-m-d H:i:s');
|
$now = date('Y-m-d H:i:s');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Save to MySQL
|
||||||
$con->prepare("DELETE FROM token_verification WHERE phone_number = ?")
|
$con->prepare("DELETE FROM token_verification WHERE phone_number = ?")
|
||||||
->execute([$receiver_enc]);
|
->execute([$receiver_enc]);
|
||||||
|
|
||||||
@@ -68,19 +69,20 @@ if ($sentOK) {
|
|||||||
");
|
");
|
||||||
$stmt->execute([$receiver_enc, $otp_enc, $exp, $now]);
|
$stmt->execute([$receiver_enc, $otp_enc, $exp, $now]);
|
||||||
|
|
||||||
|
// Also save to Redis for verify_otp.php compatibility
|
||||||
|
if ($redis) {
|
||||||
|
$redis->setex("otp:passenger:$receiver", 300, $otp);
|
||||||
|
}
|
||||||
|
|
||||||
jsonSuccess(null, 'OTP sent and saved successfully');
|
jsonSuccess(null, 'OTP sent and saved successfully');
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
|
error_log("[send_otp.php] " . $e->getMessage());
|
||||||
jsonError('OTP sent but failed to save to database');
|
jsonError('OTP sent but failed to save to database');
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$errMsg = $decoded['message'] ?? 'Unknown error';
|
$errMsg = $decoded['message'] ?? 'Unknown error';
|
||||||
jsonError('Failed to send OTP: ' . $errMsg);
|
jsonError('Failed to send OTP');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -----------------------------------------------------------------
|
|
||||||
* يمكن حذف callAPI() تمامًا إن لم يعد مستخدمًا في أي ملف آخر.
|
|
||||||
* ---------------------------------------------------------------- */
|
|
||||||
function callAPI($method, $url, $data) { /* … (أبقِها أو احذفها) */ }
|
|
||||||
?>
|
?>
|
||||||
@@ -30,7 +30,7 @@ try {
|
|||||||
|
|
||||||
$cachedOtp = $redis->get("otp:passenger:$phoneNumber");
|
$cachedOtp = $redis->get("otp:passenger:$phoneNumber");
|
||||||
|
|
||||||
if ($cachedOtp && $cachedOtp == $otp) {
|
if ($cachedOtp && $cachedOtp === $otp) {
|
||||||
// ننجح في التحقق ونحذف المفتاح من Redis لمنع استخدامه مرة أخرى (One-time use)
|
// ننجح في التحقق ونحذف المفتاح من Redis لمنع استخدامه مرة أخرى (One-time use)
|
||||||
$redis->del("otp:passenger:$phoneNumber");
|
$redis->del("otp:passenger:$phoneNumber");
|
||||||
|
|
||||||
|
|||||||
@@ -64,14 +64,25 @@ class EncryptionHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ─── تشفير/فك تشفير Binary (صور، ملفات) ───────────────
|
// ─── تشفير/فك تشفير Binary (صور، ملفات) ───────────────
|
||||||
|
// تُستخدم الـ GCM مع IV عشوائي (كما في encryptData)
|
||||||
public function encryptBinary(string $data): string
|
public function encryptBinary(string $data): string
|
||||||
{
|
{
|
||||||
return openssl_encrypt($data, self::ALGO_CBC, $this->key, OPENSSL_RAW_DATA, $this->cbcIv);
|
$iv = random_bytes(self::IV_LEN_GCM);
|
||||||
|
$tag = '';
|
||||||
|
$encrypted = openssl_encrypt($data, self::ALGO_GCM, $this->key, OPENSSL_RAW_DATA, $iv, $tag, "", self::TAG_LEN);
|
||||||
|
return base64_encode($iv . $tag . $encrypted);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function decryptBinary(string $data): string|false
|
public function decryptBinary(string $data): string|false
|
||||||
{
|
{
|
||||||
return openssl_decrypt($data, self::ALGO_CBC, $this->key, OPENSSL_RAW_DATA, $this->cbcIv);
|
$raw = base64_decode($data, true);
|
||||||
|
if ($raw === false || strlen($raw) < self::IV_LEN_GCM + self::TAG_LEN) return false;
|
||||||
|
|
||||||
|
$iv = substr($raw, 0, self::IV_LEN_GCM);
|
||||||
|
$tag = substr($raw, self::IV_LEN_GCM, self::TAG_LEN);
|
||||||
|
$cipher = substr($raw, self::IV_LEN_GCM + self::TAG_LEN);
|
||||||
|
|
||||||
|
return openssl_decrypt($cipher, self::ALGO_GCM, $this->key, OPENSSL_RAW_DATA, $iv, $tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------- دوال الـ Padding للـ CBC ----------
|
// --------- دوال الـ Padding للـ CBC ----------
|
||||||
|
|||||||
@@ -20,10 +20,7 @@ if ($debugMode) {
|
|||||||
ini_set('log_errors', '1');
|
ini_set('log_errors', '1');
|
||||||
|
|
||||||
// تحديد مسار اللوج بشكل ديناميكي (محلياً أو سيرفر)
|
// تحديد مسار اللوج بشكل ديناميكي (محلياً أو سيرفر)
|
||||||
$logPath = '/home/siro-api/logs/php_errors.log';
|
$logPath = getenv('ERROR_LOG_PATH') ?: (__DIR__ . '/../logs/php_errors.log');
|
||||||
if (!file_exists(dirname($logPath)) || !is_writable(dirname($logPath))) {
|
|
||||||
$logPath = __DIR__ . '/../logs/php_errors.log';
|
|
||||||
}
|
|
||||||
ini_set('error_log', $logPath);
|
ini_set('error_log', $logPath);
|
||||||
|
|
||||||
header_remove('X-Powered-By');
|
header_remove('X-Powered-By');
|
||||||
@@ -37,7 +34,13 @@ header("Permissions-Policy: geolocation=(), microphone=(), camera=()");
|
|||||||
header("X-XSS-Protection: 1; mode=block");
|
header("X-XSS-Protection: 1; mode=block");
|
||||||
|
|
||||||
|
|
||||||
// CORS (يجب تخصيصه في endpoints مخصصة إن لزم، لكن هذا افتراضي)
|
// CORS مع التحقق من المصدر المسموح
|
||||||
|
$allowedOrigins = array_map('trim', explode(',', getenv('CORS_ALLOWED_ORIGINS') ?: 'https://siromove.com,https://admin.siromove.com'));
|
||||||
|
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
|
||||||
|
if (in_array($origin, $allowedOrigins)) {
|
||||||
|
header("Access-Control-Allow-Origin: $origin");
|
||||||
|
header('Access-Control-Allow-Credentials: true');
|
||||||
|
}
|
||||||
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
|
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
|
||||||
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Device-FP, X-HMAC-Auth, X-Internal-Key');
|
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Device-FP, X-HMAC-Auth, X-Internal-Key');
|
||||||
|
|
||||||
@@ -54,10 +57,7 @@ if ($vendorPath) require_once $vendorPath;
|
|||||||
require_once __DIR__ . '/helpers.php';
|
require_once __DIR__ . '/helpers.php';
|
||||||
|
|
||||||
// تحديد مسار الـ .env بشكل ديناميكي
|
// تحديد مسار الـ .env بشكل ديناميكي
|
||||||
$envFile = '/home/siro-api/env/.env';
|
$envFile = getenv('ENV_FILE_PATH') ?: (__DIR__ . '/../.env');
|
||||||
if (!file_exists($envFile)) {
|
|
||||||
$envFile = __DIR__ . '/../.env'; // مسار محلي افتراضي
|
|
||||||
}
|
|
||||||
loadEnvironment($envFile);
|
loadEnvironment($envFile);
|
||||||
|
|
||||||
// 4. Redis Connection (Singleton)
|
// 4. Redis Connection (Singleton)
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ function getInternalSocketKey(): string
|
|||||||
if ($key) {
|
if ($key) {
|
||||||
return trim($key);
|
return trim($key);
|
||||||
}
|
}
|
||||||
$path = getenv('INTERNAL_SOCKET_KEY_PATH') ?: '/home/siro-api/.internal_socket_key';
|
$path = getenv('INTERNAL_SOCKET_KEY_PATH') ?: '';
|
||||||
if (file_exists($path)) {
|
if (file_exists($path)) {
|
||||||
return trim((string)@file_get_contents($path));
|
return trim((string)@file_get_contents($path));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,5 +115,6 @@ try {
|
|||||||
$mail->send();
|
$mail->send();
|
||||||
jsonSuccess(null, "Email sent successfully");
|
jsonSuccess(null, "Email sent successfully");
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
error_log("[sendTripEmail.php] " . $e->getMessage());
|
||||||
jsonError("Failed to send email: " . $mail->ErrorInfo);
|
jsonError("Failed to send email: " . $mail->ErrorInfo);
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
require_once realpath(__DIR__ . '/../vendor/autoload.php');
|
require_once realpath(__DIR__ . '/../vendor/autoload.php');
|
||||||
|
|
||||||
require_once 'load_env.php';
|
require_once 'load_env.php';
|
||||||
$env_file = '/home/siro-api/env/.env';
|
$env_file = getenv('ENV_FILE_PATH') ?: (__DIR__ . '/../../../env/.env');
|
||||||
loadEnvironment($env_file);
|
loadEnvironment($env_file);
|
||||||
|
|
||||||
// ✅ FIX C-02: استخدام getenv بدلاً من file_get_contents الثابت
|
// ✅ FIX C-02: استخدام getenv بدلاً من file_get_contents الثابت
|
||||||
@@ -49,8 +49,9 @@ class EncryptionHelper {
|
|||||||
public function encryptData($plainText) {
|
public function encryptData($plainText) {
|
||||||
$plainText = mb_convert_encoding($plainText, 'UTF-8');
|
$plainText = mb_convert_encoding($plainText, 'UTF-8');
|
||||||
$paddedText = $this->addPadding($plainText);
|
$paddedText = $this->addPadding($plainText);
|
||||||
$encrypted = openssl_encrypt($paddedText, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
|
$iv = random_bytes(16);
|
||||||
return base64_encode($encrypted);
|
$encrypted = openssl_encrypt($paddedText, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $iv);
|
||||||
|
return base64_encode($iv . $encrypted);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function decryptData($encryptedText) {
|
public function decryptData($encryptedText) {
|
||||||
@@ -61,6 +62,22 @@ class EncryptionHelper {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// محاولة أولى: استخراج IV عشوائي من أول 16 بايت
|
||||||
|
if (strlen($decoded) >= 16) {
|
||||||
|
$iv = substr($decoded, 0, 16);
|
||||||
|
$payload = substr($decoded, 16);
|
||||||
|
|
||||||
|
$decrypted = openssl_decrypt($payload, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $iv);
|
||||||
|
|
||||||
|
if ($decrypted !== false) {
|
||||||
|
$pad = ord($decrypted[strlen($decrypted) - 1]);
|
||||||
|
if ($pad >= 1 && $pad <= 16) {
|
||||||
|
return substr($decrypted, 0, -$pad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// محاولة ثانية: IV ثابت (للبيانات القديمة)
|
||||||
$decrypted = openssl_decrypt($decoded, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
|
$decrypted = openssl_decrypt($decoded, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
|
||||||
|
|
||||||
if ($decrypted === false) {
|
if ($decrypted === false) {
|
||||||
@@ -68,7 +85,6 @@ class EncryptionHelper {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify padding is valid before removal
|
|
||||||
$pad = ord($decrypted[strlen($decrypted) - 1]);
|
$pad = ord($decrypted[strlen($decrypted) - 1]);
|
||||||
if ($pad < 1 || $pad > 16) {
|
if ($pad < 1 || $pad > 16) {
|
||||||
error_log("[ERROR] Invalid padding value ($pad) for decrypted input: $encryptedText");
|
error_log("[ERROR] Invalid padding value ($pad) for decrypted input: $encryptedText");
|
||||||
@@ -95,13 +111,23 @@ class EncryptionHelper {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public function encryptBinary($data) {
|
public function encryptBinary($data) {
|
||||||
$encrypted = openssl_encrypt($data, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
|
$iv = random_bytes(16);
|
||||||
return $encrypted;
|
$encrypted = openssl_encrypt($data, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $iv);
|
||||||
|
return $iv . $encrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function decryptBinary($data) {
|
public function decryptBinary($data) {
|
||||||
|
if (strlen($data) >= 16) {
|
||||||
|
$iv = substr($data, 0, 16);
|
||||||
|
$payload = substr($data, 16);
|
||||||
|
$decrypted = openssl_decrypt($payload, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $iv);
|
||||||
|
if ($decrypted !== false) {
|
||||||
|
return $decrypted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// للبيانات القديمة ذات IV الثابت
|
||||||
$decrypted = openssl_decrypt($data, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
|
$decrypted = openssl_decrypt($data, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $this->iv);
|
||||||
// CRIT-07 FIX: التحقق من فشل openssl_decrypt
|
|
||||||
if ($decrypted === false) {
|
if ($decrypted === false) {
|
||||||
error_log('[CRIT-07] openssl_decrypt failed in decryptBinary');
|
error_log('[CRIT-07] openssl_decrypt failed in decryptBinary');
|
||||||
throw new Exception('Decryption failed');
|
throw new Exception('Decryption failed');
|
||||||
|
|||||||
@@ -44,8 +44,7 @@ function isAllowedSocketUrl(string $url): bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sendToLocationServer($action, $data) {
|
function sendToLocationServer($action, $data) {
|
||||||
// رابط سيرفر اللوكيشن الداخلي أو العام
|
$url = getenv('LOCATION_SERVER_URL') ?: 'http://188.68.36.205:2021';
|
||||||
$url = "http://188.68.36.205:2021";
|
|
||||||
if (!isAllowedSocketUrl($url)) {
|
if (!isAllowedSocketUrl($url)) {
|
||||||
error_log("[SSRF_BLOCKED] Attempted connection to: $url");
|
error_log("[SSRF_BLOCKED] Attempted connection to: $url");
|
||||||
return;
|
return;
|
||||||
@@ -269,7 +268,7 @@ function notifyPassengerOnRideServer($passenger_id, $payload) {
|
|||||||
$INTERNAL_KEY = function_exists('getInternalSocketKey') ? getInternalSocketKey() : '';
|
$INTERNAL_KEY = function_exists('getInternalSocketKey') ? getInternalSocketKey() : '';
|
||||||
|
|
||||||
if (empty($INTERNAL_KEY)) {
|
if (empty($INTERNAL_KEY)) {
|
||||||
error_log("[SOCKET_CRITICAL] Internal key missing at /home/siro-api/.internal_socket_key");
|
error_log("[SOCKET_CRITICAL] Internal socket key missing");
|
||||||
}
|
}
|
||||||
|
|
||||||
$postData = [
|
$postData = [
|
||||||
|
|||||||
@@ -1,47 +1,24 @@
|
|||||||
<?php
|
<?php
|
||||||
include 'connect.php';
|
require_once __DIR__ . '/core/bootstrap.php';
|
||||||
|
|
||||||
// نضمن أن الرد دائماً JSON
|
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
// 1) قراءة الـ body كـ JSON (من Flutter)
|
// التحقق من صلاحية الأدمن عبر JWT
|
||||||
|
$jwtService = new JwtService($redis ?? null);
|
||||||
|
$admin = $jwtService->authenticate();
|
||||||
|
if ($admin->role !== 'admin' && $admin->role !== 'super_admin') {
|
||||||
|
http_response_code(403);
|
||||||
|
echo json_encode(['status' => 'error', 'message' => 'Unauthorized. Admin access required.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
$raw = file_get_contents('php://input');
|
$raw = file_get_contents('php://input');
|
||||||
$data = json_decode($raw, true);
|
$data = json_decode($raw, true);
|
||||||
|
|
||||||
if (!is_array($data)) {
|
if (!is_array($data)) {
|
||||||
// fallback لو أرسلت form-data أو x-www-form-urlencoded
|
|
||||||
$data = $_POST;
|
$data = $_POST;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) التحقق من رقم هاتف الأدمن المصرّح له
|
|
||||||
|
|
||||||
// قراءة الأرقام المسموح لها من الـ ENV
|
|
||||||
$phonesRaw = getenv('ADMIN_PHONE_NUMBERS') ?: '';
|
|
||||||
$ALLOWED_TOOL_PHONES = array_values(
|
|
||||||
array_filter(
|
|
||||||
array_map(function ($p) {
|
|
||||||
// إزالة أي رموز غير رقمية (مسافات، +، - إلخ)
|
|
||||||
return preg_replace('/\D+/', '', $p);
|
|
||||||
}, explode(',', $phonesRaw))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// رقم الهاتف القادم من Flutter (parameter جديد)
|
|
||||||
$adminPhoneParam = isset($data['admin_phone'])
|
|
||||||
? preg_replace('/\D+/', '', $data['admin_phone'])
|
|
||||||
: '';
|
|
||||||
|
|
||||||
// إذا لم يُرسل رقم أو لم يكن ضمن القائمة → منع الوصول
|
|
||||||
if ($adminPhoneParam === '' || !in_array($adminPhoneParam, $ALLOWED_TOOL_PHONES, true)) {
|
|
||||||
http_response_code(403);
|
|
||||||
echo json_encode([
|
|
||||||
'status' => 'error',
|
|
||||||
'message' => 'Access denied for this admin phone.',
|
|
||||||
]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3) التحقق من بقية المدخلات (action + text)
|
|
||||||
$action = $data['action'] ?? '';
|
$action = $data['action'] ?? '';
|
||||||
$text = trim($data['text'] ?? '');
|
$text = trim($data['text'] ?? '');
|
||||||
|
|
||||||
@@ -54,13 +31,10 @@ if ($text === '' || ($action !== 'encrypt' && $action !== 'decrypt')) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4) تنفيذ التشفير / الفك
|
|
||||||
try {
|
try {
|
||||||
// require_once __DIR__ . '/encrypt_decrypt.php';
|
|
||||||
|
|
||||||
if ($action === 'encrypt') {
|
if ($action === 'encrypt') {
|
||||||
$result = $encryptionHelper->encryptData($text);
|
$result = $encryptionHelper->encryptData($text);
|
||||||
} else { // decrypt
|
} else {
|
||||||
$result = $encryptionHelper->decryptData($text);
|
$result = $encryptionHelper->decryptData($text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,6 +44,7 @@ try {
|
|||||||
'result' => (string) $result,
|
'result' => (string) $result,
|
||||||
]);
|
]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
error_log("[ggg.php] " . $e->getMessage());
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
echo json_encode([
|
echo json_encode([
|
||||||
'status' => 'error',
|
'status' => 'error',
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ function loadEnvironment($env_file) {
|
|||||||
$value = trim($value, "\"'");
|
$value = trim($value, "\"'");
|
||||||
putenv("$keyName=$value");
|
putenv("$keyName=$value");
|
||||||
$_ENV[$keyName] = $value;
|
$_ENV[$keyName] = $value;
|
||||||
$_SERVER[$keyName] = $value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,5 +19,6 @@ try {
|
|||||||
jsonSuccess(null, "Logged out successfully");
|
jsonSuccess(null, "Logged out successfully");
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
error_log("[logout.php] " . $e->getMessage());
|
||||||
jsonError("Logout failed", 500);
|
jsonError("Logout failed", 500);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ ini_set('memory_limit', '512M');
|
|||||||
require_once realpath(__DIR__ . '/../vendor/autoload.php');
|
require_once realpath(__DIR__ . '/../vendor/autoload.php');
|
||||||
require_once 'load_env.php';
|
require_once 'load_env.php';
|
||||||
|
|
||||||
$env_file = '/home/siro-api/env/.env';
|
$env_file = getenv('ENV_FILE_PATH') ?: (__DIR__ . '/../../../env/.env');
|
||||||
loadEnvironment($env_file);
|
loadEnvironment($env_file);
|
||||||
|
|
||||||
include "encrypt_decrypt.php"; // لاستخدام $encryptionHelper
|
include "encrypt_decrypt.php"; // لاستخدام $encryptionHelper
|
||||||
|
|||||||
@@ -16,6 +16,6 @@ try {
|
|||||||
$con->exec($sql);
|
$con->exec($sql);
|
||||||
echo "SUCCESS: passenger_opening_locations table created successfully.\n";
|
echo "SUCCESS: passenger_opening_locations table created successfully.\n";
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
echo "ERROR: " . $e->getMessage() . "\n";
|
echo "An internal error occurred" . "\n";
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -119,7 +119,9 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("Database error: " . $e->getMessage());
|
error_log("[selectDriverAndCarForMishwariTrip.php] " . $e->getMessage());
|
||||||
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
jsonError("Error: " . $e->getMessage());
|
error_log("[selectDriverAndCarForMishwariTrip.php] " . $e->getMessage());
|
||||||
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,19 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../../connect.php';
|
require_once __DIR__ . '/../../connect.php';
|
||||||
|
|
||||||
// استقبال المتغيرات
|
// استقبال المتغيرات — force user IDs from JWT based on role
|
||||||
$driverID = filterRequest("driverID");
|
|
||||||
$passengerID = filterRequest("passengerID");
|
|
||||||
$rideID = filterRequest("rideID");
|
$rideID = filterRequest("rideID");
|
||||||
$note = filterRequest("note");
|
$note = filterRequest("note");
|
||||||
|
|
||||||
|
// Force driverID/passengerID from JWT based on user role
|
||||||
|
if ($role === 'driver') {
|
||||||
|
$driverID = $user_id;
|
||||||
|
$passengerID = filterRequest("passengerID");
|
||||||
|
} else {
|
||||||
|
$passengerID = $user_id;
|
||||||
|
$driverID = filterRequest("driverID");
|
||||||
|
}
|
||||||
|
|
||||||
// تنفيذ الإدخال بطريقة آمنة
|
// تنفيذ الإدخال بطريقة آمنة
|
||||||
$sql = "INSERT INTO `canecl` (`driverID`, `passengerID`, `rideID`, `note`)
|
$sql = "INSERT INTO `canecl` (`driverID`, `passengerID`, `rideID`, `note`)
|
||||||
VALUES (:driverID, :passengerID, :rideID, :note)";
|
VALUES (:driverID, :passengerID, :rideID, :note)";
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ try {
|
|||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
error_log("❌ [cancelRideAndLog.php] Database Error: " . $e->getMessage());
|
error_log("❌ [cancelRideAndLog.php] Database Error: " . $e->getMessage());
|
||||||
jsonError("Database Error: " . $e->getMessage());
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require_once __DIR__ . '/../../connect.php';
|
require_once __DIR__ . '/../../connect.php';
|
||||||
@@ -144,7 +144,8 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("DB Error: " . $e->getMessage());
|
error_log("[addCancelTripFromDriverAfterApplied.php] " . $e->getMessage());
|
||||||
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
?>
|
?>
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../../connect.php';
|
require_once __DIR__ . '/../../connect.php';
|
||||||
|
|
||||||
|
// التحقق من أن المستخدم يملك هذا المعرف
|
||||||
|
if ($role !== 'admin' && $role !== 'super_admin' && (string)$user_id !== (string)$driverID) {
|
||||||
|
jsonError("Unauthorized: You can only add cars to your own account");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
// استقبال القيم
|
// استقبال القيم
|
||||||
$driverID = filterRequest("driverID");
|
$driverID = filterRequest("driverID");
|
||||||
$vin = $encryptionHelper->encryptData(filterRequest("vin"));
|
$vin = $encryptionHelper->encryptData(filterRequest("vin"));
|
||||||
|
|||||||
@@ -4,6 +4,23 @@ require_once __DIR__ . '/../../connect.php';
|
|||||||
// استقبال ID السجل
|
// استقبال ID السجل
|
||||||
$id = filterRequest("id");
|
$id = filterRequest("id");
|
||||||
|
|
||||||
|
// التحقق من أن السجل يخص المستخدم الحالي أو هو أدمن
|
||||||
|
$checkSql = "SELECT driverID FROM captains_car WHERE id = :id LIMIT 1";
|
||||||
|
$checkStmt = $con->prepare($checkSql);
|
||||||
|
$checkStmt->bindParam(':id', $id, PDO::PARAM_INT);
|
||||||
|
$checkStmt->execute();
|
||||||
|
$record = $checkStmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$record) {
|
||||||
|
jsonError("Record not found");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($role !== 'admin' && $role !== 'super_admin' && (string)$user_id !== $record['driverID']) {
|
||||||
|
jsonError("Unauthorized: You can only delete your own car registrations");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
// حذف السجل من جدول captains_car (أو CarRegistration لو هو الصحيح فعلاً)
|
// حذف السجل من جدول captains_car (أو CarRegistration لو هو الصحيح فعلاً)
|
||||||
$sql = "DELETE FROM captains_car WHERE id = :id";
|
$sql = "DELETE FROM captains_car WHERE id = :id";
|
||||||
$stmt = $con->prepare($sql);
|
$stmt = $con->prepare($sql);
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ try {
|
|||||||
jsonSuccess($response);
|
jsonSuccess($response);
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("Database error: " . $e->getMessage());
|
error_log("[get_driver_behavior.php] " . $e->getMessage());
|
||||||
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -43,6 +43,7 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("Database Error: " . $e->getMessage());
|
error_log("[get.php] " . $e->getMessage());
|
||||||
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -35,6 +35,7 @@ try {
|
|||||||
}
|
}
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
// Print error message
|
// Print error message
|
||||||
jsonError($message = "Database error: " . $e->getMessage());
|
error_log("[add.php] " . $e->getMessage());
|
||||||
|
jsonError($message = "Database error occurred");
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -32,6 +32,6 @@ try {
|
|||||||
}
|
}
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
// إرجاع رسالة خطأ في حال حدوث مشكلة في قاعدة البيانات
|
// إرجاع رسالة خطأ في حال حدوث مشكلة في قاعدة البيانات
|
||||||
jsonError("Database error: " . $e->getMessage());
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -1,21 +1,38 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../../connect.php';
|
require_once __DIR__ . '/../../connect.php';
|
||||||
|
|
||||||
$sql = "SELECT * FROM `driverToken`";
|
if ($role !== 'admin' && $role !== 'super_admin') {
|
||||||
|
http_response_code(403);
|
||||||
|
echo json_encode(['error' => 'Unauthorized: Admin access required']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$page = max(1, (int) filterRequest('page'));
|
||||||
|
$limit = 50;
|
||||||
|
$offset = ($page - 1) * $limit;
|
||||||
|
|
||||||
|
$sql = "SELECT * FROM `driverToken` LIMIT :lim OFFSET :off";
|
||||||
$stmt = $con->prepare($sql);
|
$stmt = $con->prepare($sql);
|
||||||
|
$stmt->bindValue(':lim', $limit, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':off', $offset, PDO::PARAM_INT);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// الحصول على العدد الإجمالي للصفحات
|
||||||
|
$countStmt = $con->query("SELECT COUNT(*) FROM `driverToken`");
|
||||||
|
$total = $countStmt->fetchColumn();
|
||||||
|
|
||||||
if ($data) {
|
if ($data) {
|
||||||
// فك تشفير token فقط لكل سجل
|
|
||||||
foreach ($data as &$item) {
|
foreach ($data as &$item) {
|
||||||
$item['token'] = $encryptionHelper->decryptData($item['token']);
|
$item['token'] = $encryptionHelper->decryptData($item['token']);
|
||||||
// لا يتم فك تشفير fingerPrint لأنه مشفّر من Flutter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
echo json_encode([
|
echo json_encode([
|
||||||
'status' => 'success',
|
'status' => 'success',
|
||||||
'data' => $data
|
'data' => $data,
|
||||||
|
'total' => (int) $total,
|
||||||
|
'page' => $page,
|
||||||
|
'pages' => (int) ceil($total / $limit),
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
jsonError("No driver tokens found");
|
jsonError("No driver tokens found");
|
||||||
|
|||||||
@@ -1,21 +1,37 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/../../connect.php';
|
require_once __DIR__ . '/../../connect.php';
|
||||||
|
|
||||||
$sql = "SELECT * FROM `tokens`";
|
if ($role !== 'admin' && $role !== 'super_admin') {
|
||||||
|
http_response_code(403);
|
||||||
|
echo json_encode(['error' => 'Unauthorized: Admin access required']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$page = max(1, (int) filterRequest('page'));
|
||||||
|
$limit = 50;
|
||||||
|
$offset = ($page - 1) * $limit;
|
||||||
|
|
||||||
|
$sql = "SELECT * FROM `tokens` LIMIT :lim OFFSET :off";
|
||||||
$stmt = $con->prepare($sql);
|
$stmt = $con->prepare($sql);
|
||||||
|
$stmt->bindValue(':lim', $limit, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':off', $offset, PDO::PARAM_INT);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$countStmt = $con->query("SELECT COUNT(*) FROM `tokens`");
|
||||||
|
$total = $countStmt->fetchColumn();
|
||||||
|
|
||||||
if ($data) {
|
if ($data) {
|
||||||
// فك تشفير token فقط
|
|
||||||
foreach ($data as &$item) {
|
foreach ($data as &$item) {
|
||||||
$item['token'] = $encryptionHelper->decryptData($item['token']);
|
$item['token'] = $encryptionHelper->decryptData($item['token']);
|
||||||
// fingerPrint يبقى كما هو (مشفّر من التطبيق)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
echo json_encode([
|
echo json_encode([
|
||||||
'status' => 'success',
|
'status' => 'success',
|
||||||
'data' => $data
|
'data' => $data,
|
||||||
|
'total' => (int) $total,
|
||||||
|
'page' => $page,
|
||||||
|
'pages' => (int) ceil($total / $limit),
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
jsonError("No token records found");
|
jsonError("No token records found");
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
// send_fcm.php - FCM HTTP v1 Sender
|
// send_fcm.php - FCM HTTP v1 Sender (Internal use only)
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
// 🔐 Require internal API key for authentication
|
||||||
|
$apiKey = $_SERVER['HTTP_X_API_KEY'] ?? '';
|
||||||
|
$expectedKey = getenv('FCM_INTERNAL_API_KEY');
|
||||||
|
if (empty($expectedKey) || !hash_equals($expectedKey, $apiKey)) {
|
||||||
|
http_response_code(403);
|
||||||
|
echo json_encode(['status' => 'error', 'message' => 'Unauthorized']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
$serviceAccountFile = __DIR__ . '/service-account.json';
|
$serviceAccountFile = __DIR__ . '/service-account.json';
|
||||||
|
|
||||||
// السماح فقط بـ POST
|
// السماح فقط بـ POST
|
||||||
|
|||||||
@@ -99,6 +99,6 @@ try {
|
|||||||
$con->rollBack();
|
$con->rollBack();
|
||||||
}
|
}
|
||||||
error_log("claimChallengeReward Error: " . $e->getMessage());
|
error_log("claimChallengeReward Error: " . $e->getMessage());
|
||||||
jsonError("Failed to claim reward: " . $e->getMessage());
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -115,6 +115,6 @@ try {
|
|||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
error_log("getGamificationDashboard Error: " . $e->getMessage());
|
error_log("getGamificationDashboard Error: " . $e->getMessage());
|
||||||
jsonError("Database error occurred: " . $e->getMessage());
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -17,7 +17,12 @@ function generateUniqueCode($con) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$driverId = filterRequest("driverId");
|
// Force driverId from JWT — only drivers can manage invitations
|
||||||
|
if ($role !== 'driver') {
|
||||||
|
jsonError("Only drivers can create invitations");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
$driverId = $user_id;
|
||||||
$inviterDriverPhone = filterRequest("inviterDriverPhone");
|
$inviterDriverPhone = filterRequest("inviterDriverPhone");
|
||||||
|
|
||||||
// 🔐 تشفير رقم الهاتف
|
// 🔐 تشفير رقم الهاتف
|
||||||
@@ -52,7 +57,8 @@ if ($checkStmt->rowCount() > 0) {
|
|||||||
"expirationTime" => $expirationTime
|
"expirationTime" => $expirationTime
|
||||||
]);
|
]);
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("Database error: " . $e->getMessage());
|
error_log("[invitor/add] DB Error: " . $e->getMessage());
|
||||||
|
jsonError("Database error occurred");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +89,8 @@ if ($checkStmt->rowCount() > 0) {
|
|||||||
jsonError("Failed to save invite data");
|
jsonError("Failed to save invite data");
|
||||||
}
|
}
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("Database error: " . $e->getMessage());
|
error_log("[invitor/add] DB Error: " . $e->getMessage());
|
||||||
|
jsonError("Database error occurred");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -58,7 +58,8 @@ if ($checkStmt->rowCount() > 0) {
|
|||||||
"expirationTime" => $expirationTime
|
"expirationTime" => $expirationTime
|
||||||
]);
|
]);
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("Database error: " . $e->getMessage());
|
error_log("[addInvitationPassenger.php] " . $e->getMessage());
|
||||||
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -91,7 +92,8 @@ if ($checkStmt->rowCount() > 0) {
|
|||||||
jsonError("Failed to save invite data");
|
jsonError("Failed to save invite data");
|
||||||
}
|
}
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("Database error: " . $e->getMessage());
|
error_log("[addInvitationPassenger.php] " . $e->getMessage());
|
||||||
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -32,6 +32,7 @@ try {
|
|||||||
$insertStmt->execute([$inviterCode, $user_id, $role]);
|
$insertStmt->execute([$inviterCode, $user_id, $role]);
|
||||||
printSuccess(["message" => "Referral linked successfully"]);
|
printSuccess(["message" => "Referral linked successfully"]);
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("Database error: " . $e->getMessage());
|
error_log("[add_unified_invite.php] " . $e->getMessage());
|
||||||
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -7,8 +7,17 @@ header('Content-Type: application/json');
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
$inviteId = filterRequest("invite_id");
|
$inviteId = filterRequest("invite_id");
|
||||||
$driverId = filterRequest("driver_id");
|
// Force user ID from JWT based on role
|
||||||
$passengerId = filterRequest("passenger_id");
|
if ($role === 'driver') {
|
||||||
|
$driverId = $user_id;
|
||||||
|
$passengerId = null;
|
||||||
|
} elseif ($role === 'passenger') {
|
||||||
|
$passengerId = $user_id;
|
||||||
|
$driverId = null;
|
||||||
|
} else {
|
||||||
|
echo json_encode(["status" => "failure", "message" => "Invalid user role."]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
$countryCode = filterRequest("country_code"); // Expected: Jordan, Syria, Egypt
|
$countryCode = filterRequest("country_code"); // Expected: Jordan, Syria, Egypt
|
||||||
|
|
||||||
if (empty($inviteId)) {
|
if (empty($inviteId)) {
|
||||||
@@ -88,6 +97,7 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addWalletBalance($url, $userId, $userType, $amount) {
|
function addWalletBalance($url, $userId, $userType, $amount) {
|
||||||
|
$s2sKey = getenv('S2S_SHARED_KEY');
|
||||||
$data = [
|
$data = [
|
||||||
"user_id" => $userId,
|
"user_id" => $userId,
|
||||||
"user_type" => $userType,
|
"user_type" => $userType,
|
||||||
@@ -100,6 +110,11 @@ function addWalletBalance($url, $userId, $userType, $amount) {
|
|||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
curl_setopt($ch, CURLOPT_POST, true);
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
|
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
|
||||||
|
if ($s2sKey) {
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-Auth-Token: $s2sKey"]);
|
||||||
|
}
|
||||||
$response = curl_exec($ch);
|
$response = curl_exec($ch);
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
return $response;
|
return $response;
|
||||||
|
|||||||
@@ -145,6 +145,6 @@ try {
|
|||||||
if ($con->inTransaction()) {
|
if ($con->inTransaction()) {
|
||||||
$con->rollBack();
|
$con->rollBack();
|
||||||
}
|
}
|
||||||
jsonError("Failed to claim reward: " . $e->getMessage());
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ if ($stmt->rowCount() > 0) {
|
|||||||
$insertStmt->execute([$user_id, $role, $newCode]);
|
$insertStmt->execute([$user_id, $role, $newCode]);
|
||||||
printSuccess(["referral_code" => $newCode]);
|
printSuccess(["referral_code" => $newCode]);
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("Database error: " . $e->getMessage());
|
error_log("[get_unified_code.php] " . $e->getMessage());
|
||||||
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -54,6 +54,6 @@ try {
|
|||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
error_log("DB Error: " . $e->getMessage());
|
error_log("DB Error: " . $e->getMessage());
|
||||||
jsonError("Database error: " . $e->getMessage());
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -39,6 +39,7 @@ try {
|
|||||||
jsonError("Invalid invite code, already installed, or expired.");
|
jsonError("Invalid invite code, already installed, or expired.");
|
||||||
}
|
}
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("Database error: " . $e->getMessage());
|
error_log("[updateInvitationCodeFromRegister.php] " . $e->getMessage());
|
||||||
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -40,6 +40,7 @@ try {
|
|||||||
jsonError("Invalid invite code, already used, or marked as gift.");
|
jsonError("Invalid invite code, already used, or marked as gift.");
|
||||||
}
|
}
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
jsonError("Database error: " . $e->getMessage());
|
error_log("[updatePassengersInvitation.php] " . $e->getMessage());
|
||||||
|
jsonError("An internal error occurred. Please try again later.");
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -5,10 +5,10 @@ require_once __DIR__ . '/../../connect.php';
|
|||||||
// $promo_code = filterRequest("promo_code");
|
// $promo_code = filterRequest("promo_code");
|
||||||
$driverID = filterRequest("driverID");
|
$driverID = filterRequest("driverID");
|
||||||
|
|
||||||
$sql = "SELECT * FROM `lisenceDetails`WHERE`driverID`='$driverID'";
|
$sql = "SELECT * FROM `lisenceDetails` WHERE `driverID` = :driverID";
|
||||||
|
|
||||||
$stmt = $con->prepare($sql);
|
$stmt = $con->prepare($sql);
|
||||||
$stmt->execute();
|
$stmt->execute([':driverID' => $driverID]);
|
||||||
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
if ($result) {
|
if ($result) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user