enforce(RateLimiter::identifier(), 'otp_verify'); // 1. Fetch input parameters $phone_number = filterRequest("phone_number"); if (empty($phone_number)) { $phone_number = filterRequest("receiver"); } $token_code = filterRequest("token_code"); if (empty($token_code)) { $token_code = filterRequest("token"); } $user_type = filterRequest("user_type"); $context = filterRequest("context"); // token_change | login (default) // user_type is taken from request only (JWT not trusted without signature verification) if (empty($phone_number)) { jsonError("Phone number is required."); exit; } if (empty($token_code)) { jsonError("Verification token code is required."); exit; } if (empty($user_type)) { if (strpos($_SERVER['REQUEST_URI'], 'driver') !== false) { $user_type = 'driver'; } else { $user_type = 'passenger'; } } if (empty($user_type) || !in_array($user_type, ['passenger', 'driver', 'admin', 'service'])) { jsonError("User type must be 'passenger', 'driver', 'admin', or 'service'."); exit; } // 2. Establish DB Connection try { $con = Database::get('main'); } catch (Exception $e) { http_response_code(500); exit(json_encode(['error' => 'Database connection failed'])); } // 3. Encrypt data to query $encryptedPhone = $encryptionHelper->encryptData($phone_number); $encryptedToken = $encryptionHelper->encryptData($token_code); // 4. Verify based on user type try { if ($user_type === 'admin') { $sql = "SELECT * FROM token_verification_admin WHERE phone_number = :phone AND token = :token AND expiration_time >= NOW() AND verified = 0"; $stmt = $con->prepare($sql); $stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR); $stmt->bindParam(':token', $encryptedToken, PDO::PARAM_STR); $stmt->execute(); if ($stmt->rowCount() > 0) { $deviceNumber = filterRequest("device_number") ?? ''; // adminUser stores unencrypted phone $checkAdmin = $con->prepare("SELECT * FROM adminUser WHERE name = ?"); $checkAdmin->execute([$phone_number]); $now = date("Y-m-d H:i:s"); if ($checkAdmin->rowCount() > 0) { $update = $con->prepare("UPDATE adminUser SET device_number = ?, updated_at = ? WHERE name = ?"); $update->execute([$deviceNumber, $now, $phone_number]); jsonSuccess(["message" => "verified and updated existing admin"]); } else { $insert = $con->prepare("INSERT INTO adminUser (device_number, name, created_at, updated_at) VALUES (?, ?, ?, ?)"); $insert->execute([$deviceNumber, $phone_number, $now, $now]); jsonSuccess(["message" => "verified and new admin created"]); } } else { jsonError("Your phone number could not be verified or the code is expired. Please try again."); } } elseif ($user_type === 'service') { $sql = "SELECT `id` FROM `phone_verification_service` WHERE `phone_number` = :phone AND `token_code` = :token AND `expiration_time` > NOW() AND `is_verified` = 0"; $stmt = $con->prepare($sql); $stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR); $stmt->bindParam(':token', $encryptedToken, PDO::PARAM_STR); $stmt->execute(); $result = $stmt->fetch(); if ($result) { $sqlUpdate = "UPDATE `phone_verification_service` SET `is_verified` = 1 WHERE `phone_number` = :phone"; $stmtUpd = $con->prepare($sqlUpdate); $stmtUpd->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR); $stmtUpd->execute(); jsonSuccess(null, "Your phone number has been verified."); } else { jsonError("Your phone number could not be verified or the code is expired. Please try again."); } } elseif ($user_type === 'driver') { if ($context === 'token_change') { $sql = "SELECT `id` FROM `token_verification_driver` WHERE `phone_number` = :phone AND `token` = :token AND `expiration_time` > NOW() AND `verified` = 0"; $stmt = $con->prepare($sql); $stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR); $stmt->bindParam(':token', $encryptedToken, PDO::PARAM_STR); $stmt->execute(); $result = $stmt->fetch(); if ($result) { // Update driver verified status $sqlUpdate = "UPDATE `token_verification_driver` SET `verified` = 1 WHERE `phone_number` = :phone"; $stmtUpd = $con->prepare($sqlUpdate); $stmtUpd->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR); $stmtUpd->execute(); jsonSuccess(null, "Your phone number has been verified."); } else { jsonError("Your phone number could not be verified or the code is expired. Please try again."); } } else { $sql = "SELECT `id` FROM `phone_verification` WHERE `phone_number` = :phone AND `token_code` = :token AND `expiration_time` > NOW() AND `is_verified` = 0"; $stmt = $con->prepare($sql); $stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR); $stmt->bindParam(':token', $encryptedToken, PDO::PARAM_STR); $stmt->execute(); $result = $stmt->fetch(); if ($result) { // Update driver is_verified status $sqlUpdate = "UPDATE `phone_verification` SET `is_verified` = 1 WHERE `phone_number` = :phone"; $stmtUpd = $con->prepare($sqlUpdate); $stmtUpd->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR); $stmtUpd->execute(); jsonSuccess(null, "Your phone number has been verified."); } else { jsonError("Your phone number could not be verified or the code is expired. Please try again."); } } } else { if ($context === 'token_change') { $sql = "SELECT `id` FROM `token_verification` WHERE `phone_number` = :phone AND `token` = :token AND `expiration_time` > NOW() AND `verified` = 0"; $stmt = $con->prepare($sql); $stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR); $stmt->bindParam(':token', $encryptedToken, PDO::PARAM_STR); $stmt->execute(); $result = $stmt->fetch(); if ($result) { // Update passenger verified status $sqlUpdate = "UPDATE `token_verification` SET `verified` = 1 WHERE `phone_number` = :phone"; $stmtUpd = $con->prepare($sqlUpdate); $stmtUpd->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR); $stmtUpd->execute(); jsonSuccess(null, "Your phone number has been verified."); } else { jsonError("Your phone number could not be verified or the code is expired. Please try again."); } } else { $sql = "SELECT `id` FROM `phone_verification_passenger` WHERE `phone_number` = :phone AND `token` = :token AND `expiration_time` > NOW() AND `verified` = 0"; $stmt = $con->prepare($sql); $stmt->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR); $stmt->bindParam(':token', $encryptedToken, PDO::PARAM_STR); $stmt->execute(); $result = $stmt->fetch(); if ($result) { // Update passenger verified status $sqlUpdate = "UPDATE `phone_verification_passenger` SET `verified` = 1 WHERE `phone_number` = :phone"; $stmtUpd = $con->prepare($sqlUpdate); $stmtUpd->bindParam(':phone', $encryptedPhone, PDO::PARAM_STR); $stmtUpd->execute(); jsonSuccess(null, "Your phone number has been verified."); } else { jsonError("Your phone number could not be verified or the code is expired. Please try again."); } } } } catch (PDOException $e) { error_log("⚠️ [OTP DB Verify] Error: " . $e->getMessage()); jsonError("An error occurred during verification. Please try again."); }