0 follower

Final Class Yiisoft\NetworkUtilities\IpHelper

InheritanceYiisoft\NetworkUtilities\IpHelper

IpHelper contains static methods to work with IPs.

Public Methods

Hide inherited methods

Method Description Defined By
expandIPv6() Expands an IPv6 address to it's full notation. Yiisoft\NetworkUtilities\IpHelper
getCidrBits() Gets the bits from CIDR Notation. Yiisoft\NetworkUtilities\IpHelper
getIpVersion() Gets the IP version. Yiisoft\NetworkUtilities\IpHelper
inRange() Checks whether IP address or subnet $subnet is contained by $subnet. Yiisoft\NetworkUtilities\IpHelper
ip2bin() Converts IP address to bits representation. Yiisoft\NetworkUtilities\IpHelper
isIp() Yiisoft\NetworkUtilities\IpHelper
isIpv4() Yiisoft\NetworkUtilities\IpHelper
isIpv6() Yiisoft\NetworkUtilities\IpHelper

Constants

Hide inherited constants

Constant Value Description Defined By
IPV4 4 Yiisoft\NetworkUtilities\IpHelper
IPV4_ADDRESS_LENGTH 32 The length of IPv4 address in bits. Yiisoft\NetworkUtilities\IpHelper
IPV4_PATTERN '((2(5[0-5]|[0-4]\d)|1\d{2}|[1-9]?\d)\.){3}(2(5[0-5]|[0-4]\d)|1\d{2}|[1-9]?\d)' IPv4 address pattern. This pattern is PHP and JavaScript compatible. Allows to define your own IP regexp e.g. '/^'.IpHelper::IPV4_PATTERN.'/(\d+)$/'. Yiisoft\NetworkUtilities\IpHelper
IPV4_REGEXP '/^' . self::IPV4_PATTERN . '$/' IPv6 address regexp. This regexp is PHP and Javascript compatible. Yiisoft\NetworkUtilities\IpHelper
IPV6 6 Yiisoft\NetworkUtilities\IpHelper
IPV6_ADDRESS_LENGTH 128 The length of IPv6 address in bits. Yiisoft\NetworkUtilities\IpHelper
IPV6_PATTERN '(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:' . self::IPV4_PATTERN . ')' IPv6 address pattern. This pattern is PHP and Javascript compatible. Allows to define your own IP regexp e.g. '/^'.IpHelper::IPV6_PATTERN.'/(\d+)$/'. Yiisoft\NetworkUtilities\IpHelper
IPV6_REGEXP '/^' . self::IPV6_PATTERN . '$/' IPv6 address regexp. This regexp is PHP and JavaScript compatible. Yiisoft\NetworkUtilities\IpHelper
IP_PATTERN '((' . self::IPV4_PATTERN . ')|(' . self::IPV6_PATTERN . '))' IP address pattern (for both IPv4 and IPv6 versions). This pattern is PHP and Javascript compatible. Allows to define your own IP regexp. Yiisoft\NetworkUtilities\IpHelper
IP_REGEXP '/^' . self::IP_PATTERN . '$/' IP address regexp (for both IPv4 and IPv6 versions). This regexp is PHP and JavaScript compatible. Yiisoft\NetworkUtilities\IpHelper

Method Details

Hide inherited methods

expandIPv6() public static method

Expands an IPv6 address to it's full notation.

For example 2001:db8::1 will be expanded to 2001:0db8:0000:0000:0000:0000:0000:0001.

public static string expandIPv6 ( string $ip )
$ip string

The original valid IPv6 address.

return string

The expanded IPv6 address.

                public static function expandIPv6(string $ip): string
{
    $ipRaw = @inet_pton($ip);
    if ($ipRaw === false) {
        if (@inet_pton('::1') === false) {
            throw new RuntimeException('IPv6 is not supported by inet_pton()!');
        }
        throw new InvalidArgumentException("Unrecognized address $ip.");
    }
    /** @psalm-var array{hex:string} $hex */
    $hex = unpack('H*hex', $ipRaw);
    /**
     * @psalm-suppress PossiblyNullArgument We use correct regular expression, so `preg_replace()` will always
     * return a string.
     */
    return substr(preg_replace('/([a-f0-9]{4})/i', '$1:', $hex['hex']), 0, -1);
}

            
getCidrBits() public static method

Gets the bits from CIDR Notation.

public static integer getCidrBits ( string $ip )
$ip string

IP or IP with CIDR Notation (127.0.0.1, 2001:db8:a::123/64).

return integer

Bits.

                public static function getCidrBits(string $ip): int
{
    if (preg_match('/^(?<ip>.{2,}?)(?:\/(?<bits>-?\d+))?$/', $ip, $matches) === 0) {
        throw new InvalidArgumentException("Unrecognized address $ip.", 1);
    }
    $ipVersion = self::getIpVersion($matches['ip']);
    $maxBits = $ipVersion === self::IPV6 ? self::IPV6_ADDRESS_LENGTH : self::IPV4_ADDRESS_LENGTH;
    $bits = $matches['bits'] ?? null;
    if ($bits === null) {
        return $maxBits;
    }
    $bits = (int) $bits;
    if ($bits < 0) {
        throw new InvalidArgumentException('The number of CIDR bits cannot be negative.', 2);
    }
    if ($bits > $maxBits) {
        throw new InvalidArgumentException("CIDR bits is greater than $bits.", 3);
    }
    return $bits;
}

            
getIpVersion() public static method

Gets the IP version.

public static integer getIpVersion ( string $ip, boolean $validate true )
$ip string

The valid IPv4 or IPv6 address.

$validate boolean

Enable perform IP address validation. False is best practice if the data comes from a trusted source.

return integer

Value of either {@see \Yiisoft\NetworkUtilities\IPV4} or {@see \Yiisoft\NetworkUtilities\IPV6} constant.

                public static function getIpVersion(string $ip, bool $validate = true): int
{
    $ipStringLength = strlen($ip);
    if ($ipStringLength < 2) {
        throw new InvalidArgumentException("Unrecognized address $ip", 10);
    }
    $preIpVersion = strpos($ip, ':') === false ? self::IPV4 : self::IPV6;
    if ($preIpVersion === self::IPV4 && $ipStringLength < 7) {
        throw new InvalidArgumentException("Unrecognized address $ip", 11);
    }
    if (!$validate) {
        return $preIpVersion;
    }
    $rawIp = @inet_pton($ip);
    if ($rawIp !== false) {
        return strlen($rawIp) === self::IPV4_ADDRESS_LENGTH >> 3 ? self::IPV4 : self::IPV6;
    }
    if ($preIpVersion === self::IPV6 && preg_match(self::IPV6_REGEXP, $ip) === 1) {
        return self::IPV6;
    }
    throw new InvalidArgumentException("Unrecognized address $ip.", 12);
}

            
inRange() public static method

Checks whether IP address or subnet $subnet is contained by $subnet.

For example, the following code checks whether subnet 192.168.1.0/24 is in subnet 192.168.0.0/22:

IpHelper::inRange('192.168.1.0/24', '192.168.0.0/22'); // true

In case you need to check whether a single IP address 192.168.1.21 is in the subnet 192.168.1.0/24, you can use any of theses examples:

IpHelper::inRange('192.168.1.21', '192.168.1.0/24'); // true
IpHelper::inRange('192.168.1.21/32', '192.168.1.0/24'); // true

See also https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing.

public static boolean inRange ( string $subnet, string $range )
$subnet string

The valid IPv4 or IPv6 address or CIDR range, e.g.: 10.0.0.0/8 or 2001:af::/64.

$range string

The valid IPv4 or IPv6 CIDR range, e.g. 10.0.0.0/8 or 2001:af::/64.

return boolean

Whether $subnet is contained by $range.

                public static function inRange(string $subnet, string $range): bool
{
    [$ip, $mask] = array_pad(explode('/', $subnet), 2, null);
    [$net, $netMask] = array_pad(explode('/', $range), 2, null);
    assert(is_string($ip));
    assert(is_string($net));
    $ipVersion = self::getIpVersion($ip);
    $netVersion = self::getIpVersion($net);
    if ($ipVersion !== $netVersion) {
        return false;
    }
    $maxMask = $ipVersion === self::IPV4 ? self::IPV4_ADDRESS_LENGTH : self::IPV6_ADDRESS_LENGTH;
    $mask ??= $maxMask;
    $netMask ??= $maxMask;
    $binIp = self::ip2bin($ip);
    $binNet = self::ip2bin($net);
    $masked = substr($binNet, 0, (int) $netMask);
    return ($masked === '' || strpos($binIp, $masked) === 0) && $mask >= $netMask;
}

            
ip2bin() public static method

Converts IP address to bits representation.

public static string ip2bin ( string $ip )
$ip string

The valid IPv4 or IPv6 address.

return string

Bits as a string.

                public static function ip2bin(string $ip): string
{
    if (self::getIpVersion($ip) === self::IPV4) {
        $ipBinary = pack('N', ip2long($ip));
    } elseif (@inet_pton('::1') === false) {
        throw new RuntimeException('IPv6 is not supported by inet_pton()!');
    } else {
        $ipBinary = inet_pton($ip);
    }
    assert(is_string($ipBinary));
    $result = '';
    for ($i = 0, $iMax = strlen($ipBinary); $i < $iMax; $i += 4) {
        $data = substr($ipBinary, $i, 4);
        /**
         * @psalm-suppress RiskyTruthyFalsyComparison This is required for PHP 7.4 only.
         */
        if (empty($data)) {
            throw new RuntimeException('An error occurred while converting IP address to bits representation.');
        }
        /**
         * @psalm-suppress MixedArgument, PossiblyInvalidArrayAccess
         */
        $result .= str_pad(decbin(unpack('N', $data)[1]), 32, '0', STR_PAD_LEFT);
    }
    return $result;
}

            
isIp() public static method

public static boolean isIp ( string $value )
$value string

                public static function isIp(string $value): bool
{
    return preg_match(self::IP_REGEXP, $value) === 1;
}

            
isIpv4() public static method

public static boolean isIpv4 ( string $value )
$value string

                public static function isIpv4(string $value): bool
{
    return preg_match(self::IPV4_REGEXP, $value) === 1;
}

            
isIpv6() public static method

public static boolean isIpv6 ( string $value )
$value string

                public static function isIpv6(string $value): bool
{
    return preg_match(self::IPV6_REGEXP, $value) === 1;
}