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