2

I am trying to figure out what the best/most efficient way to get individual /24 IP blocks from a range of IP addresses using PHP.

I have ranges of IP addresses in an MySQL database (I cannot change how this is presented) and have to have individual ranges of /24 blocks saved, also in a specific way (I cannot change the MySQL entries, nor how the software processes the list).

For example, I have various ranges of IPv4 IP addresses in this format:

86.111.160.0 - 86.111.175.255

Which I need to save in this specific format to represent each /24 block in the range of given addresses:

86.111.160.0
86.111.161.0
86.111.162.0
...
86.111.175.0

I'm having a bit of a block on how to do this without writing something hugely complicated to process each line.

Is there any function in PHP that can help me with this?

Thanks in advance.

omega1
  • 1,031
  • 4
  • 21
  • 41
  • Does this answer your question? [Get all IP addresses in a range in PHP](https://stackoverflow.com/questions/32720629/get-all-ip-addresses-in-a-range-in-php) – Nico Haase Dec 10 '21 at 10:58
  • Or this? https://stackoverflow.com/questions/4931721/getting-list-ips-from-cidr-notation-in-php – Nico Haase Dec 10 '21 at 10:58
  • It is worth bearing in mind you should probably be looking at building this with IPv6 not IPv4 which is reaching (if not already) end of life – Martin Dec 10 '21 at 11:02

2 Answers2

2

Here is the example off of https://www.php.net/manual/en/ref.network.php#74656

A simple and very fast function to check against CIDR.

This example takes into account your range parameter

Here it is (only with arithmetic operators and call only to ip2long () and split() ):

<?php


function ipCIDRCheck ($IP, $CIDR) {
    list ($net, $mask) = explode("/", $CIDR);
   
    $ip_net = ip2long ($net);
    $ip_mask = ~((1 << (32 - $mask)) - 1);

    $ip_ip = ip2long ($IP);

    $ip_ip_net = $ip_ip & $ip_mask;

    return long2ip($ip_ip_net);
  }

  $range = "86.111.160.0 - 86.111.175.255";
  list($lower,$upper) = explode('-',$range);
  $lowerIp = ip2long(trim($lower));
  $upperIp = ip2long(trim($upper));

  while($lowerIp <= $upperIp){
    echo ipCIDRCheck(long2ip($lowerIp),long2ip($lowerIp) .'/24') . "\n\r";
    $lowerIp += 255;
  }

Jordan Casey
  • 955
  • 9
  • 16
  • 1
    It shouldn't be an issue in 2021, but please be aware that bit manipulation on IPv4 addresses only works reliably in 64-bit PHP distributions. – Álvaro González Dec 10 '21 at 10:45
  • Thanks, but I am not able to modify how the ranges are presented to me so I'd have to first convert them back into a CIDR format to use this. – omega1 Dec 10 '21 at 11:17
  • 1
    @omega1 I've updated the code to accept your range parameter and return your mask. Change the range to what you prefer – Jordan Casey Dec 10 '21 at 12:34
2

There is this library you could use: https://github.com/S1lentium/IPTools

Looks like this is similar to what you're after. There are many other methods within this library for you to use.

Iterate over Network IP adresses:

$network = Network::parse('192.168.1.0/24');
foreach($network as $ip) {
    echo (string)$ip . '<br>';
}

// Output
192.168.1.0
...
192.168.1.255

Iterate over Range IP adresses:

$range = Range::parse('192.168.1.1-192.168.1.254');
foreach($range as $ip) {
    echo (string)$ip . '<br>';
}

// Output
192.168.1.1
...
192.168.1.254
Bossman
  • 1,416
  • 1
  • 11
  • 17
  • Thanks, I'll take a look at that library, but I do not need individual IP addresses from a range, I need to specifically save each /24 block in the range as per the OP. – omega1 Dec 10 '21 at 11:20