/home/smartonegroup/www/system/vendor/laminas/laminas-diactoros/src/ServerRequestFilter/IPRange.php
<?php
declare(strict_types=1);
namespace Laminas\Diactoros\ServerRequestFilter;
use function assert;
use function count;
use function explode;
use function inet_pton;
use function intval;
use function ip2long;
use function pack;
use function sprintf;
use function str_contains;
use function str_pad;
use function str_repeat;
use function substr_compare;
use function unpack;
/** @internal */
final class IPRange
{
/**
* Disable instantiation
*/
private function __construct()
{
}
/** @psalm-pure */
public static function matches(string $ip, string $cidr): bool
{
if (str_contains($ip, ':')) {
return self::matchesIPv6($ip, $cidr);
}
return self::matchesIPv4($ip, $cidr);
}
/** @psalm-pure */
public static function matchesIPv4(string $ip, string $cidr): bool
{
$mask = 32;
$subnet = $cidr;
if (str_contains($cidr, '/')) {
$parts = explode('/', $cidr, 2);
assert(count($parts) >= 2);
[$subnet, $mask] = $parts;
$mask = (int) $mask;
}
if ($mask < 0 || $mask > 32) {
return false;
}
$ip = ip2long($ip);
$subnet = ip2long($subnet);
if (false === $ip || false === $subnet) {
// Invalid data
return false;
}
return 0 === substr_compare(
sprintf("%032b", $ip),
sprintf("%032b", $subnet),
0,
$mask
);
}
/** @psalm-pure */
public static function matchesIPv6(string $ip, string $cidr): bool
{
$mask = 128;
$subnet = $cidr;
if (str_contains($cidr, '/')) {
$parts = explode('/', $cidr, 2);
assert(count($parts) >= 2);
[$subnet, $mask] = $parts;
$mask = (int) $mask;
}
if ($mask < 0 || $mask > 128) {
return false;
}
$ip = inet_pton($ip);
$subnet = inet_pton($subnet);
if (false === $ip || false === $subnet) {
// Invalid data
return false;
}
// mask 0: if it's a valid IP, it's valid
if ($mask === 0) {
return (bool) unpack('n*', $ip);
}
// @see http://stackoverflow.com/questions/7951061/matching-ipv6-address-to-a-cidr-subnet, MW answer
$binMask = str_repeat("f", intval($mask / 4));
switch ($mask % 4) {
case 0:
break;
case 1:
$binMask .= "8";
break;
case 2:
$binMask .= "c";
break;
case 3:
$binMask .= "e";
break;
}
$binMask = str_pad($binMask, 32, '0');
$binMask = pack("H*", $binMask);
return ($ip & $binMask) === $subnet;
}
}