enforce(RateLimiter::identifier(), 'register_passenger'); // تعريف بادئة للوج (Tag) لسهولة البحث عنها في ملف الأخطاء $logTag = "[Register_Debug_passenger]"; $step = 0; try { // ====================================================== // Step 1: استقبال البيانات // ====================================================== $step = 1; $phoneNumber = filterRequest("phone_number"); $firstName = filterRequest("first_name"); $lastName = filterRequest("last_name"); $email = filterRequest("email"); // طباعة وصول البيانات (مع إخفاء جزء من الرقم) error_log("$logTag Step 1: Received request. Phone: " . substr($phoneNumber, 0, 7) . "*****"); // ====================================================== // Step 2: التحقق من المدخلات // ====================================================== $step = 2; if (empty($phoneNumber) || empty($firstName) || empty($lastName)) { error_log("$logTag Step 2 Error: Missing required fields."); jsonError("Required fields are missing."); exit(); } // ====================================================== // Step 3: معالجة الإيميل // ====================================================== $step = 3; if (empty($email)) { $email = $phoneNumber . '@intaleqapp.com'; error_log("$logTag Step 3: Email was empty, generated default: " . substr($email, 0, 5) . "***"); } // ====================================================== // Step 4: تشفير البيانات // ====================================================== $step = 4; error_log("$logTag Step 4: Encrypting data..."); if (!isset($encryptionHelper)) { throw new Exception("Encryption Helper class is missing."); } $phoneNumber_encrypted = $encryptionHelper->encryptData($phoneNumber); $firstName_encrypted = $encryptionHelper->encryptData($firstName); $lastName_encrypted = $encryptionHelper->encryptData($lastName); $email_encrypted = $encryptionHelper->encryptData($email); $uniqueId = substr(md5($phoneNumber), 0, 20); $password_hashed = password_hash($email . $uniqueId, PASSWORD_DEFAULT); $unknown_encrypted = $encryptionHelper->encryptData("unknown yet"); // ====================================================== // Step 4.5: التحقق الفعلي من ملكية رقم الهاتف (🔥 Fix) // ====================================================== // كانت هذه النقطة تسمح بإنشاء حساب راكب بأي رقم هاتف بدون إثبات // ملكيته فعلياً — auth/otp/verify.php يُعلّم الصف verified=1 لكن // register_passenger.php لم يكن يتحقق من ذلك إطلاقاً. الآن نشترط // وجود صف تحقق ناجح (verified=1) لنفس رقم الهاتف خلال آخر 30 دقيقة // (مهلة أوسع من صلاحية الرمز نفسه [5 دقائق] لإعطاء وقت كافٍ لإكمال // نموذج التسجيل بعد التحقق مباشرة). $step = 4.5; $verifyCheckStmt = $con->prepare( "SELECT id FROM phone_verification_passenger WHERE phone_number = ? AND verified = 1 AND created_at > DATE_SUB(NOW(), INTERVAL 30 MINUTE) LIMIT 1" ); $verifyCheckStmt->execute([$phoneNumber_encrypted]); if ($verifyCheckStmt->rowCount() === 0) { error_log("$logTag Step 4.5 Error: Phone number not verified via OTP."); jsonError("Phone number must be verified before registration."); exit(); } // ====================================================== // Step 5: إنشاء ID فريد // ====================================================== $step = 5; // $uniqueId = substr(md5(uniqid(mt_rand(), true)), 0, 20); // $uniqueId is now generated earlier error_log("$logTag Step 5: Generated Unique ID: $uniqueId"); // ====================================================== // Step 6: التحقق من وجود المستخدم (Database Check) // ====================================================== $step = 6; // كشف التكرار عبر الفهرس الأعمى + المقارنة القديمة: بدون الفهرس يفشل // الكشف بعد الانتقال إلى GCM فيُسمح بتسجيل نفس الرقم مرتين. global $blindIndex; $phoneBidx = $blindIndex ? $blindIndex->index('passengers.phone', $phoneNumber) : null; $emailBidx = $blindIndex ? $blindIndex->index('passengers.email', $email) : null; $nameBidx = $blindIndex ? $blindIndex->index('passengers.name', trim("$firstName $lastName")) : null; $checkStmt = $con->prepare( "SELECT id FROM passengers WHERE phone = ? OR (? IS NOT NULL AND phone_bidx = ?)" ); $checkStmt->execute([$phoneNumber_encrypted, $phoneBidx, $phoneBidx]); if ($checkStmt->rowCount() > 0) { error_log("$logTag Step 6 Error: User already exists."); jsonError("User with this phone number or email already exists."); exit(); } // ====================================================== // Step 7: الإضافة (Insert User) // ====================================================== $step = 7; error_log("$logTag Step 7: Inserting into passengers table..."); $insertStmt = $con->prepare(" INSERT INTO passengers (id, first_name, last_name, email, phone, password, gender, birthdate, site, sosPhone, education, employmentType, maritalStatus, status, created_at, updated_at, phone_bidx, email_bidx, name_bidx) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'active', NOW(), NOW(), ?, ?, ?) "); $success = $insertStmt->execute([ $uniqueId, $firstName_encrypted, $lastName_encrypted, $email_encrypted, $phoneNumber_encrypted, $password_hashed, $unknown_encrypted, $unknown_encrypted, $unknown_encrypted, $unknown_encrypted, $unknown_encrypted, $unknown_encrypted, $unknown_encrypted, // فهارس البحث: تُكتب مع السجل حتى يكون قابلاً للبحث فوراً $phoneBidx, $emailBidx, $nameBidx ]); if (!$success) { $errorInfo = $insertStmt->errorInfo(); // طباعة تفاصيل خطأ الـ SQL في اللوج error_log("$logTag Step 7 Error: SQL Insert Failed. Details: " . json_encode($errorInfo)); jsonError("Failed to create user account."); exit(); } // ====================================================== // Step 9: جلب البيانات لإعادتها // ====================================================== $step = 9; $userStmt = $con->prepare("SELECT * FROM passengers WHERE id = ?"); $userStmt->execute([$uniqueId]); $newUser = $userStmt->fetch(PDO::FETCH_ASSOC); // ====================================================== // Step 10: فك التشفير وإرسال الرد // ====================================================== $step = 10; if ($newUser) { unset($newUser['password']); foreach ($newUser as $key => &$value) { if ($key !== 'id' && $key !== 'status' && $key !== 'created_at' && $key !== 'updated_at' && !is_null($value)) { $value = $encryptionHelper->decryptData($value); } } } error_log("$logTag Success: User registered successfully."); jsonSuccess(["status" => "registration_success", "data" => $newUser]); } catch (PDOException $e) { // طباعة خطأ قاعدة البيانات في اللوج error_log("$logTag PDO Exception at Step $step: " . $e->getMessage()); jsonError("Database Error."); } catch (Exception $e) { // طباعة الأخطاء العامة في اللوج error_log("$logTag General Exception at Step $step: " . $e->getMessage()); jsonError("General Error."); } ?>