* @since February 2025 */ class RegisterRequest extends FormRequest { /** * Determine if the user is authorized to make this request. */ public function authorize(): bool { return true; } /** * Get the validation rules that apply to the request. */ public function rules(): array { return [ 'first_name' => [ 'required', 'string', 'min:2', 'max:50', 'regex:/^[a-zA-ZÀ-ÿ\s\-\'\.]+$/', ], 'last_name' => [ 'required', 'string', 'min:2', 'max:50', 'regex:/^[a-zA-ZÀ-ÿ\s\-\'\.]+$/', ], 'email' => [ 'required', 'string', 'email:rfc,dns', 'max:255', 'unique:users,email', ], 'password' => [ 'required', 'string', 'confirmed', Password::min(8) ->letters() ->mixedCase() ->numbers() ->symbols() ->uncompromised(), ], 'password_confirmation' => [ 'required', 'string', 'same:password', ], 'phone' => [ 'nullable', 'string', 'min:10', 'max:20', 'regex:/^[\+]?[0-9\s\-\(\)]+$/', ], 'terms' => [ 'required', 'accepted', ], 'newsletter' => [ 'boolean', ], 'marketing' => [ 'boolean', ], ]; } /** * Get custom error messages for validation rules. */ public function messages(): array { return [ 'first_name.required' => 'First name is required.', 'first_name.min' => 'First name must be at least 2 characters.', 'first_name.regex' => 'First name contains invalid characters.', 'last_name.required' => 'Last name is required.', 'last_name.min' => 'Last name must be at least 2 characters.', 'last_name.regex' => 'Last name contains invalid characters.', 'email.required' => 'Email address is required.', 'email.email' => 'Please enter a valid email address.', 'email.unique' => 'An account with this email address already exists.', 'password.required' => 'Password is required.', 'password.min' => 'Password must be at least 8 characters long.', 'password.confirmed' => 'Password confirmation does not match.', 'password_confirmation.required' => 'Password confirmation is required.', 'password_confirmation.same' => 'Password confirmation must match the password.', 'phone.regex' => 'Please enter a valid phone number.', 'terms.required' => 'You must accept the terms and conditions.', 'terms.accepted' => 'You must accept the terms and conditions.', ]; } /** * Get custom attributes for validator errors. */ public function attributes(): array { return [ 'first_name' => 'first name', 'last_name' => 'last name', 'email' => 'email address', 'password' => 'password', 'password_confirmation' => 'password confirmation', 'phone' => 'phone number', 'terms' => 'terms and conditions', 'newsletter' => 'newsletter subscription', 'marketing' => 'marketing communications', ]; } /** * Prepare the data for validation. */ protected function prepareForValidation(): void { $this->merge([ 'first_name' => ucfirst(strtolower(trim($this->first_name))), 'last_name' => ucfirst(strtolower(trim($this->last_name))), 'email' => strtolower(trim($this->email)), 'phone' => $this->phone ? preg_replace('/[^\+0-9]/', '', $this->phone) : null, 'newsletter' => $this->boolean('newsletter'), 'marketing' => $this->boolean('marketing'), ]); } /** * Configure advanced validation rules and security checks * * Implements additional validation logic beyond standard rules: * - Name similarity validation * - Suspicious pattern detection * - Data integrity verification * * @param \Illuminate\Validation\Validator $validator * @return void */ public function withValidator($validator): void { $validator->after(function ($validator) { if ($this->first_name === $this->last_name) { $validator->errors()->add( 'last_name', 'Last name should be different from first name.' ); } $suspiciousPatterns = ['test', 'admin', 'root', 'null', 'undefined']; $fullName = strtolower($this->first_name . ' ' . $this->last_name); foreach ($suspiciousPatterns as $pattern) { if (strpos($fullName, $pattern) !== false) { $validator->errors()->add( 'first_name', 'Please enter your real name.' ); break; } } }); } /** * Handle failed registration validation for security monitoring * * Logs failed registration attempts with comprehensive security context * including user input, IP address, and validation errors. * Critical for detecting registration abuse and attacks. * * @param \Illuminate\Contracts\Validation\Validator $validator * @return void * @throws \Illuminate\Validation\ValidationException */ protected function failedValidation($validator): void { logger()->warning('Registration validation failed', [ 'email' => $this->input('email'), 'first_name' => $this->input('first_name'), 'last_name' => $this->input('last_name'), 'ip' => $this->ip(), 'user_agent' => $this->userAgent(), 'errors' => $validator->errors()->toArray(), ]); parent::failedValidation($validator); } }