1 | <?php |
||
18 | class BaseIpHelper |
||
19 | { |
||
20 | const IPV4 = 4; |
||
21 | const IPV6 = 6; |
||
22 | /** |
||
23 | * The length of IPv6 address in bits |
||
24 | */ |
||
25 | const IPV6_ADDRESS_LENGTH = 128; |
||
26 | /** |
||
27 | * The length of IPv4 address in bits |
||
28 | */ |
||
29 | const IPV4_ADDRESS_LENGTH = 32; |
||
30 | |||
31 | |||
32 | /** |
||
33 | * Gets the IP version. Does not perform IP address validation. |
||
34 | * |
||
35 | * @param string $ip the valid IPv4 or IPv6 address. |
||
36 | * @return int [[IPV4]] or [[IPV6]] |
||
37 | */ |
||
38 | 41 | public static function getIpVersion($ip) |
|
42 | |||
43 | /** |
||
44 | * Checks whether IP address or subnet $subnet is contained by $subnet. |
||
45 | * |
||
46 | * For example, the following code checks whether subnet `192.168.1.0/24` is in subnet `192.168.0.0/22`: |
||
47 | * |
||
48 | * ```php |
||
49 | * IpHelper::inRange('192.168.1.0/24', '192.168.0.0/22'); // true |
||
50 | * ``` |
||
51 | * |
||
52 | * In case you need to check whether a single IP address `192.168.1.21` is in the subnet `192.168.1.0/24`, |
||
53 | * you can use any of theses examples: |
||
54 | * |
||
55 | * ```php |
||
56 | * IpHelper::inRange('192.168.1.21', '192.168.1.0/24'); // true |
||
57 | * IpHelper::inRange('192.168.1.21/32', '192.168.1.0/24'); // true |
||
58 | * ``` |
||
59 | * |
||
60 | * @param string $subnet the valid IPv4 or IPv6 address or CIDR range, e.g.: `10.0.0.0/8` or `2001:af::/64` |
||
61 | * @param string $range the valid IPv4 or IPv6 CIDR range, e.g. `10.0.0.0/8` or `2001:af::/64` |
||
62 | * @return bool whether $subnet is contained by $range |
||
63 | * |
||
64 | * @see https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing |
||
65 | */ |
||
66 | 23 | public static function inRange($subnet, $range) |
|
67 | { |
||
68 | 23 | [$ip, $mask] = array_pad(explode('/', $subnet), 2, null); |
|
69 | 23 | [$net, $netMask] = array_pad(explode('/', $range), 2, null); |
|
70 | |||
71 | 23 | $ipVersion = static::getIpVersion($ip); |
|
72 | 23 | $netVersion = static::getIpVersion($net); |
|
73 | 23 | if ($ipVersion !== $netVersion) { |
|
74 | 2 | return false; |
|
75 | } |
||
76 | |||
77 | 23 | $maxMask = $ipVersion === self::IPV4 ? self::IPV4_ADDRESS_LENGTH : self::IPV6_ADDRESS_LENGTH; |
|
78 | 23 | $mask = $mask ?? $maxMask; |
|
79 | 23 | $netMask = $netMask ?? $maxMask; |
|
80 | |||
81 | 23 | $binIp = static::ip2bin($ip); |
|
82 | 23 | $binNet = static::ip2bin($net); |
|
83 | 23 | return substr($binIp, 0, $netMask) === substr($binNet, 0, $netMask) && $mask >= $netMask; |
|
84 | } |
||
85 | |||
86 | /** |
||
87 | * Expands an IPv6 address to it's full notation. |
||
88 | * |
||
89 | * For example `2001:db8::1` will be expanded to `2001:0db8:0000:0000:0000:0000:0000:0001` |
||
90 | * |
||
91 | * @param string $ip the original valid IPv6 address |
||
92 | * @return string the expanded IPv6 address |
||
93 | */ |
||
94 | 4 | public static function expandIPv6($ip) |
|
99 | |||
100 | /** |
||
101 | * Converts IP address to bits representation. |
||
102 | * |
||
103 | * @param string $ip the valid IPv4 or IPv6 address |
||
104 | * @return string bits as a string |
||
105 | */ |
||
106 | 27 | public static function ip2bin($ip) |
|
121 | } |
||
122 |
This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.