data = $data; } public function validate(array $data, array $rules): bool { $this->data = $data; $this->errors = []; $this->rules = $rules; foreach ($rules as $field => $fieldRules) { $fieldRules = is_string($fieldRules) ? explode('|', $fieldRules) : $fieldRules; $value = $data[$field] ?? null; foreach ($fieldRules as $rule) { $params = []; if (str_contains($rule, ':')) { [$rule, $paramStr] = explode(':', $rule, 2); $params = explode(',', $paramStr); } $method = 'validate' . ucfirst($rule); if (method_exists($this, $method)) { $this->{$method}($field, $value, $params); } } } return empty($this->errors); } public function getErrors(): array { return $this->errors; } public function getFirstError(): ?string { if (empty($this->errors)) { return null; } $first = reset($this->errors); return is_array($first) ? reset($first) : $first; } public function addError(string $field, string $message): void { $this->errors[$field][] = $message; } private function validateRequired(string $field, mixed $value, array $params): void { if ($value === null || $value === '' || (is_array($value) && empty($value))) { $this->errors[$field][] = "The {$field} field is required."; } } private function validateEmail(string $field, mixed $value, array $params): void { if ($value !== null && $value !== '' && !filter_var($value, FILTER_VALIDATE_EMAIL)) { $this->errors[$field][] = "The {$field} field must be a valid email address."; } } private function validateMin(string $field, mixed $value, array $params): void { $min = (int) ($params[0] ?? 0); if (is_string($value) && mb_strlen($value) < $min) { $this->errors[$field][] = "The {$field} field must be at least {$min} characters."; } elseif (is_numeric($value) && $value < $min) { $this->errors[$field][] = "The {$field} field must be at least {$min}."; } } private function validateMax(string $field, mixed $value, array $params): void { $max = (int) ($params[0] ?? 0); if (is_string($value) && mb_strlen($value) > $max) { $this->errors[$field][] = "The {$field} field must not exceed {$max} characters."; } elseif (is_numeric($value) && $value > $max) { $this->errors[$field][] = "The {$field} field must not exceed {$max}."; } } private function validatesNumeric(string $field, mixed $value, array $params): void { if ($value !== null && $value !== '' && !is_numeric($value)) { $this->errors[$field][] = "The {$field} field must be a number."; } } private function validatesInteger(string $field, mixed $value, array $params): void { if ($value !== null && $value !== '' && filter_var($value, FILTER_VALIDATE_INT) === false) { $this->errors[$field][] = "The {$field} field must be an integer."; } } private function validatesIp(string $field, mixed $value, array $params): void { if ($value !== null && $value !== '' && !filter_var($value, FILTER_VALIDATE_IP)) { $this->errors[$field][] = "The {$field} field must be a valid IP address or hostname."; } } private function validatesPort(string $field, mixed $value, array $params): void { if ($value !== null && $value !== '') { $port = (int) $value; if ($port < 1 || $port > 65535) { $this->errors[$field][] = "The {$field} field must be a valid port (1-65535)."; } } } private function validatesAlphaNum(string $field, mixed $value, array $params): void { if ($value !== null && $value !== '' && !preg_match('/^[a-zA-Z0-9_\-]+$/', $value)) { $this->errors[$field][] = "The {$field} field may only contain letters, numbers, dashes and underscores."; } } private function validatesMatch(string $field, mixed $value, array $params): void { $otherField = $params[0] ?? null; if ($otherField && ($this->data[$otherField] ?? null) !== $value) { $this->errors[$field][] = "The {$field} field does not match {$otherField}."; } } private function validatesIn(string $field, mixed $value, array $params): void { if ($value !== null && $value !== '' && !in_array($value, $params, true)) { $this->errors[$field][] = "The selected {$field} is invalid."; } } private function validatesJson(string $field, mixed $value, array $params): void { if ($value !== null && $value !== '' && is_string($value)) { json_decode($value); if (json_last_error() !== JSON_ERROR_NONE) { $this->errors[$field][] = "The {$field} field must be valid JSON."; } } } }