Files
domnitor/app/Helpers/InputValidator.php
Hosteroid df2942b356 Add tags support for domains with filtering and bulk actions
Introduces a 'tags' field to the domains table and UI, allowing users to organize domains with custom tags. Adds tag input and display to create, edit, bulk-add, and view pages, as well as tag-based filtering and bulk tag management (add/remove) in the domain list. Updates backend validation, controller logic, and migrations to support tags, including a new migration and index for efficient tag searches.
2025-10-12 12:46:16 +03:00

255 lines
7.9 KiB
PHP

<?php
namespace App\Helpers;
/**
* Input Validator
*
* Centralized input validation helper for consistent validation across the application
*/
class InputValidator
{
/**
* Validate domain name format
*
* @param string $domain Domain name to validate
* @return bool True if valid, false otherwise
*/
public static function validateDomain(string $domain): bool
{
// Check length (max 253 characters per RFC 1035)
if (strlen($domain) > 253 || strlen($domain) < 3) {
return false;
}
// Validate domain format
// Allows: example.com, sub.example.com, example.co.uk
// Pattern: alphanumeric with hyphens, dots between labels, valid TLD
return (bool)preg_match('/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}$/i', $domain);
}
/**
* Validate text field length
*
* @param string $value Value to validate
* @param int $max Maximum length
* @param string $fieldName Field name for error message
* @return string|null Error message or null if valid
*/
public static function validateLength(string $value, int $max, string $fieldName = 'Field'): ?string
{
if (strlen($value) > $max) {
return "$fieldName is too long (maximum $max characters)";
}
return null;
}
/**
* Validate string is within min and max length
*
* @param string $value Value to validate
* @param int $min Minimum length
* @param int $max Maximum length
* @param string $fieldName Field name for error message
* @return string|null Error message or null if valid
*/
public static function validateLengthRange(string $value, int $min, int $max, string $fieldName = 'Field'): ?string
{
$len = strlen($value);
if ($len < $min) {
return "$fieldName is too short (minimum $min characters)";
}
if ($len > $max) {
return "$fieldName is too long (maximum $max characters)";
}
return null;
}
/**
* Sanitize text input (remove control characters)
*
* @param string $text Text to sanitize
* @return string Sanitized text
*/
public static function sanitizeText(string $text): string
{
// Remove control characters (except tabs and newlines for text areas)
$text = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/u', '', $text);
return trim($text);
}
/**
* Validate array size is within limits
*
* @param array $array Array to validate
* @param int $max Maximum number of elements
* @param string $fieldName Field name for error message
* @return string|null Error message or null if valid
*/
public static function validateArraySize(array $array, int $max, string $fieldName = 'Selection'): ?string
{
if (count($array) > $max) {
return "$fieldName exceeds maximum of $max items";
}
return null;
}
/**
* Sanitize search query
*
* @param string $query Search query
* @param int $maxLength Maximum length (default 100)
* @return string Sanitized query
*/
public static function sanitizeSearch(string $query, int $maxLength = 100): string
{
// Remove control characters
$query = self::sanitizeText($query);
// Limit length
if (strlen($query) > $maxLength) {
$query = substr($query, 0, $maxLength);
}
return $query;
}
/**
* Validate username format
*
* @param string $username Username to validate
* @param int $minLength Minimum length (default 3)
* @param int $maxLength Maximum length (default 50)
* @return string|null Error message or null if valid
*/
public static function validateUsername(string $username, int $minLength = 3, int $maxLength = 50): ?string
{
if (strlen($username) < $minLength) {
return "Username must be at least $minLength characters";
}
if (strlen($username) > $maxLength) {
return "Username must not exceed $maxLength characters";
}
if (!preg_match('/^[a-zA-Z0-9_]+$/', $username)) {
return 'Username can only contain letters, numbers, and underscores';
}
return null;
}
/**
* Validate URL format
*
* @param string $url URL to validate
* @return bool True if valid, false otherwise
*/
public static function validateUrl(string $url): bool
{
return filter_var($url, FILTER_VALIDATE_URL) !== false;
}
/**
* Validate email format
*
* @param string $email Email to validate
* @return bool True if valid, false otherwise
*/
public static function validateEmail(string $email): bool
{
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}
/**
* Validate numeric value is within range
*
* @param mixed $value Value to validate
* @param int|float $min Minimum value
* @param int|float $max Maximum value
* @param string $fieldName Field name for error message
* @return string|null Error message or null if valid
*/
public static function validateRange($value, $min, $max, string $fieldName = 'Value'): ?string
{
if (!is_numeric($value)) {
return "$fieldName must be a number";
}
$numValue = is_float($min) || is_float($max) ? floatval($value) : intval($value);
if ($numValue < $min || $numValue > $max) {
return "$fieldName must be between $min and $max";
}
return null;
}
/**
* Validate value is in allowed list (whitelist)
*
* @param mixed $value Value to validate
* @param array $allowed Allowed values
* @param string $fieldName Field name for error message
* @return string|null Error message or null if valid
*/
public static function validateInList($value, array $allowed, string $fieldName = 'Value'): ?string
{
if (!in_array($value, $allowed, true)) {
return "$fieldName has an invalid value";
}
return null;
}
/**
* Validate and sanitize tags
*
* @param string $tagsString Comma-separated tags
* @param int $maxTags Maximum number of tags allowed (default 10)
* @param int $maxLength Maximum length per tag (default 50)
* @return array Array with 'valid' (bool), 'tags' (string), and 'error' (string|null)
*/
public static function validateTags(string $tagsString, int $maxTags = 10, int $maxLength = 50): array
{
if (empty($tagsString)) {
return ['valid' => true, 'tags' => '', 'error' => null];
}
// Split tags and clean them
$tags = array_filter(array_map('trim', explode(',', $tagsString)));
// Check tag count
if (count($tags) > $maxTags) {
return ['valid' => false, 'tags' => '', 'error' => "Maximum $maxTags tags allowed"];
}
// Validate each tag
$validatedTags = [];
foreach ($tags as $tag) {
$tag = strtolower($tag);
// Check length
if (strlen($tag) > $maxLength) {
return ['valid' => false, 'tags' => '', 'error' => "Tag '$tag' is too long (maximum $maxLength characters)"];
}
// Check format (alphanumeric and hyphens only)
if (!preg_match('/^[a-z0-9-]+$/', $tag)) {
return ['valid' => false, 'tags' => '', 'error' => "Tag '$tag' contains invalid characters (use only letters, numbers, and hyphens)"];
}
// Avoid duplicates
if (!in_array($tag, $validatedTags)) {
$validatedTags[] = $tag;
}
}
return ['valid' => true, 'tags' => implode(',', $validatedTags), 'error' => null];
}
}