3

我在这个网站上看到了各种各样的问题和答案,但我仍然很难解决这个问题(可能是因为我感冒了)。无论如何,我正在尝试开发一个小型 Web 应用程序,该应用程序将为我们的每个办公室创建 IP 地址表。

比如说如果我为 10.1.10.0/4 创建一个新范围,它将创建一个数组(然后我可以将其打印到一个表中):

 10.1.10.0 network ID
 10.1.10.1 gateway
 10.1.10.2 usable
 10.1.10.3 broadcast

(并不是说它会自动插入描述,但这就是我们要做的)。

我很确定我将使用 ip2long/long2ip 将地址存储为整数,但仍然如此。

4

5 回答 5

12

正如您已经注意到的,所有 IPv4 地址都可以使用 转换为数字ip2long(),然后使用long2ip(). 我不确定您是否注意到关键的额外信息是顺序 IP 对应于顺序编号,因此您可以操纵这些数字!

给定一个 CIDR 前缀(例如,对于您的范围),您可以使用位移运算符$prefix = 30计算该范围内的 IP 数量:

$ip_count = 1 << (32 - $prefix);

然后使用以下命令遍历该范围内的所有 IP:

$start = ip2long($start_ip);
for ($i = 0; $i < $ip_count; $i++) {
    $ip = long2ip($start + $i);
    // do stuff with $ip...
}
于 2013-04-16T20:29:24.993 回答
10

以下是基于 CIDR 计算真实 IP 范围的实际方法:

最佳答案实际上是不正确的。它给出了错误的 IP 范围列表。

function ipRange($cidr) {
   $range = array();
   $cidr = explode('/', $cidr);
   $range[0] = long2ip((ip2long($cidr[0])) & ((-1 << (32 - (int)$cidr[1]))));
   $range[1] = long2ip((ip2long($range[0])) + pow(2, (32 - (int)$cidr[1])) - 1);
   return $range;
}

 var_dump(ipRange("207.64.1.68/28"));

 //////////////////OUTPUT////////////////////////
 // array(2) {
 //   [0]=>
 //   string(12) "207.64.1.64"
 //   [1]=>
 //   string(12) "207.64.1.79"
 // }
 /////////////////////////////////////////////////

IP:207.64.1.68

应该给我 207.64.1.64 和 207.64.1.79 内的所有 IP

其他答案不减去,它们仅来自 207.64.1.68 - 207.64.1.83(在 IP 范围块中不正确)

你可以在这里查看:https ://www.ipaddressguide.com/cidr

于 2019-03-18T20:01:45.567 回答
4

我正在使用以下功能为我提供网络、第一个可用、最后一个可用和广播地址以及所有主机:

function ipv4Breakout ($ip_address, $ip_nmask) {
    $hosts = array();
    //convert ip addresses to long form
    $ip_address_long = ip2long($ip_address);
    $ip_nmask_long = ip2long($ip_nmask);

    //caculate network address
    $ip_net = $ip_address_long & $ip_nmask_long;

    //caculate first usable address
    $ip_host_first = ((~$ip_nmask_long) & $ip_address_long);
    $ip_first = ($ip_address_long ^ $ip_host_first) + 1;

    //caculate last usable address
    $ip_broadcast_invert = ~$ip_nmask_long;
    $ip_last = ($ip_address_long | $ip_broadcast_invert) - 1;

    //caculate broadcast address
    $ip_broadcast = $ip_address_long | $ip_broadcast_invert;

    foreach (range($ip_first, $ip_last) as $ip) {
            array_push($hosts, $ip);
    }

    $block_info = array(array("network" => "$ip_net"),
            array("first_host" => "$ip_first"),
            array("last_host" => "$ip_last"),
            array("broadcast" => "$ip_broadcast"),
            $hosts);

    return $block_info;
}

我还注意到您要求根据 CIDR 表示法进行计算。这是我用来从 CIDR 转换为点分十进制的函数:

function v4CIDRtoMask($cidr) {
    $cidr = explode('/', $cidr);
    return array($cidr[0], long2ip(-1 << (32 - (int)$cidr[1])));
}

我主要处理点分十进制而不是 CIDR 表示法。ipv4Breakout 函数通过长格式返回一个包含您需要的所有信息的多维数组。如果您想要实际的点分十进制 IP 地址,则需要使用 long2ip()。该函数需要点分十进制格式的 IP 地址和子网掩码。

希望这可以帮助您或其他任何人。

于 2013-11-18T20:30:58.670 回答
2

我的版本可以帮助您使用变量。

<?php
$ip_address = "192.168.0.2";
$ip_nmask = "255.255.255.0";
ipv4Breakout($ip_address, $ip_nmask);

function ipv4Breakout ($ip_address, $ip_nmask) {
    //convert ip addresses to long form
    $ip_address_long = ip2long($ip_address);
    $ip_nmask_long = ip2long($ip_nmask);
    //caculate network address
    $ip_net = $ip_address_long & $ip_nmask_long;
    //caculate first usable address
    $ip_host_first = ((~$ip_nmask_long) & $ip_address_long);
    $ip_first = ($ip_address_long ^ $ip_host_first) + 1;
    //caculate last usable address
    $ip_broadcast_invert = ~$ip_nmask_long;
    $ip_last = ($ip_address_long | $ip_broadcast_invert) - 1;
    //caculate broadcast address
    $ip_broadcast = $ip_address_long | $ip_broadcast_invert;

    //Output
    $ip_net_short = long2ip($ip_net);
    $ip_first_short = long2ip($ip_first);
    $ip_last_short = long2ip($ip_last);
    $ip_broadcast_short = long2ip($ip_broadcast);
    echo "Network - " . $ip_net_short . "<br>";
    echo "First usable - " . $ip_first_short . "<br>";
    echo "Last usable - " . $ip_last_short . "<br>";
    echo "Broadcast - " . $ip_broadcast_short . "<br>";
}
于 2015-12-12T00:10:07.420 回答
0

我创建了这个 php 函数以获取网络/范围的子网拆分。它适用于 ipv4 或 ipv6。
如果 php<5.4 然后使用这个 hex2bin 函数https://github.com/dompdf/dompdf/issues/1692

function divide_ip_range($cidr="2001:db8:abc:12ff::/54",$mindivs=2){ // input range 192.168.4.0/24 and returns array with the 1st range and 2nd range [0] => 192.168.4.0/25 , [1] => 192.168.4.127/25
  $outarr=array();
  list($ipaddr,$range) = explode('/', $cidr);
  for($rngsplit=1;pow(2,$rngsplit)<$mindivs;$rngsplit++){} // find to how many networks to divide
  $divs=pow(2,$rngsplit);    
  $divcidr=(int)$range+$rngsplit;
  if(preg_match("/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/",$ipaddr)){ // IPv4
    $ip_address_long = ip2long($ipaddr);
    $ip_nmask_long=(-1 << (32 - $range));
    $ip_net = $ip_address_long & $ip_nmask_long;
    $ip_broadcast_invert = ~$ip_nmask_long;
    $ip_last = ($ip_address_long | $ip_broadcast_invert) - 1;
    $ip_broadcast = $ip_address_long | $ip_broadcast_invert;
    $numofhosts=pow(2,32-$range)-2;
    for ($i=0;$i<$divs;$i++){
      $outarr[]=long2ip($ip_net+$i*ceil($numofhosts/$divs)+($i*ceil($numofhosts/$divs)%2) )."/$divcidr";
    }
    //echo "Net:$ipaddr/$range\nFirst:".long2ip($ip_net)."\nLast: ".long2ip($ip_last)."\nNumOfHosts:$numofhosts \n";
  } else if (preg_match("/^[0-9a-f:]+$/",$ipaddr)) { // IPv6 section 
    $ip_addr_bin = inet_pton($ipaddr);
    $ip_addr_hex = bin2hex($ip_addr_bin);
    $flexbits = 128 - $range; // Calculate the number of 'flexible' bits for first net
    $pos = 31; $addr_hex_first = $ip_addr_hex; $addr_hex_last = $ip_addr_hex;
    while ($flexbits > 0) {
      $orig_val = hexdec(substr($ip_addr_hex, $pos, 1)); // dec value of pos char. ex. f=15
      $mask = 0xf << (min(4,$flexbits)); // calculate the subnet mask. min() prevents comparison to be negative 
      $new_val_first = $orig_val & $mask;
      $addr_hex_first = substr_replace($addr_hex_first, dechex($new_val_first) , $pos, 1); // Put hex character in pos
      $segmask=(pow(2,min(4,$flexbits))-1); // Last address: OR it with (2^flexbits)-1, with flexbits limited to 4 at a time
      $new_val_last = $orig_val | $segmask;
      $addr_hex_last = substr_replace($addr_hex_last, dechex($new_val_last) , $pos, 1);
      $pos--; $flexbits -= 4; // Next nibble
    }
    $partpos=(4*floor($pos/4)); // The 4 digits that vary by the subnetting
    $partfirst=substr($addr_hex_first,$partpos,4);
    $partlast=substr($addr_hex_last,$partpos,4);
    $numofhosts=(hexdec($partlast)+1-hexdec($partfirst));
    for ($i=0;$i<$divs;$i++){
      $partdiv=dechex(hexdec($partfirst)+$i*$numofhosts/$divs);
      $addr_hex_div=substr_replace($addr_hex_first, $partdiv , $partpos, 4);
      $outarr[]=inet_ntop(hex2bin($addr_hex_div))."/$divcidr";
    }  
    //echo "Net:$ipaddr/$range\nFirst:".inet_ntop(hex2bin($addr_hex_first))."\nLast:".inet_ntop(hex2bin($addr_hex_last))."\nNumOfHosts:$numofhosts\nDivide at partpos:$partpos ($partlast+1-$partfirst)/$divs=$partdiv\n";
  }
  return $outarr;
}
于 2020-05-24T14:38:27.247 回答