Files
Siro/backend/auth/syria/driver/register_driver_and_car_signed.php
2026-06-16 17:47:19 +03:00

303 lines
12 KiB
PHP

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