如何在PHP中检查IP范围是否为私有?

时间:2017-08-04 14:47:51

标签: php

我见过的关于在PHP中验证私有IP的大多数问题都与验证特定IP地址是否为私有IP,或者IP是否存在于特定范围内有关。

但是,我希望能够在PHP中确定是否以IP格式给出的IP范围。 “X.X.X.X - Y.Y.Y.Y”是一个专属私人系列。就这么清楚,我想知道整个范围是否是私有的。例子:

10.0.0.1 - 10.0.0.14将返回true,因为此范围内的所有IP都是内部的。

10.0.0.1 - 127.0.0.16将返回false,因为并非所有范围内的IP都是内部/私有的,即使起点和终点是。

我最初的想法只是验证开始和结束IP,如果它们是内部的,那么一切都很好。但是,正如我上面所说,如果我有一个类似$range = '10.0.0.1 - 127.0.0.16'的范围,而起始和结束IP地址都被认为是私有IP地址,它跨越非内部的IP地址,因此它不是一个专门的内部IP地址范围。

我或许可以在该范围内生成每个IP地址,并对每个IP地址进行验证,但这看起来非常低效。

是否有更简单,更有效的方法?

编辑:只是为了让那些标记为重复的人更加明确:我不是要验证单个给定的IP并查看它是否是私有的。我想检查格式为$range = '10.0.0.1 - 127.0.0.16'的给定范围内的每个可能的IP是否为私有。做这样的事情太慢而且效率低下(假设我已经爆炸了字符串以获取起始和结束IP地址):

<?php
function checkRange($start, $end)
{
    $start = ip2long($start);
    $end = ip2long($end);

    for ($i = $start; $i <= $end; $i++) {
        $ip = long2ip($i);
        if (!filter_var(
            $ip,
            FILTER_VALIDATE_IP,
            FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE | FILTER_FLAG_IPV4
        )) {
            continue;
        }
        return false;
    }
    return true;
}

2 个答案:

答案 0 :(得分:3)

IP空间中的所有私有范围均以公开范围分隔(私有p,公共_公开):

__ppp___pppp___ppp___

如果您希望用户定义的范围完全私有,则需要将其完全包含在其中一个私有范围内(u用于用户定义的所有私有范围=命中,x表示错误的范围,失败):

__ppp___pppp___ppp___
   uu
  u
    xxxxxxx
          uu
               u

因此,我们需要检查两个输入值($start$end)是否不仅是私有的,还是在同一个私有范围内。

function checkRange($start, $end)
{
    $start = ip2long($start);
    $end   = ip2long($end);

    if (!$start || !$end)
        throw new Exception('Invalid input.');

    if ($start > $end)
        throw new Exception('Invalid range.'); // Alternative: switch $start and $end

    $range1_start = ip2long('10.0.0.0');
    $range1_end   = ip2long('10.255.255.255');
    $range2_start = ip2long('172.16.0.0');
    $range2_end   = ip2long('172.31.255.255');
    $range3_start = ip2long('192.168.0.0');
    $range3_end   = ip2long('192.168.255.255');

    return ($start >= $range1_start && $start <= $range1_end &&
            $end   >= $range1_start && $end   <= $range1_end) ||
           ($start >= $range2_start && $start <= $range2_end &&
            $end   >= $range2_start && $end   <= $range2_end) ||
           ($start >= $range3_start && $start <= $range3_end &&
            $end   >= $range3_start && $end   <= $range3_end);

}

答案 1 :(得分:0)

IP地址是32位数。它可以表示为由句点分隔的四个小数,每个小数是基数10中32位数的8位。 PHP的内置http://wiki.fasterxml.com/JacksonJsonViews从IPv4 字符串表示法转换为标准的32位整数。

考虑到这一点(IPv4字符串表示法字符串只是32位整数),您可以轻松地提出一种算法,检查整数是否在某个范围内,或者范围是否在另一个范围内。

<?php

function check($start, $end) {
    $r10Start = ip2long('10.0.0.0');
    $r10End = ip2long('10.255.255.255');

    $r127Start = ip2long('127.0.0.0');
    $r127End = ip2long('127.255.255.255');

    if (
        ($start >= $r10Start && $end <= $r10End)
        || ($start >= $r127Start && $end <= $r127End)
    ) {
        return true;
    }

    return false;
}

var_dump(check(ip2long('10.0.0.1'), ip2long('10.0.0.14')));
var_dump(check(ip2long('10.0.0.1'), ip2long('127.0.0.16')));