php判断ip段,PHP中判断IP是否在某个给定的IP段中

这篇博客介绍了如何在PHP中实现判断一个IP地址是否落在指定的IP段内的功能,通过转换IP地址为二进制并进行位运算来确定。文章详细解释了各个辅助函数的作用,包括检查IP合法性、生成掩码二进制串、获取网络地址和广播地址,最后使用bccomp函数进行精确比较。示例代码展示了如何判断IP是否在多个给定IP段的列表中。
摘要由CSDN通过智能技术生成

PHP中判断IP是否在某个给定的IP段中

在Linux中,可以往iptables防火墙中添加规则,如-A INPUT -s 180.76.5.0/24 -j

DROP,这样客户端的IP如果落在180.76.5.0/24这个段中,那么这个IP过来的数据包将被丢弃,这里iptables帮我们判断了IP是否落在某给定的IP段中,但是在PHP中如何实现这个判断呢?

解决方案,可以从IP段中读出段的网络地址和广播地址,然后再把它们转换成数字,判断访问者IP的数字值是否落在其中,如果在,则说明在这个段中,否则就不在这个段中。

思路看起来很简单,不过实现过程就要非常小心。

//把客户端访问IP转换成数字,使用ip2long()函数

$ip = "202.105.77.179";

//这个输出在32位系统下是负值,原因是ip2long()回返回PHP的整型数,而PHP的整型是带符号的,数得简单点就是整型用32位,但是第32位是符号位,0表示正,1表示负,这样正负最大能到达的是2^31。而这里的IP转换成整型数时,它超过了PHP整型数能表示的范围,叫做溢出。

$ip_long = ip2long($ip);

//虽然转换成整数时产生了溢出,但是并不影响转换成二进制的正确性,返回一个二进制串,注意这个函数并没有假定它一定返回二进制串的长度

$ip_bin = decbin($ip_long);

//这个时候再从二进制转换成十进制,使用bindec()函数,这个函数返回的数字串是不受符号位影响的,就是通过这样的转换获得了正确的数字串

$ip_dec = bindec($ip_bin);

接下来需要一些函数:

//判断是否是合法IP

function isIp($str) {

$ip = explode(".", $str);

if (count($ip) < 4 || count($ip) > 4) return

FALSE;

foreach($ip as $ip_addr) {

if ( !is_numeric($ip_addr) ) return FALSE;

if ( $ip_addr < 0 || $ip_addr > 255 ) return

FALSE;

}

return

(preg_match("/^([0-9]{1,3}\.){3}[0-9]{1,3}$/is", $str));

}

//根据给出的数字生成二进制掩码串

function mask2bin($n){

$n = intval($n);

if($n < 0 || $n > 32) return

FALSE;

return str_repeat( "1",$n).str_repeat(

"0",32-$n);

}

//反转掩码串

function revBin($s)  {

$p = array('0','1','2');

$r = array('2','0','1');

return

str_replace($p,$r,$s);

}

//根据IP和掩码得到网络地址 十进制

function getSubnet($ip, $mask){

//这里的按为运算务必要保证长度一致,都是32位

$bin_ip =

str_pad(decbin(ip2long($ip)),32,'0',STR_PAD_LEFT);

$msk = mask2bin($mask);

return bindec($bin_ip & $msk);

}

//根据IP和掩码得到广播地址 十进制

function getBroadcast($ip, $mask){

$bin_ip =

str_pad(decbin(ip2long($ip)),32,'0',STR_PAD_LEFT);

$msk = mask2bin($mask);

return bindec($bin_ip | revBin($msk));

}

以上的函数getSubnet() 和

getBroadcast()可以获得网络地址和广播地址,返回的是十进制的数字串(不是整型数),这个数字串可能已经超过了PHP整型能表示的范围,所以,如果要判断$ip_dec是否落在它们之间,绝对不能转换成整型然后比较。必须得使用bccomp()函数,这个函数前两个是操作数,第三参数表示精度,如果第一操作数大于第二操作数,返回整型数1,否则返回-1,如果相等返回0。

以下为判断$ip_dec是否落在给定段的代码:

$passlist[] = "192.168.0.0/16";

$passlist[]= "10.0.0.1/8";

$passlist[]= "8.8.8.8";

$ip = $ip_dec;

function inTheList($passlist,$ip){

foreach ($passlist as $pass){

//$dec_ip = bindec(decbin(ip2long($ip)));

$dec_ip = $ip;

$tm = explode("/",$pass);

if(count($tm) > 1){

// 合法IP 和 掩码数

if(isIp($tm[0]) === FALSE){ continue; }

if( ((int)$tm[1] < 1) || ((int)$tm[1] > 32)){ continue;

}

$dec_from = getSubnet($tm[0],(int)$tm[1]);

$dec_end = getBroadcast($tm[0],(int)$tm[1]);

// 在段中

if( (bccomp($dec_ip,$dec_from) == 1) &&

(bccomp($dec_ip,$dec_end) == -1) ){

return TRUE;

break;

}

}else if(trim($ip) ==

bindec(decbin(ip2long(trim($pass))))){

return TRUE;

break;

}

}

return FALSE;

}

if(inTheList($passlist,$ip)){

echo "The ip -> $ip is in the list.";

}else{

echo "The ip -> $ip is not in the

list.";

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值