Inloggen
NL
<?phpnamespace App\Model;/** * Addresses checked in plain PHP: the browser's PHP has no filter extension (filter_var() is undefined there: the VNC console * died on it, "Call to undefined function App\Model\filter_var()"). */final class Address{    /** An IPv4 (192.168.1.10) or IPv6 (fe80::1, ::ffff:10.0.0.1) address, not a name. */    public static function isIp(string $text): bool    {        return self::isIpv4($text) || self::isIpv6($text);    }    public static function isIpv4(string $text): bool    {        if (!preg_match('/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/', $text, $m)) {            return false;        }        foreach (array_slice($m, 1) as $part) {            if ((int)$part > 255 || (strlen($part) > 1 && $part[0] === '0')) {                return false;            }        }        return true;    }    public static function isIpv6(string $text): bool    {        $text = trim($text, '[]');        if (!str_contains($text, ':') || !preg_match('/^[0-9a-f:.]+$/i', $text) || substr_count($text, '::') > 1 || str_contains($text, ':::')) {            return false;        }        $groups = explode(':', $text);        $last = end($groups);        $count = count($groups);        if (str_contains($last, '.')) {             // an IPv4 tail counts as two groups            if (!self::isIpv4($last)) {                return false;            }            array_pop($groups);            $count++;        }        foreach ($groups as $i => $g) {            if ($g === '' ? !str_contains($text, '::') : !preg_match('/^[0-9a-f]{1,4}$/i', $g)) {                return false;            }        }        return str_contains($text, '::') ? $count <= 9 : $count === 8;    }    /**     * An address of a local / private network, which the JumPHP server's bridge refuses (only the JumPHP runtime on the user's computer     * reaches it from a browser): RFC 1918 (10/8, 172.16/12, 192.168/16), loopback 127/8, link-local 169.254/16, CGNAT 100.64/10 (VPNs such     * as Tailscale), 0/8; IPv6 ::1, ::, fc00::/7, fe80::/10 and IPv4-mapped ones; names: localhost, no dot at all, or ending in .local,     * .lan, .home, .internal, .localdomain, .home.arpa.     */    public static function isLocal(string $host): bool    {        $host = strtolower(rtrim(trim(trim($host), '[]'), '.'));        if ($host === '') {            return false;        }        if (self::isIpv4($host)) {            [$a, $b] = array_map('intval', explode('.', $host));            return $a === 10 || $a === 127 || $a === 0 || ($a === 172 && $b >= 16 && $b <= 31) || ($a === 192 && $b === 168)                || ($a === 169 && $b === 254) || ($a === 100 && $b >= 64 && $b <= 127);        }        if (self::isIpv6($host)) {            if (preg_match('/^::ffff:(\d+\.\d+\.\d+\.\d+)$/', $host, $m)) {                return self::isLocal($m[1]);            }            if (preg_match('/^[0:]+1?$/', $host)) {     // ::1, ::, 0:0:...:1                return true;            }            $first = explode(':', $host)[0];            $word = $first === '' ? 0 : hexdec($first);            return ($word & 0xfe00) === 0xfc00 || ($word & 0xffc0) === 0xfe80;        }        if ($host === 'localhost' || !str_contains($host, '.')) {            return true;        }        return (bool)preg_match('/\.(local|lan|home|internal|localdomain|localhost|home\.arpa)$/', $host);    }    /** [email protected], what an alert's mail needs (not every RFC 5322 corner). */    public static function isEmail(string $text): bool    {        return (bool)preg_match('/^[A-Za-z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?(?:\.[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)+$/', $text);    }}