*/ public const PRIVILEGE_LABELS = [ 'ALL' => 'Wszystkie uprawnienia', 'SELECT' => 'SELECT', 'INSERT' => 'INSERT', 'UPDATE' => 'UPDATE', 'DELETE' => 'DELETE', 'CREATE' => 'CREATE', 'ALTER' => 'ALTER', 'DROP' => 'DROP', 'INDEX' => 'INDEX', 'REFERENCES' => 'REFERENCES', 'CREATE_VIEW' => 'CREATE VIEW', 'SHOW_VIEW' => 'SHOW VIEW', 'TRIGGER' => 'TRIGGER', 'EXECUTE' => 'EXECUTE', 'EVENT' => 'EVENT', 'LOCK_TABLES' => 'LOCK TABLES', ]; public static function defaultPrivileges(): array { return ['ALL']; } public static function normalizeDatabaseName(string $input, string $prefix): string { return self::normalizeIdentifier($input, $prefix, 'Nazwa bazy'); } public static function normalizeRoleName(string $input, string $prefix): string { return self::normalizeIdentifier($input, $prefix, 'Nazwa użytkownika'); } public static function assertBelongsToUser(string $name, string $prefix, string $entityLabel = 'Obiekt'): void { if (strpos($name, $prefix) !== 0) { throw new InvalidArgumentException($entityLabel . ' musi zaczynać się od prefiksu: ' . $prefix); } } public static function normalizeIdentifier(string $input, string $prefix, string $label): string { $value = strtolower(trim($input)); if ($value === '') { throw new InvalidArgumentException($label . ' jest wymagana.'); } if (!preg_match('/^[a-z0-9_]+$/', $value)) { throw new InvalidArgumentException($label . ' może zawierać wyłącznie znaki a-z, 0-9 oraz _.'); } if (strpos($value, $prefix) !== 0) { $value = $prefix . $value; } if (strlen($value) > self::MAX_IDENTIFIER_LEN) { throw new InvalidArgumentException($label . ' przekracza limit 64 znaków MySQL.'); } if ($value === $prefix) { throw new InvalidArgumentException($label . ' nie może być równa samemu prefiksowi.'); } return $value; } /** * @return string[] */ public static function parseHosts(string $raw): array { $raw = str_replace(["\r\n", "\r", ';'], ["\n", "\n", "\n"], $raw); $raw = str_replace(',', "\n", $raw); $parts = explode("\n", $raw); $hosts = []; foreach ($parts as $part) { $part = trim($part); if ($part === '') { continue; } $hosts[] = $part; } return array_values(array_unique($hosts)); } public static function normalizeHost(string $input, bool $allowWildcard): string { $host = strtolower(trim($input)); if ($host === '') { throw new InvalidArgumentException('Pusty host.'); } if (in_array($host, ['localhost', '127.0.0.1', '::1', '%'], true)) { return $host; } if (self::isStrictIpv4($host)) { return $host; } if ($allowWildcard && preg_match('/^[A-Za-z0-9._%-]+$/', $host)) { return $host; } throw new InvalidArgumentException('Nieobsługiwany format hosta: ' . $input); } public static function normalizeRemoteIpv4Host(string $input): string { $host = trim($input); if ($host === '') { throw new InvalidArgumentException('Adres IPv4 jest wymagany.'); } if (!self::isStrictIpv4($host)) { throw new InvalidArgumentException('Dozwolone są tylko pojedyncze adresy IPv4, np. 203.0.113.10.'); } return $host; } public static function normalizeHostComment(string $input): string { $comment = trim(preg_replace('/[\r\n\t]+/', ' ', $input) ?? ''); $comment = preg_replace('/\s+/', ' ', $comment) ?? ''; $comment = trim($comment); if (strlen($comment) > self::MAX_HOST_COMMENT_LEN) { throw new InvalidArgumentException('Komentarz hosta przekracza limit ' . self::MAX_HOST_COMMENT_LEN . ' znaków.'); } return $comment; } /** * @param array $input * @return string[] */ public static function sanitizePrivileges(array $input): array { $allowed = array_keys(self::PRIVILEGE_LABELS); $result = []; foreach ($input as $priv) { $priv = strtoupper(trim((string)$priv)); if ($priv === '' || !in_array($priv, $allowed, true)) { continue; } $result[] = $priv; } $result = array_values(array_unique($result)); if (in_array('ALL', $result, true)) { return ['ALL']; } return $result; } private static function isStrictIpv4(string $value): bool { if (!preg_match('/^(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}$/', $value)) { return false; } return filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false; } }