我正在使用试图访问我网站的$ _SERVER ['REMOTE_ADDR']获取用户的IP地址。我的数据库中每个框都有不同的IDS和不同的CIDR条目。我想检查用户IP是否存在于任何CIDR中是否存在于特定框中。 如果它存在则允许他进入否则不进入。 假设用户IP是
127.0.0.1
假设框12的CIDR条目是
192.168.1.20/27
192.168.0.10/32
CIDR条目存储在数据库
的列中如果他带有一个属于这个范围的IP,那么他应该被允许进入该网站,否则不允许。 我想针对每个CIDR条目检查他的ip。
有什么想法吗?
由于
答案 0 :(得分:11)
好的,试试这五个简单的步骤......
1. 将您的CIDR存储到数组中(从数据库中读取;猜猜您知道如何获取此数据)
$cidrs = array(
'192.168.1.20/27',
'192.168.0.10/32'
);
2. 获取用户的IP(远程地址)
$user_ip = $_SERVER['REMOTE_ADDR'];
3. 添加此功能
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. 比较用户的IP地址与 $ cidrs
$validaddr = false;
foreach ($cidrs as $addr)
if (IPvsCIDR($user_ip, $addr)) {
$validaddr = true;
break;
}
5. 决定如何处理用户
if ($validaddr) {
echo "CORRECT IP ADDRESS";
}
else {
echo "INCORRECT IP ADDRESS";
}
就是这样!
这个功能如何运作。它将CIDR地址部分(x.x.x.x)转换为二进制字符串并取前N个数字。然后它使用用户的IP执行相同的工作,并检查值是否匹配。
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;
}
$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
}
答案 1 :(得分:3)
我一直在使用这个功能:
<?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;
}
<强>更新强>
实际上,在我的情况下,所有CIDR条目都在数据库中。我怎么能够 检查带有所有TIDR条目的IP,foreach循环是否可以工作?
这取决于您拥有的条目数量。 PHP循环适用于几个范围,但其中有50个意味着启动50个SQL查询!在这种情况下,您应该切换到数据库方法。例如,您可以将范围存储在两列中(较低的IP地址和较高的IP地址)。这样,您需要做的就是:
$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']),
);
(如果需要,可以获取所有匹配项。)
请你解释这行代码
list($str_network, $str_mask) = array_pad(explode('/', $str_range), 2, NULL);
explode('/', $str_range)
// Split the string at `/` characters
array_pad(explode('/', $str_range), 2, NULL);
// Fill with NULLs if we have less than 2 items
list($str_network, $str_mask) =
// Store first part in `$str_network` and second part in `$str_mask`