一、PHP 判断IP信息,相关信息的方法仅供大家参考
1.获取ip协议
2.ip转为数值
3.ipv4子网匹配
4.ipv6前缀匹配
二、调用例子
<?php
var_dump(IpUtils::ipToNumeric("20e1::1:2345:6989:abcd"));//获取ipv6的二进制字符信息
var_dump(IpUtils::ipToNumeric("192.168.8.112"));//获取ipv4的数值信息
var_dump(IpUtils::getSubnetMask("192.168.8.112"));//获取ip协议
var_dump(IpUtils::matchCidrIpv4("192.168.8.112","192.168.8.0/24"));//ipv4子网判断
var_dump(IpUtils::matchCidrIPv6("20e1::1:2345:6989:abcd","20e1:0000:0000:0000:0001:2345:6989:abcd/64"));//ipv6前缀判断通过例子
var_dump(IpUtils::matchCidrIPv6("20e1::1:2345:6989:abcd","20e1:0000:0100:0000:0001:2345:6989:abcd/64"));//ipv6前缀判断不通过例子
三、例如用模拟的数据,返回信息:
string(32) "20e1000000000000000123456989abcd"
string(10) "3232237680"
string(4) "ipv4"
bool(true)
bool(true)
bool(false)
四、调用注意点
matchCidrIpv4与matchCidrIPv6方法的第一个参数一般为客户端ip,第二参数分为两部分用"/"分隔前面是需要匹配的ip,后面的数字表示网络位,ipv4最大32,ipv6最大128。
五、ip工具类实现:
<?php
class IpUtils
{
/**
* 获取ip协议
* @param string $ip IP 地址
*/
public static function getSubnetMask(string $ip) :string
{
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
return "ipv4";
} elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
return "ipv6";
} else {
throw new \InvalidArgumentException("Invalid IP address");
}
}
/**
* 将 IP 地址转换为数值。
* @param string $ip IP 地址
* @return string|false 转换后的数值,失败时返回 false
*/
public static function ipToNumeric(string $ip) :string
{
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
return self::ipv4ToNumeric($ip);
} elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
return self::ipv6ToNumeric($ip);
} else {
throw new \InvalidArgumentException("Invalid IP address");
}
}
/**
* 将 IPv4 地址转换为数值。
*
* @param string $ip IPv4 地址
* @return string 数值
*/
private static function ipv4ToNumeric(string $ip): string
{
return sprintf('%u', ip2long($ip));
}
/**
* 将 IPv6 地址转换为二进制
* @param string $ip IPv6 地址
* @return string 数值
*/
private static function ipv6ToNumeric(string $ip): string
{
$ip = inet_pton($ip);
return bin2hex($ip);
}
/**
* ipv6前缀匹配
* @param string $ip
* @param string $cidr
* @return bool
*/
public static function matchCidrIPv6(string $ip,string $cidr): bool
{
list($matchIp, $prefixLength) = explode('/', $cidr);
$prefixLength = (int) $prefixLength;
if ($prefixLength > 128 || $prefixLength < 1) {
return false;
}
// 将 IPv6 地址转换为二进制格式
$ipBinary = inet_pton($ip);
$networkBinary = inet_pton($matchIp);
$maskBinary = str_repeat("\xFF",intval($prefixLength / 8));
$residue = $prefixLength % 8;
if ($residue) {
$num = 0;
for ($i = 0; $i < 8; $i++) {
$num <<= 1;
if ($residue > $i) {
$num |= 0b1;
}
}
$maskBinary .= pack("C",$num);
}
$maskBinary = str_pad($maskBinary,16,"\x00",STR_PAD_RIGHT);
return strcmp($ipBinary & $maskBinary,$networkBinary & $maskBinary) === 0;
}
/**
* ipv4 子网匹配
* @param $ip
* @param $cidr
* @return bool
*/
public static function matchCidrIpv4($ip, $cidr): bool
{
list($matchIp, $mask) = explode('/', $cidr);
if ($mask > 32 || $mask < 1) {
return false;
}
return (ip2long($ip) >> (32 - $mask) == ip2long($matchIp) >> (32 - $mask));
}
}