*/ private const LOCAL_SUFFIXES = ['.localhost', '.local', '.lan', '.internal', '.home.arpa', '.test']; public static function url(string $publicUrl, ?string $dnsStatus = null, ?string $expectedIp = null): ?string { $parts = parse_url($publicUrl); if (! is_array($parts) || ! isset($parts['scheme'], $parts['host'])) { return null; } if (self::isPrivateHost($parts['host'])) { return null; } if ($dnsStatus === 'ok' && filled($expectedIp) && ! DnsRecordHints::isPublicAddress($expectedIp)) { return null; } $port = isset($parts['port']) ? ':'.$parts['port'] : ''; return $parts['scheme'].'://'.$parts['host'].$port.'/favicon.ico'; } private static function isPrivateHost(string $host): bool { $host = strtolower(trim($host, '[]')); if (filter_var($host, FILTER_VALIDATE_IP) !== false) { return ! DnsRecordHints::isPublicAddress($host); } if ($host === 'localhost') { return true; } foreach (self::LOCAL_SUFFIXES as $suffix) { if (str_ends_with($host, $suffix)) { return true; } } if (preg_match('/(?:^|\.)(\d{1,3}(?:[.-]\d{1,3}){3})\.(?:sslip|nip)\.io$/', $host, $matches) === 1) { $embeddedIp = str_replace('-', '.', $matches[1]); return filter_var($embeddedIp, FILTER_VALIDATE_IP) === false || ! DnsRecordHints::isPublicAddress($embeddedIp); } // sslip.io writes an IPv6 address with dashes: fd00--1.sslip.io is fd00::1. if (preg_match('/(?:^|\.)([0-9a-f]*-[0-9a-f-]*)\.(?:sslip|nip)\.io$/', $host, $matches) === 1) { $embeddedIp = str_replace('-', ':', $matches[1]); return filter_var($embeddedIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false && ! DnsRecordHints::isPublicAddress($embeddedIp); } return false; } }