Deploy: 2026-05-23 01:45:24

This commit is contained in:
Hamza-Ayed
2026-05-23 01:45:24 +03:00
parent f684b58906
commit 154c6317b0
3 changed files with 2 additions and 484 deletions

View File

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

View File

@@ -31,8 +31,8 @@ class OTPController extends BaseController
return; return;
} }
// Clean phone number (remove non-digits except +) // Clean phone number (remove non-digits including +)
$phone = preg_replace('/[^\d+]/', '', $phone); $phone = preg_replace('/\D/', '', $phone);
// 1. Resolve WhatsApp Session // 1. Resolve WhatsApp Session
$session = null; $session = null;

View File

@@ -1,237 +0,0 @@
<?php
// --- 1. Dependencias y Conexión ---
require_once __DIR__ . '/../connect.php';
// دالة مساعدة لتسجيل الخطوات في ملف الـ LOG
function logStep($step, $message) {
error_log("[DriverReg] Step $step: $message");
}
try {
// --- بدء المعاملة ---
$con->beginTransaction();
logStep(1, "Transaction started via beginTransaction()");
// --- 2. Recolección de Datos (Conductor + Coche) ---
$phone = filterRequest("phone");
$password = filterRequest("password");
$firstName = filterRequest("first_name");
$lastName = filterRequest("last_name");
// تسجيل البيانات المبدئية (بدون كلمات المرور) للتأكد من وصولها
logStep(2, "Inputs received -> Phone: $phone, Name: $firstName $lastName");
// التحقق من الحقول الإجبارية
if (empty($phone) || empty($password) || empty($firstName) || empty($lastName)) {
throw new Exception("Required fields missing (phone, password, first_name, last_name).");
}
// --- 3. Generar ID de Conductor ---
$driverId = substr(md5($phone), 0, 20);
logStep(3, "Driver ID generated: $driverId");
// --- 4. Procesamiento de Datos del Conductor ---
$password_hashed = password_hash($password, PASSWORD_DEFAULT);
$email = filterRequest("email");
if (empty($email) || $email === 'Not specified') {
$email = $phone . '@intaleqapp.com';
}
$nameArabic = $firstName . ' ' . $lastName;
$site = filterRequest("site");
$address = $site;
// بيانات إضافية
$gender = filterRequest("gender");
$license_type = filterRequest("license_type");
$nationalNumber = filterRequest("national_number");
$issue_date = filterRequest("issue_date");
$expiry_date = filterRequest("expiry_date");
$licenseCategories = filterRequest("license_categories");
$licenseIssueDate = filterRequest("license_issue_date");
$birthdate = filterRequest("birthdate");
$maritalStatus = filterRequest("maritalStatus");
// --- 5. Recolección de Datos del Coche ---
$owner = filterRequest("owner");
$color = filterRequest("color");
$colorHex = filterRequest("color_hex");
$model = filterRequest("model");
$carPlate = filterRequest("car_plate");
$make = filterRequest("make");
$fuel = filterRequest("fuel");
$year = filterRequest("year");
$vin = filterRequest("vin");
if (empty($vin)) {
$vin = 'unknown';
}
$carExpirationDate = filterRequest("expiration_date");
logStep(4, "Data processing completed. Car Plate: $carPlate, VIN: $vin");
// --- 6. Cifrado de Datos ---
try {
$encryptedPhone = $encryptionHelper->encryptData($phone);
$encryptedEmail = $encryptionHelper->encryptData($email);
$encryptedFirstName = $encryptionHelper->encryptData($firstName);
$encryptedLastName = $encryptionHelper->encryptData($lastName);
$encryptedNameArabic = $encryptionHelper->encryptData($nameArabic);
$encryptedGender = $encryptionHelper->encryptData($gender);
$encryptedNationalNumber = $encryptionHelper->encryptData($nationalNumber);
$encryptedAddress = $encryptionHelper->encryptData($address);
$encryptedSite = $encryptionHelper->encryptData($site);
$encryptedBirthdate = $encryptionHelper->encryptData($birthdate);
$encryptedOwner = $encryptionHelper->encryptData($owner);
$encryptedCarPlate = $encryptionHelper->encryptData($carPlate);
logStep(5, "Encryption successful for sensitive fields.");
} catch (Exception $encEx) {
throw new Exception("Encryption Error: " . $encEx->getMessage());
}
// --- 7. Comprobación de Duplicados ---
// ملاحظة: إذا كان التشفير عشوائياً، فلن يجد التكرار هنا.
$dup = $con->prepare("SELECT id FROM driver WHERE phone = :phone OR email = :email OR national_number = :national_number");
$dup->execute([':phone' => $encryptedPhone, ':email' => $encryptedEmail, ':national_number' =>$encryptedNationalNumber]);
if ($dup->rowCount() > 0) {
logStep(6, "Duplicate found! Phone or Email or encryptedNationalNumber already exists.");
throw new Exception("Phone or email already registered.");
}
logStep(6, "No duplicates found. Proceeding.");
// --- 8. INSERCIÓN 1: Tabla 'driver' ---
$sqlDriver = "
INSERT INTO driver (
id, phone, email, password, gender, license_type, national_number,
name_arabic, issue_date, expiry_date, license_categories,
address, licenseIssueDate, status, birthdate, site,
first_name, last_name, accountBank, bankCode,
employmentType, maritalStatus, fullNameMaritial, expirationDate,
created_at, updated_at
) VALUES (
:id, :phone, :email, :pwd, :gender, :license_type, :national_number,
:name_arabic, :issue_date, :expiry_date, :license_categories,
:address, :licenseIssueDate, :status, :birthdate, :site,
:first_name, :last_name, :accountBank, :bankCode,
:employmentType, :maritalStatus, :fullNameMaritial, :expirationDate,
NOW(), NOW()
)
";
$stmtDriver = $con->prepare($sqlDriver);
// تم توحيد المفاتيح لتشمل النقطتين (:)
$driverData = [
':id' => $driverId,
':phone' => $encryptedPhone,
':email' => $encryptedEmail,
':pwd' => $password_hashed,
':gender' => $encryptedGender,
':license_type' => $license_type,
':national_number' => $encryptedNationalNumber,
':name_arabic' => $encryptedNameArabic,
':issue_date' => $issue_date,
':expiry_date' => $expiry_date,
':license_categories' => $licenseCategories ?? 'B',
':address' => $encryptedAddress,
':licenseIssueDate' => $licenseIssueDate,
':status' => 'actives',
':birthdate' => $encryptedBirthdate,
':site' => $encryptedSite,
':first_name' => $encryptedFirstName,
':last_name' => $encryptedLastName,
':accountBank' => 'yet',
':bankCode' => 'yet',
':employmentType' => $maritalStatus ?? 'yet',
':maritalStatus' => $maritalStatus ?? 'yet',
':fullNameMaritial' => 'yet',
':expirationDate' => 'yet',
];
if (!$stmtDriver->execute($driverData)) {
// تسجيل خطأ SQL بالتفصيل
$errInfo = $stmtDriver->errorInfo();
throw new Exception("Driver Insert Failed: " . $errInfo[2]);
}
logStep(7, "Driver table insert successful.");
// --- 9. INSERCIÓN 2: Tabla 'CarRegistration' ---
$sqlCar = "
INSERT INTO CarRegistration (
driverID, vin, owner, color, color_hex, model, car_plate,
make, fuel, `year`, expiration_date, created_at
) VALUES (
:driverId, :vin, :owner, :color, :color_hex, :model, :car_plate,
:make, :fuel, :year, :expiration_date, NOW()
)
";
$stmtCar = $con->prepare($sqlCar);
$carData = [
':driverId' => $driverId,
':vin' => $vin,
':owner' => $encryptedOwner,
':color' => $color,
':color_hex' => $colorHex,
':model' => $model,
':car_plate' => $encryptedCarPlate,
':make' => $make,
':fuel' => $fuel,
':year' => $year,
':expiration_date' => $carExpirationDate
];
if (!$stmtCar->execute($carData)) {
$errInfo = $stmtCar->errorInfo();
throw new Exception("Car Insert Failed: " . $errInfo[2]);
}
logStep(8, "CarRegistration insert successful.");
// --- 10. Confirmar Transacción ---
$con->commit();
logStep(9, "COMMIT successful. Sending Success Response.");
jsonSuccess(["driverId" => $driverId, "message" => "Driver and car registered successfully."]);
// --- 11. Enviar Notificación (خارج المعاملة يفضل، ولكن هنا كما في الكود الأصلي) ---
try {
$supportPhones = ['0952475740', '0952475742'];
$randomIndex = array_rand($supportPhones);
$phoneToUse = $supportPhones[$randomIndex];
$randomNumber = rand(1000, 999999);
$messageBody = "أهلاً وسهلاً كابتن $firstName 👋\n"
. "تم تفعيل حسابك على تطبيق *انطلق*.\n"
. "يمكنك الآن تسجيل الدخول والبدء بالعمل مباشرة.\n"
. "للمساعدة تواصل معنا على الرقم: $phoneToUse\n"
. "نتمنى لك عمل موفق 🚖\n\n"
. "معرف الرسالة: $randomNumber";
sendWhatsAppFromServer($phone, $messageBody);
logStep(10, "WhatsApp notification sent.");
} catch (Exception $waError) {
// لا نوقف العملية إذا فشل الواتساب، فقط نسجل الخطأ
logStep(10, "WhatsApp Warning: " . $waError->getMessage());
}
} catch (PDOException $e) {
$con->rollBack();
$errorMsg = "Database Error (PDO): " . $e->getMessage();
logStep("ERROR-PDO", $errorMsg);
// إظهار رسالة عامة للمستخدم، وتسجيل التفاصيل في السيرفر
jsonError("System error during registration. Please contact support.");
} catch (Exception $e) {
// إذا كانت المعاملة مفتوحة، قم بإلغائها
if ($con->inTransaction()) {
$con->rollBack();
}
$errorMsg = "General Error: " . $e->getMessage();
logStep("ERROR-GEN", $errorMsg);
jsonError($e->getMessage());
}
?>