Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/229.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在PHP中比较IP地址和通配符的优化方法?_Php_String_Performance - Fatal编程技术网

在PHP中比较IP地址和通配符的优化方法?

在PHP中比较IP地址和通配符的优化方法?,php,string,performance,Php,String,Performance,任何人都知道一种有效且安全的方法,以查看此输入是否: $_SERVER['REMOTE_ADDR'] 匹配类似于此不一致筛选器数组的内容(注意,200.100.*.*可以表示为200.100.*.*),通配符由*表示: array( '192.168.1.*', '192.168.2.1*', '10.0.0.*', '200.100.*.*', '300.200.*', ) 更新 想法 foreach($instanceSettings['accessControl']

任何人都知道一种有效且安全的方法,以查看此输入是否:

$_SERVER['REMOTE_ADDR']
匹配类似于此不一致筛选器数组的内容(注意,200.100.*.*可以表示为200.100.*.*),通配符由*表示:

array(
  '192.168.1.*',
  '192.168.2.1*',
  '10.0.0.*',
  '200.100.*.*',
  '300.200.*',
)
更新

想法

foreach($instanceSettings['accessControl']['allowedIpV4Addresses'] as $ipV4Address) {
    echo 'Now checking against '.$ipV4Address.'.';

    // Compare each octet
    $ipV4AddressOctets = String::explode('.', $ipV4Address);
    $remoteIpV4AddressOctets = String::explode('.', $_SERVER['REMOTE_ADDR']);
    $remoteIpV4AddressIsAllowed = true;
    for($i = 0; $i < Arr::size($ipV4AddressOctets); $i++) {
        echo 'Comparing '.$ipV4AddressOctets[$i].' against '.$remoteIpV4AddressOctets[$i].'.';
        if($ipV4AddressOctets[$i] != $remoteIpV4AddressOctets[$i] && $ipV4AddressOctets[$i] != '*') {
            echo 'No match.';
            $remoteIpV4AddressIsAllowed = false;
            break;
        }
    }

    // Get out of the foreach if we've found a match
    if($remoteIpV4AddressIsAllowed) {
        break;
    }
}
foreach($instanceSettings['accessControl']['allowedIpV4Addresses']作为$ipV4Address){
echo“正在检查“$ipV4Address”。”;
//比较每个八位组
$ipV4AddressOctets=String::explode('.',$ipV4Address);
$remoteIpV4AddressOctets=String::explode('.',$服务器['REMOTE\u ADDR']);
$remoteIpV4AddressIsAllowed=true;
对于($i=0;$i
为什么不使用正则表达式呢

 preg_match("((192\\.168\\.1)|(10\\.0\\.0)|(127\\.0\\.0)\\.[012]\\d{0,2}|(\\:\\:1))",$_SERVER['REMOTE_ADDR'])

删除星号,只需执行以下操作:

$ips = array('192.168.1.', '10.0.0.');

foreach ($ips as $ip) {
    if (strpos($_SERVER['REMOTE_ADDR'], $ip) === 0) {
        // match
    }
}

只是为了好玩,我要把它设计得更完美。好吧,除非你有一个相当长的名单来匹配

假设您只使用通配符来表示“我不关心这个八位元”,那么您可以将数组中的每个条目解析为四个值(每个八位元一个)。假设使用-1表示通配符,0–255表示完全匹配该值。(如果您需要比O(n)更好的性能,其中n是匹配列表的大小,那么这里可以使用更好的数据结构,例如trie。)调用此数组L。当然,您只需要执行一次,而不是每次请求

然后,您可以以相同的方式解析远程地址(除非没有通配符)。您还可以在此处发现REMOTE_ADDR的格式不符合预期,现在检查匹配项变得相当简单:

has_match(ip) =
  for n in [0 … L.length)
    if (-1 == L.n.0 || L.n.0 = ip.0) && (-1 == L.n.1 || L.n.1 == ip.1) && …
      return true
  return false

(当然,这是伪代码)

我还没有做基准测试,但我会选择使用网络硬件/软件使用的方法

将任意*替换为0和255。 将IP转换为整数

因此,如果255.255.255.*变为255.255.255.0和255.255.255.255 然后在这两个IP上执行ip2long功能

然后可以将给定的ip转换为长ip。例如,将255.255.50.51转换为长ip

然后,您可以比较此给定ip的长ip是否在黑名单中转换的长ip之间。如果是,那么它是不允许的,否则它是

$ips = array("ip1", "ip2");
foreach($ips as $ip){
 $ip1 = str_replace("*", "0", $ip);
 $ip2 = str_replace("*", "255", $ip);

 $ip1 = ip2long($ip1);
 $ip2 = ip2long($ip2);
 $givenip = $_GET["ip"];
 $givenip = ip2long($givenip);

 if($givenip >= $ip1 && $ip <= $givenip){
   echo "blacklist ip hit between {$ip1} and {$ip2} on {$ip}";
 }
}
$ips=array(“ip1”、“ip2”);
foreach($ip作为$ip){
$ip1=str_替换(“*”、“0”、$ip);
$ip2=str_替换(“*”、“255”、$ip);
$ip1=IP2长($ip1);
$ip2=ip2长($ip2);
$givenip=$_GET[“ip”];
$givenip=ip2long($givenip);

如果($givenip>=$ip1&&$ip这个选项允许问题中的所有情况加上没有像123.123这样的星号的短遮罩

/**
 * Checks given IP against array of masks like 123.123.123.123, 123.123.*.101, 123.123., 123.123.1*.*
 *
 * @param $ip
 * @param $masks
 * @return bool
 */
public static function checkIp($ip, $masks)
{
    if (in_array($ip, $masks)) {
        return true;  // Simple match
    } else {
        foreach ($masks as $mask) {
            if (substr($mask, -1) == '.' AND substr($ip, 0, strlen($mask)) == $mask) {
                return true; // Case for 123.123. mask
            }
            if (strpos($mask, '*') === false) {
                continue; // No simple matching and no wildcard in the mask, leaves no chance to match
            }
            // Breaking into triads
            $maskParts = explode('.', $mask);
            $ipParts = explode('.', $ip);
            foreach ($maskParts as $key => $maskPart) {
                if ($maskPart == '*') {
                    continue;  // This triad is matching, continue with next triad
                } elseif (strpos($maskPart, '*') !== false) {
                    // Case like 1*, 1*2, *1
                    // Let's use regexp for this
                    $regExp = str_replace('*', '\d{0,3}', $maskPart);
                    if (preg_match('/^' . $regExp . '$/', $ipParts[$key])) {
                        continue;  // Matching, go to check next triad
                    } else {
                        continue 2;  // Not matching, Go to check next mask
                    }
                } else {
                    if ($maskPart != $ipParts[$key]) {
                        continue 2; // If triad has no wildcard and not matching, check next mask
                    }
                    // otherwise just continue
                }
            }
            // We checked all triads and all matched, hence this mask is matching
            return true;
        }
        // We went through all masks and none has matched.
        return false;
    }
}

这一个是基于preg_match()的,您提供了要测试它的模式和主题

/**
 * ip_match("172.30.20.*", "172.30.20.162"); // true
 * ip_match("172.30.20", "172.30.20.162"); // true; works if incomplete
 * ip_match("172.30.*.12", "172.30.20.12"); // true
 * ip_match("172.30.*.12", "172.30.20.11"); // false
 * ip_match("172.30.20.*", "172.30.20.*"); // true; wildcards in the subject will match with wildcards in the pattern
 * ip_match("172.30.20.12", "172.30.*.*"); // false
 * 
 * @param $pattern  The pattern to test against as a string
 * @param $subject  The input string
 *
 *  @return bool
 *
 */
function ip_match($pattern, $subject) {
    $pattern = explode(".", trim($pattern, "."));
    $pattern = array_pad($pattern, 4, "*");
        
    $subject = explode(".", trim($subject, "."));
    $subject = array_pad($subject, 4, "1");
        
    foreach ($pattern as $i => $octet) {
        if ($octet != "*" && $subject[$i] != $octet) {
            return false;
        }
    }
        
    return true;
}

我想我可以根据数组的内容动态生成一个regex to。我更新了问题,使其更明显地表明筛选器数组是动态的。此解决方案不需要按照问题的要求进行“优化”。通常,IP最好被视为整数(无符号或长)将整数与整数数组进行比较要比将正则表达式数组与字符串(即ip)进行比较快@stereofrog:恐怕我从未使用过Refal(在你提到它之前也没有听说过它)。很可能我读过别人的伪代码,不过。我不太确定它与我的伪代码有什么相似之处……除了下标的
。只写了我想写的(很好的解决方案!)。关于
192.168.*.*.
?您还需要从$ip字符串中删除
。将不会捕获这样的内容:255.*.255.255.+1用于ip2long和数字比较,而不是字符串比较。列表中的第二个ip将破坏您的解决方案:
192.168.2.1.
将变成
192.168.2.10
192.168.2.1255
。虽然第一个不是我们想要的,但第二个是完全非法的IP地址:)不应该
$IP与@Lekensteyn达成一致——很明显,范围是使用
$ip1
$ip2
确定的(顺便说一句,我会将这些变量的名称更改为
$ipStart
$ipEnd
,以便更清楚地说明这一点)。您是否也可以指定每个ip地址的网络掩码?即:
'192.168.100.251/26'
'192.168.100.251'=>26'
(26位掩码甚至可能对给定的IP地址无效,这只是为了举例)如果您可以指定网络掩码,那么计算IP地址有效性就像
If($first\u addr\u of_mask>$IP&$last\u addr\u of_mask<$IP)一样简单。
我不会在PHP中这样做,而是在服务器防火墙上。