Find whether a given IP exists in CIDR or not Find whether a given IP exists in CIDR or not php php

Find whether a given IP exists in CIDR or not


OK, try following this 5 simple steps...

1. Store your CIDRs into array (read 'em from database; guess you know how to get this)

$cidrs = array(  '192.168.1.20/27',   '192.168.0.10/32'  );

2. Get user's IP (remote address)

$user_ip = $_SERVER['REMOTE_ADDR'];

3. Add this function

function IPvsCIDR($user_ip, $cidr) {  $parts = explode('/', $cidr);  $ipc = explode('.', $parts[0]);  foreach ($ipc as &$v)    $v = str_pad(decbin($v), 8, '0', STR_PAD_LEFT);  $ipc = substr(join('', $ipc), 0, $parts[1]);  $ipu = explode('.', $user_ip);  foreach ($ipu as &$v)    $v = str_pad(decbin($v), 8, '0', STR_PAD_LEFT);  $ipu = substr(join('', $ipu), 0, $parts[1]);  return $ipu == $ipc;  }

4. Compare user's IP address against $cidrs

$validaddr = false;foreach ($cidrs as $addr)  if (IPvsCIDR($user_ip, $addr)) {    $validaddr = true;    break;    } 

5. Decide what to do with user

if ($validaddr) {  echo "CORRECT IP ADDRESS";  }else {  echo "INCORRECT IP ADDRESS";  }

That's it!

how this function works. It converts CIDR address-part (x.x.x.x) into binary string and takes first N digits. Then it does same job with user's IP and checks do values match.

Example 2 (complete job from function)

function testUserIP($user_ip, $cidrs) {  $ipu = explode('.', $user_ip);  foreach ($ipu as &$v)    $v = str_pad(decbin($v), 8, '0', STR_PAD_LEFT);  $ipu = join('', $ipu);  $res = false;  foreach ($cidrs as $cidr) {    $parts = explode('/', $cidr);    $ipc = explode('.', $parts[0]);    foreach ($ipc as &$v) $v = str_pad(decbin($v), 8, '0', STR_PAD_LEFT);    $ipc = substr(join('', $ipc), 0, $parts[1]);    $ipux = substr($ipu, 0, $parts[1]);    $res = ($ipc === $ipux);    if ($res) break;    }  return $res;  }

Usage:

$user_ip = $_SERVER['REMOTE_ADDR'];$cidrs = array('192.168.1.20/27', '192.168.0.10/32'); if (testUserIP($user_ip, $cidrs)) {  // user ip is ok  }else {  // access denied  }


I've been using this function for a while:

<?php/** * Returns TRUE if given IPv4 address belongs to given network, FALSE otherwhise * * @param string $str_ip IP address in '127.0.0.1' format * @param string $str_range Network and mask as '127.0.0.0/8', '127.0.0.0/255.0.0.0' or '127.0.0.1' * @return bool * * @version v2011-08-30 */function ip_belongs_to_network($str_ip, $str_range){    // Extract mask    list($str_network, $str_mask) = array_pad(explode('/', $str_range), 2, NULL);    if( is_null($str_mask) ){        // No mask specified: range is a single IP address        $mask = 0xFFFFFFFF;    }elseif( (int)$str_mask==$str_mask ){        // Mask is an integer: it's a bit count        $mask = 0xFFFFFFFF << (32 - (int)$str_mask);    }else{        // Mask is in x.x.x.x format        $mask = ip2long($str_mask);    }    $ip = ip2long($str_ip);    $network = ip2long($str_network);    $lower = $network & $mask;    $upper = $network | (~$mask & 0xFFFFFFFF);    return $ip>=$lower && $ip<=$upper;}

Update:

Actually all the CIDR entries are in database in my case. How can I check an IP with all tose CIDR entries will a foreach loop can work?

It depends on how many entries you have. A PHP loop is fine for a couple of ranges, but having 50 of them would imply launching 50 SQL queries! In that case, you should probably switch to a database approach. E.g., you could store ranges in two columns (lower IP address and upper IP address). That way, all you need to do would be this:

$sql = 'SELECT COUNT(1) AS belongs_to_at_least_one_range    FROM ranges    WHERE :remote_address BETWEEN lower_address AND upper_address    LIMIT 1';$params = array(    'remote_address' => ip2long($_SERVER['REMOTE_ADDR']),);

(Or fetch all matches if you need that.)

can u please explain this line of code list($str_network, $str_mask) = array_pad(explode('/', $str_range), 2, NULL);

explode('/', $str_range)// Split the string at `/` charactersarray_pad(explode('/', $str_range), 2, NULL);// Fill with NULLs if we have less than 2 itemslist($str_network, $str_mask) =// Store first part in `$str_network` and second part in `$str_mask`