'datetime', ]; } public static function normalizeDomain(?string $value): ?string { $value = trim((string) $value); if ($value === '') { return null; } $value = preg_replace('#^https?://#i', '', $value) ?? $value; $value = explode('/', $value, 2)[0]; $value = strtolower(rtrim($value)); if ($value === '' || ! str_contains($value, '.')) { return null; } return substr($value, 0, 255); } public const VISITOR_UID_LENGTH = 16; /** * Stable visitor id: same domain+ip always yields the same 16-hex value. */ public static function visitorUid(?string $domain, ?string $ip): string { $domainKey = self::normalizeDomain($domain) ?? strtolower(trim((string) $domain)); $ipKey = trim((string) $ip); return substr(hash('sha256', $domainKey."\0".$ipKey), 0, self::VISITOR_UID_LENGTH); } }