Final Class Yiisoft\NetworkUtilities\IpHelper
| Inheritance | Yiisoft\NetworkUtilities\IpHelper |
|---|
IpHelper contains static methods to work with IPs.
Public 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
| 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
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);
}
Gets the bits from CIDR Notation.
| public static integer getCidrBits ( string $ip ) | ||
| $ip | string |
IP or IP with CIDR Notation ( |
| 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;
}
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);
}
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.: |
| $range | string |
The valid IPv4 or IPv6 CIDR range, e.g. |
| 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;
}
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;
}
| public static boolean isIp ( string $value ) | ||
| $value | string | |
public static function isIp(string $value): bool
{
return preg_match(self::IP_REGEXP, $value) === 1;
}
| public static boolean isIpv4 ( string $value ) | ||
| $value | string | |
public static function isIpv4(string $value): bool
{
return preg_match(self::IPV4_REGEXP, $value) === 1;
}
Signup or Login in order to comment.