183 lines
5.3 KiB
PHP
183 lines
5.3 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
final class NamePolicy
|
|
{
|
|
public const MAX_IDENTIFIER_LEN = 64;
|
|
public const MAX_HOST_COMMENT_LEN = 180;
|
|
|
|
/**
|
|
* @var array<string,string>
|
|
*/
|
|
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<int,string> $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;
|
|
}
|
|
}
|