'Merge IP Ranges with PHP
I am stuck at a point and cant think beyond it :
I have a list of Ip ranges, I need to merge them making them as a range. For example
192.168.1.1
192.168.1.2
192.168.1.3
192.168.1.5
192.168.1.6
I need to club them into IP ranges. For this case it will be 192.168.1.1-192.168.1.3 and 192.168.1.5-192.168.1.6
I was thinking of converting these into integer by using ip2long function and sorting it. But can't think beyond that.
Any help would be appreciated.
Thanks In advance :)
Solution 1:[1]
Here is my answer :
$ip_list = array('192.168.1.1', '192.168.1.2', '192.168.1.3', '192.168.1.5', '192.168.1.6');
$ip_long_list = array();
foreach($ip_list as $ip) {
$ip_long_list[] = ip2long($ip);
}
unset($ip_list); // no longer in use
sort($ip_long_list); // sort it
$result = array();
$cnt_group = 0;
for($i = 0; $i < count($ip_long_list)-1; $i++) {
if($i == 0) {
$result[$cnt_group] = array($ip_long_list[0]); // initialize 1st group
continue;
}
if(abs($ip_long_list[$i] - $ip_long_list[$i+1]) == 1) {
// they are in series, group it.
$tmp_array = $result[$cnt_group]; // get back the array
$tmp_array[] = $ip_long_list[$i]; // push item into array
$result[$cnt_group] = $tmp_array;
unset($tmp_array); // remove to save memory
} else {
// they are separate. next group.
$cnt_group++;
$result[$cnt_group] = array($ip_long_list[1]);
}
}
After all the above, convert back to IP from Long.
foreach($result as $ip_long_group) {
$first_ip = long2ip($ip_long_group[0]);
$last_ip = long2ip($ip_long_group[count($ip_long_group)-1];
$common_parts = longest_common_substring(array($first_ip, $last_ip));
echo $common_parts . str_replace($common_parts, '', $first_ip) . '-' . str_replace($common_parts, '', $last_ip) . PHP_EOL;
}
Note: I used a 3rd party function (listed in Reference) to get the common parts of 2 strings.
Reference: longest_common_substring()
Solution 2:[2]
Manual method to get range (without using ip2long):
<?php
$ip_addressess=array(
'192.168.1.1', '192.168.1.2', '192.168.1.3', '192.168.1.5', '192.168.1.6', '192.168.1.7', '192.168.1.9', '192.168.1.10', '192.168.1.11', '192.168.1.15', '192.168.1.16', '192.168.1.17');
foreach($ip_addressess as $ip_address){
$break_ip[] = explode('.', $ip_address); //break ip address
}
foreach($break_ip as $break){
$numbers[] = $break[3]; //get last number of ip address
}
$commaList_ipaddress = implode(',', $numbers); //generate comma separated list of last digits of ip address
$missing = array();
$a =0 ;
for ($i = 1; $i <= max($numbers); $i++) {
if (!in_array($i, $numbers))
{
$missing[] = $i;
$a++;
} else{
$new_ip_ranges[$a][] = $i;
}
}
$new_ip_ranges = array_values($new_ip_ranges); //rearrange the array
foreach($new_ip_ranges as $new_range){
$min = min($new_range);
$max = max($new_range);
$min_range = $break_ip[0][0].'.'.$break_ip[0][1].'.'.$break_ip[0][2].'.'.$min;
$max_range = $break_ip[0][0].'.'.$break_ip[0][1].'.'.$break_ip[0][2].'.'.$max;
$range[] = $min_range .'-'.$max_range;
}
echo '<pre>';
print_r($range);
?>
Output:
Array
(
[0] => 192.168.2.1-192.168.2.3
[1] => 192.168.2.5-192.168.2.7
[2] => 192.168.2.9-192.168.2.11
[3] => 192.168.2.15-192.168.2.17
)
Demo at CodeFiddle>>
Solution 3:[3]
function printCombinedIPs($ip_arr) {
//$ip_arr = array('192.168.1.5','192.168.1.6');
$k = NULL;
$prev = -1;
foreach ( $ip_arr as $ip ) {
$octet = explode(".",$ip);
$fourth = $octet[3];
$net = $octet[0].".".$octet[1].".".$octet[2];
if ( $fourth < $prev ) {
$prev = -1;
}
$end = $fourth;
if ( $fourth - 1 != $prev ) {
$start = $fourth;
$rtn_arr[] = $k;
}
if ( $start == $end )
$k = $net.".$end";
else
$k = $net.".$start-$end";
$prev = $octet[3];
}
$rtn_arr[] = $k;
array_shift($rtn_arr);
return implode(", ", $rtn_arr);
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Vijaya Pandey |
| Solution 3 | Ivaylo M. Ivanov |
