connect_error) { die("Connection failed: " . $conn->connect_error); } // Form processing if ($_SERVER['REQUEST_METHOD'] === 'POST') { // CSRF Token Validation if (!isset($_POST['csrf_token']) || !validateCSRFToken($_POST['csrf_token'])) { auditLog(null, 'CSRF_VALIDATION_FAILED', 'users', null, ['endpoint' => 'register_user.php']); echo json_encode(['status' => 'error', 'message' => 'Security token validation failed. Please try again.']); exit(); } // Check rate limiting on registration endpoint (by IP) $ip = getClientIPAddress(); $cutoffTime = date('Y-m-d H:i:s', time() - (3600)); // Last hour $stmt = $conn->prepare("SELECT COUNT(*) as count FROM audit_log WHERE action = 'REGISTRATION_ATTEMPT' AND ip_address = ? AND created_at > ?"); $stmt->bind_param('ss', $ip, $cutoffTime); $stmt->execute(); $stmt->bind_result($regAttempts); $stmt->fetch(); $stmt->close(); // Allow max 5 registration attempts per IP per hour if ($regAttempts >= 5) { auditLog(null, 'REGISTRATION_RATE_LIMIT_EXCEEDED', 'users', null, ['ip' => $ip, 'attempts' => $regAttempts]); echo json_encode(['status' => 'error', 'message' => 'Too many registration attempts. Please try again later.']); exit(); } // Validate and sanitize first name $first_name = validateName($_POST['first_name'] ?? ''); if ($first_name === false) { auditLog(null, 'REGISTRATION_INVALID_FIRST_NAME', 'users'); echo json_encode(['status' => 'error', 'message' => 'Invalid first name. Only letters, spaces, hyphens, and apostrophes allowed (2-100 characters).']); exit(); } // Validate and sanitize last name $last_name = validateName($_POST['last_name'] ?? ''); if ($last_name === false) { auditLog(null, 'REGISTRATION_INVALID_LAST_NAME', 'users'); echo json_encode(['status' => 'error', 'message' => 'Invalid last name. Only letters, spaces, hyphens, and apostrophes allowed (2-100 characters).']); exit(); } // Validate and sanitize phone number $phone_number = validatePhoneNumber($_POST['phone_number'] ?? ''); if ($phone_number === false) { auditLog(null, 'REGISTRATION_INVALID_PHONE', 'users'); echo json_encode(['status' => 'error', 'message' => 'Invalid phone number format.']); exit(); } // Validate email $email = validateEmail($_POST['email'] ?? ''); if ($email === false) { auditLog(null, 'REGISTRATION_INVALID_EMAIL', 'users'); echo json_encode(['status' => 'error', 'message' => 'Invalid email format.']); exit(); } $password = $_POST['password'] ?? ''; $password_confirm = $_POST['password_confirm'] ?? ''; // Validate password strength (minimum 8 characters, must contain uppercase, lowercase, number, special char) if (strlen($password) < 8) { echo json_encode(['status' => 'error', 'message' => 'Password must be at least 8 characters long.']); exit(); } if (!preg_match('/[A-Z]/', $password) || !preg_match('/[a-z]/', $password) || !preg_match('/[0-9]/', $password) || !preg_match('/[!@#$%^&*]/', $password)) { echo json_encode(['status' => 'error', 'message' => 'Password must contain uppercase, lowercase, number, and special character (!@#$%^&*).']); exit(); } if ($password !== $password_confirm) { echo json_encode(['status' => 'error', 'message' => 'Passwords do not match.']); exit(); } // Check if the email is already registered $stmt = $conn->prepare('SELECT user_id FROM users WHERE email = ?'); $stmt->bind_param('s', $email); $stmt->execute(); $stmt->store_result(); if ($stmt->num_rows > 0) { auditLog(null, 'REGISTRATION_EMAIL_EXISTS', 'users', null, ['email' => $email]); echo json_encode(['status' => 'error', 'message' => 'Email is already registered.']); $stmt->close(); $conn->close(); exit(); } $stmt->close(); // Hash password $hashed_password = password_hash($password, PASSWORD_BCRYPT); // Generate email verification token $token = bin2hex(random_bytes(50)); // Prepare and execute query $stmt = $conn->prepare('INSERT INTO users (first_name, last_name, phone_number, email, password, token, is_verified, type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)'); $is_verified = 0; // Not verified $type = 'credentials'; $stmt->bind_param('ssssssis', $first_name, $last_name, $phone_number, $email, $hashed_password, $token, $is_verified, $type); if ($stmt->execute()) { $newUser_id = $conn->insert_id; processLegacyMembership($newUser_id); auditLog($newUser_id, 'USER_REGISTRATION', 'users', $newUser_id, ['email' => $email]); if (sendVerificationEmail($email, $first_name . ' ' . $last_name, $token)) { sendEmail($_ENV['ADMIN_EMAIL'], '4WDCSA: New User Registration', $first_name . ' ' . $last_name . ' (' . $email . ') has just created an account using Credentials.'); echo json_encode(['status' => 'success', 'message' => 'Registration successful. Please check your email to verify your account.']); } else { echo json_encode(['status' => 'error', 'message' => 'Failed to send verification email.']); } } else { auditLog(null, 'REGISTRATION_DATABASE_ERROR', 'users', null, ['email' => $email]); echo json_encode(['status' => 'error', 'message' => 'Failed to register user.']); } $stmt->close(); } $conn->close();