calculate IP range using PHP and CIDR

坚强是说给别人听的谎言 提交于 2019-11-30 18:40:51

问题


I've seen various questions and answers around this site and I'm still having difficulty wrapping my head around this problem (could be because I've got a cold). Regardless, I'm trying to come up with a small web app that will create tables of IP addresses for each of our offices.

Like say if I create a new scope for 10.1.10.0/4 it will create an array (which I can then print to a table) of:

 10.1.10.0 network ID
 10.1.10.1 gateway
 10.1.10.2 usable
 10.1.10.3 broadcast

(not that it would insert the descriptions automatically but that's what we'd be doing).

I'm pretty sure I'm going to be using ip2long/long2ip to store the addresses as integers but still.


回答1:


As you've already noted, all IPv4 addresses can be converted to numbers using ip2long(), and converted back using long2ip(). The critical extra bit I'm not sure you've noticed is that sequential IPs correspond with sequential numbers, so you can manipulate these numbers!

Given a CIDR prefix (e.g, $prefix = 30 for your range), you can calculate the number of IPs in that range using a bit shift operator:

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

And then loop through all the IPs in that range using:

$start = ip2long($start_ip);
for ($i = 0; $i < $ip_count; $i++) {
    $ip = long2ip($start + $i);
    // do stuff with $ip...
}



回答2:


I am using the following function to give me the network, 1st usable, last usable and the broadcast address along with all hosts:

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;
}

I also noticed that you are asking to calculate based on a CIDR notation. Here is a function that I am using to convert from CIDR to dotted decimal:

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

I deal mainly dotted decimal and not with CIDR notation. The ipv4Breakout function returns a multidimensional array with all the information that you need via long format. You will need to use long2ip() if you want the actual dotted decimal IP Address. The function requires IP Address and a subnet mask via dotted decimal format.

Hope this helps you or anyone else out.




回答3:


Here is the actual way to calculate a true IP range based on CIDR:

The top answer is actually not correct. It gives the wrong IP range list.

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

Should give me all IPs within 207.64.1.64 and 207.64.1.79

The other answers do not subtract, they only go from 207.64.1.68 - 207.64.1.83 (not correct in the IP range block)

You can check it here: https://www.ipaddressguide.com/cidr




回答4:


My version to help you use variables.

<?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>";
}


来源:https://stackoverflow.com/questions/15961557/calculate-ip-range-using-php-and-cidr

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!