How to check IP address within two IP addresses in PHP?

I have an IP address and I have been given two other IP addresses that together create an IP range. I want to check if the first IP address is in this range. How can I find this in PHP?

+42
php range ip
Jun 20 2018-12-12T00:
source share
7 answers

With ip2long() it is easy to convert your addresses to numbers. After that, you just need to check if the number is in the range:

 if ($ip <= $high_ip && $low_ip <= $ip) { echo "in range"; } 
+53
Jun 20 2018-12-12T00:
source share

This site offers an excellent guide and code for this (this was the first Google search result on this):

 <?php /* * ip_in_range.php - Function to determine if an IP is located in a * specific range as specified via several alternative * formats. * * Network ranges can be specified as: * 1. Wildcard format: 1.2.3.* * 2. CIDR format: 1.2.3/24 OR 1.2.3.4/255.255.255.0 * 3. Start-End IP format: 1.2.3.0-1.2.3.255 * * Return value BOOLEAN : ip_in_range($ip, $range); * * Copyright 2008: Paul Gregg <pgregg@pgregg.com> * 10 January 2008 * Version: 1.2 * * Source website: http://www.pgregg.com/projects/php/ip_in_range/ * Version 1.2 * * This software is Donationware - if you feel you have benefited from * the use of this tool then please consider a donation. The value of * which is entirely left up to your discretion. * http://www.pgregg.com/donate/ * * Please do not remove this header, or source attibution from this file. */ // decbin32 // In order to simplify working with IP addresses (in binary) and their // netmasks, it is easier to ensure that the binary strings are padded // with zeros out to 32 characters - IP addresses are 32 bit numbers Function decbin32 ($dec) { return str_pad(decbin($dec), 32, '0', STR_PAD_LEFT); } // ip_in_range // This function takes 2 arguments, an IP address and a "range" in several // different formats. // Network ranges can be specified as: // 1. Wildcard format: 1.2.3.* // 2. CIDR format: 1.2.3/24 OR 1.2.3.4/255.255.255.0 // 3. Start-End IP format: 1.2.3.0-1.2.3.255 // The function will return true if the supplied IP is within the range. // Note little validation is done on the range inputs - it expects you to // use one of the above 3 formats. Function ip_in_range($ip, $range) { if (strpos($range, '/') !== false) { // $range is in IP/NETMASK format list($range, $netmask) = explode('/', $range, 2); if (strpos($netmask, '.') !== false) { // $netmask is a 255.255.0.0 format $netmask = str_replace('*', '0', $netmask); $netmask_dec = ip2long($netmask); return ( (ip2long($ip) & $netmask_dec) == (ip2long($range) & $netmask_dec) ); } else { // $netmask is a CIDR size block // fix the range argument $x = explode('.', $range); while(count($x)<4) $x[] = '0'; list($a,$b,$c,$d) = $x; $range = sprintf("%u.%u.%u.%u", empty($a)?'0':$a, empty($b)?'0':$b,empty($c)?'0':$c,empty($d)?'0':$d); $range_dec = ip2long($range); $ip_dec = ip2long($ip); # Strategy 1 - Create the netmask with 'netmask' 1s and then fill it to 32 with 0s #$netmask_dec = bindec(str_pad('', $netmask, '1') . str_pad('', 32-$netmask, '0')); # Strategy 2 - Use math to create it $wildcard_dec = pow(2, (32-$netmask)) - 1; $netmask_dec = ~ $wildcard_dec; return (($ip_dec & $netmask_dec) == ($range_dec & $netmask_dec)); } } else { // range might be 255.255.*.* or 1.2.3.0-1.2.3.255 if (strpos($range, '*') !==false) { // ab*.* format // Just convert to AB format by setting * to 0 for A and 255 for B $lower = str_replace('*', '0', $range); $upper = str_replace('*', '255', $range); $range = "$lower-$upper"; } if (strpos($range, '-')!==false) { // AB format list($lower, $upper) = explode('-', $range, 2); $lower_dec = (float)sprintf("%u",ip2long($lower)); $upper_dec = (float)sprintf("%u",ip2long($upper)); $ip_dec = (float)sprintf("%u",ip2long($ip)); return ( ($ip_dec>=$lower_dec) && ($ip_dec<=$upper_dec) ); } echo 'Range argument is not in 1.2.3.4/24 or 1.2.3.4/255.255.255.0 format'; return false; } } ?> 
+28
Jun 20 2018-12-12T00:
source share

I found this little gist which has a simpler / shorter solution than already mentioned here.

The second argument (range) can be either a static ip, for example 127.0.0.1, or a range of 127.0.0.0/24.

 /** * Check if a given ip is in a network * @param string $ip IP to check in IPV4 format eg. 127.0.0.1 * @param string $range IP/CIDR netmask eg. 127.0.0.0/24, also 127.0.0.1 is accepted and /32 assumed * @return boolean true if the ip is in this range / false if not. */ function ip_in_range( $ip, $range ) { if ( strpos( $range, '/' ) == false ) { $range .= '/32'; } // $range is in IP/CIDR format eg 127.0.0.1/24 list( $range, $netmask ) = explode( '/', $range, 2 ); $range_decimal = ip2long( $range ); $ip_decimal = ip2long( $ip ); $wildcard_decimal = pow( 2, ( 32 - $netmask ) ) - 1; $netmask_decimal = ~ $wildcard_decimal; return ( ( $ip_decimal & $netmask_decimal ) == ( $range_decimal & $netmask_decimal ) ); } 
+9
Sep 27 '14 at 6:27
source share

I always suggested ip2long , but sometimes you need to check networks, etc. In the past, I built an IPv4 class network, which can be found here on HighOnPHP .

The best part about working with IP addressing is flexibility, especially when using BITWISE statements. AND'ing, OR'ing and BitShifting will work like a charm.

+2
Jun 20 '12 at 14:40
source share
 if(version_compare($low_ip, $ip) + version_compare($ip, $high_ip) === -2) { echo "in range"; } 
+1
23 Oct '15 at 12:38
source share

Btw, if you need to check several ranges at once, you can add several lines to the code to pass an array of ranges. The second argument can be an array or a string:

 public static function ip_in_range($ip, $range) { if (is_array($range)) { foreach ($range as $r) { return self::ip_in_range($ip, $r); } } else { if ($ip === $range) { // in case you have passed a static IP, not a range return TRUE; } } // The rest of the code follows here.. // ......... } 
0
Oct 17 '14 at 14:18
source share

Range Comparison (including IPv6 support)

In PHP 5.1.0, inet_pton and inet_pton following two functions were introduced. Their goal is to translate human readable IP addresses into their packed in_addr representation. Since the result is not pure binary, we need to use the unpack function to apply bitwise operators.

Both features support IPv6 as well as IPv4. The only difference is how you unpack the address from the results. With IPv6, you unzip the contents using A16, and with IPv4 you unzip the A4.

To put the previous one in perspective, here is a small example of the output to help clarify:

 // Our Example IP's $ip4= "10.22.99.129"; $ip6= "fe80:1:2:3:a:bad:1dea:dad"; // ip2long examples var_dump( ip2long($ip4) ); // int(169239425) var_dump( ip2long($ip6) ); // bool(false) // inet_pton examples var_dump( inet_pton( $ip4 ) ); // string(4) var_dump( inet_pton( $ip6 ) ); // string(16) 

We demonstrate above that the inet_ * family supports both IPv6 and v4. The next step is to translate the packaged result into an unpacked variable.

 // Unpacking and Packing $_u4 = current( unpack( "A4", inet_pton( $ip4 ) ) ); var_dump( inet_ntop( pack( "A4", $_u4 ) ) ); // string(12) "10.22.99.129" $_u6 = current( unpack( "A16", inet_pton( $ip6 ) ) ); var_dump( inet_ntop( pack( "A16", $_u6 ) ) ); //string(25) "fe80:1:2:3:a:bad:1dea:dad" 

Note. The current function returns the first index of the array. This is equivalent to the statement $ array [0].

After unpacking and packaging, we see that we have achieved the same result as the entrance. This is a simple proof of concept to ensure that we do not lose any data.

Finally use

 if ($ip <= $high_ip && $low_ip <= $ip) { echo "in range"; } 

Link: php.net

-one
Dec 28 '15 at 20:30
source share



All Articles