昨天正好需要用到IP地址操作的一些函数,就找到了一个比较全的类,支持IPv6地址,当然,这个不能不考虑,为了以后着想嘛。
原本这是IPv6的,我稍作修改把ipv4需要的一些东西添加了进来,然后就行了。顺便整理了一下。
<?php
/* PHP-IPv6&4 V1.1.
* Copyright (c) 2010 Mr.Bin <bin_jly@163.com>
*/
/**
* IP地址操作控制类
* Class Ip
*/
class Ip
{
/**
* 获取服务器变量中的客户IP地址
* @return string
*/
public function addr() {
return $_SERVER['REMOTE_ADDR'];
}
/**
* 获取单一客户端IP地址
* @return string
*/
public function realip() {
/* 穿过代理获取真实IP地址
* 返回值为数组,array[0]为真实IP,array[1]为代理IP(可能为空)
* 若array[0]和array[1]相等,则实际真实IP可能无法获取(高度匿名?)
*/
$is_proxy = false;
$ip = "0.0.0.0";
if($_SERVER['HTTP_X_FORWARDED_FOR']) {
$is_proxy = true;
$ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach($ips as $ip) {
if(!self::wan_ip($ip)) {
$ip = false;
} else {
break;
}
}
}
if(!$ip && $_SERVER['HTTP_CLIENT_IP']) {
$is_proxy = true;
$ip = $_SERVER['HTTP_CLIENT_IP'];
if(!self::wan_ip($ip)) {
$ip = false;
}
}
$proxy = '';
if($is_proxy) {
$proxy = $_SERVER['REMOTE_ADDR'];
if(!$ip) {
$ip = $proxy;
}
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
return explode(',', $ip . ',' . $proxy)[0];
}
/**
* 压缩IPv6地址
* @param $addr
* @return mixed|string
*/
public function cut($addr) {
// 压缩IPv6地址
if(!self::ipv6_check($addr)) {
return $addr;
}
$addr = self::fill($addr);
$arr = explode(':', $addr);
$arr2 = [];
foreach($arr as $a) {
$arr2[] = preg_replace('/^0{1,3}(\w+)/', '\1', $a);
}
$addr = join(':', $arr2);
$olen = strlen($addr);
for($i = 6; $i > 0; $i--) {
// 初步压缩
$addr = preg_replace('/:(0\:){' . $i . '}/', '::', $addr, 1);
if(strlen($addr) < $olen) {
break;
}
}
$addr = preg_replace('/^0\:\:/', '::', $addr);
$addr = preg_replace('/\:\:0$/', '::', $addr);
return $addr;
}
/**
* 将地址转换为标准IPv6地址
* @param $addr
* @return mixed|string
*/
public function fill($addr) {
// 标准IPv6格式
if(!self::ipv6_check($addr)) {
return $addr;
}
$addr = self::_fix_v4($addr);
$arr = explode(':', $addr);
$arr2 = [];
foreach($arr as $a) {
$l = strlen($a);
if($l > 0 && $l < 4) {
$arr2[] = str_repeat('0', 4 - $l) . $a;
} else {
$arr2[] = $a;
}
}
$addr = join(':', $arr2);
$fil = ':' . str_repeat('0000:', 9 - count($arr));
$addr = str_replace('::', $fil, $addr);
$addr = preg_replace('/^\:/', '0000:', $addr);
$addr = preg_replace('/\:$/', ':0000', $addr);
return $addr;
}
/**
* ip转换为128位二进制地址
* @param $addr
* @return bool|string
*/
public function ip2bin($addr) {
$type = self::type($addr);
if($type === 0) {
return false;
} elseif($type === 4) {
$addr = self::ip426($addr);
} else {
$addr = self::fill($addr);
}
$hexstr = str_replace(':', '', $addr);
return pack('H*', $hexstr);
}
/**
* ipv6二进制转为为非压缩型地址
* @param $bin
* @return bool|string
*/
public function bin2ip6($bin) {
if(strlen($bin) !== 16) {
return false;
}
$arr = str_split(join('', unpack('H*', $bin)), 4);
$addr = join(':', $arr);
return $addr;
}
/**
* ipv4二进制转换为字符型
* @param $bin string 必须为16个字符或者4个字符
* @return bool|string
*/
public function bin2ipv4($bin) {
$len = strlen($bin);
if($len !== 16 && $len !== 4) {
return false;
}
if($len === 16) {
$bin = substr($bin, 12);
}
$arr = str_split(join('', unpack('H*', $bin)), 2);
$arr[0] = hexdec($arr[0]);
$arr[1] = hexdec($arr[1]);
$arr[2] = hexdec($arr[2]);
$arr[3] = hexdec($arr[3]);
$addr = join('.', $arr);
return $addr;
}
/**
* IPv4转换为IPv6地址
* @param $addr
* @return string
*/
public function ip426($addr) {
// IPv4 to IPv6
if(!self::ipv4_check($addr)) {
return $addr;
}
$hex = dechex(self::ip2long($addr));
$hex = str_repeat('0', 8 - strlen($hex)) . $hex;
$ipv6 = '0000:0000:0000:0000:0000:0000:';
$ipv6 .= substr($hex, 0, 4) . ':' . substr($hex, 4, 4);
return $ipv6;
}
/**
* 检测IP地址是否由IPv4转换而来
* @param $ipv6_bin
* @return bool
*/
public function ipv6_is_ipv4($ipv6_bin) {
if(strlen($ipv6_bin) !== 16) {
return false;
}
$unpack = join('', unpack("H*", $ipv6_bin));
//IPv4只有32位所以前96位全部为0
return strpos($unpack, "000000000000000000000000") === 0;
}
/**
* 判断IP地址的类型
* @param $addr
* @return int 无法判断时返回0
*/
public function type($addr) {
if(self::ipv6_check($addr)) {
return 6;
} elseif(self::ipv4_check($addr)) {
return 4;
} else {
return 0;
}
}
/**
* 检测是否为IPv4地址
* @param $addr
* @return bool
*/
public function ipv4_check($addr) {
$arr = explode('.', $addr);
$l = count($arr);
for($i = 0; $i < $l; $i++) {
if(strlen($arr[$i]) > 3) {
return false;
}
if(!is_numeric($arr[$i])) {
return false;
}
$a = intval($arr[$i], 10);
if($a > 255 || $a < 0) {
return false;
}
}
return true;
}
/**
* 检测是否为IPv6地址
* @param $addr
* @return bool
*/
public function ipv6_check($addr) {
$addr = self::_fix_v4($addr);
if(strpos($addr, '.')) {
return false;
}
$l1 = count(explode('::', $addr));
if($l1 > 2) {
return false;
}
$l2 = count(explode(':', $addr));
if($l2 < 3 || $l2 > 8) {
return false;
}
if($l2 < 8 && $l1 !== 2) {
return false;
}
preg_match('/^([0-9a-f]{0,4}\:)+[0-9a-f]{0,4}$/i', $addr, $arr);
if(!$arr[0]) {
return false;
}
return true;
}
/**
* 将IPv4地址转换为长整型
* @param $addr
* @return bool|int 地址格式错误时返回false
*/
public function ip2long($addr) {
$arr = explode('.', $addr);
$l = count($arr);
$long = 0;
for($i = 0; $i < $l; $i++) {
if(strlen($arr[$i]) > 3) {
return false;
}
if(!is_numeric($arr[$i])) {
return false;
}
$a = intval($arr[$i], 10);
if($a > 255 || $a < 0) {
return false;
}
$long += $a * pow(2, 24 - $i * 8);
}
return $long;
}
/**
* 检测一个地址是否为外网地址,不确保正确性,以IANA为准
* @param $addr
* @return bool
*/
public function wan_ip($addr) {
// 检查外网可用地址
if(self::ipv6_check($addr)) {
$addr = self::fill($addr);
// IPv4类地址处理
$v4p = substr($addr, 0, 29);
if($v4p == '0000:0000:0000:0000:0000:0000' || strtolower($v4p) == 'ffff:0000:0000:0000:0000:0000') {
$t = str_replace($v4p, '', $addr);
$t = str_replace(':', '', $t);
$ipv4 = long2ip(hexdec($t));
return self::_wan_ipv4($ipv4);
}
// 取前16位进行比较
$v6p = substr($addr, 0, 4);
$bin = decbin(hexdec($v6p));
$p = str_repeat(0, 16 - strlen($bin)) . $bin;
if((($p & '1110000000000000') == '0010000000000000') //2000::/3
|| (($p & '1111111000000000') == '1111110000000000') //FC00::/7
|| (($p & '1111111111000000') == '1111111010000000') //FE80::/10
|| (($p & '1111111100000000') == '1111111100000000') //FF00::/8
) {
return false;
}
return true;
} else {
return self::_wan_ipv4($addr);
}
}
/**
* IPv4外网地址检测
* @param $addr
* @return bool
*/
private function _wan_ipv4($addr) {
if(!self::ipv4_check($addr)) {
return false;
}
$arr = explode('.', $addr);
$bin = decbin($arr[0] * 256 + $arr[1]);
$p = str_repeat(0, 16 - strlen($bin)) . $bin;
$p8 = $p & '1111111100000000';
$p16 = & $p;
if(($p8 == '0000000000000000') // 0/8
|| ($p8 == '0000010100000000') // 5/8
|| ($p8 == '0000101000000000') // 10/8
|| ($p8 == '0001011100000000') // 23/8
|| ($p8 == '0010010000000000') // 36/8
|| ($p8 == '0010010100000000') // 37/8
|| ($p8 == '0010011100000000') // 39/8
|| ($p8 == '0010101000000000') // 42/8
|| ($p8 == '0110010000000000') // 100/8
|| ($p8 == '0110011000000000') // 102/8
|| ($p8 == '0110011100000000') // 103/8
|| ($p8 == '0110100000000000') // 104/8
|| ($p8 == '0110100100000000') // 105/8
|| ($p8 == '0110101000000000') // 106/8
|| ($p8 == '0111111100000000') // 127/8
|| ($p16 == '1010100111111110') // 169.254/16
|| (($p & '1111111111110000') == '1010110000010000') // 172.16/12
|| ($p8 == '1011001100000000') // 179/8
|| ($p8 == '1011100100000000') // 185/8
|| ($p16 == '1100000010101000') // 192.168/16
|| (($p & '1110000000000000') == '1110000000000000') // 224/8-255/8
) {
return false;
}
return true;
}
/**
* 修正IPv4位址类IPv6格式为标准IPv6格式,不验证合法性
* @param $addr
* @return string
*/
private function _fix_v4($addr) {
if(!strpos($addr, '.')) {
return $addr;
}
preg_match('/(\d+\.){3}\d+$/', $addr, $arr);
if(!self::ipv4_check($arr[0])) {
return $addr;
}
$hex = dechex(self::ip2long($arr[0]));
$hex = str_repeat('0', 8 - strlen($hex)) . $hex;
$v4p = substr($hex, 0, 4) . ':' . substr($hex, 4, 4);
$p1 = str_replace($arr[0], '', $addr);
strtolower($p1) === 'ffff:' && $p1 = '::' . $p1;
$addr = $p1 . $v4p;
return $addr;
}
}
/* PHP-IPv6&4 V1.1.
* Copyright (c) 2010 Mr.Bin <bin_jly@163.com>
*/
/**
* IP地址操作控制类
* Class Ip
*/
class Ip
{
/**
* 获取服务器变量中的客户IP地址
* @return string
*/
public function addr() {
return $_SERVER['REMOTE_ADDR'];
}
/**
* 获取单一客户端IP地址
* @return string
*/
public function realip() {
/* 穿过代理获取真实IP地址
* 返回值为数组,array[0]为真实IP,array[1]为代理IP(可能为空)
* 若array[0]和array[1]相等,则实际真实IP可能无法获取(高度匿名?)
*/
$is_proxy = false;
$ip = "0.0.0.0";
if($_SERVER['HTTP_X_FORWARDED_FOR']) {
$is_proxy = true;
$ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach($ips as $ip) {
if(!self::wan_ip($ip)) {
$ip = false;
} else {
break;
}
}
}
if(!$ip && $_SERVER['HTTP_CLIENT_IP']) {
$is_proxy = true;
$ip = $_SERVER['HTTP_CLIENT_IP'];
if(!self::wan_ip($ip)) {
$ip = false;
}
}
$proxy = '';
if($is_proxy) {
$proxy = $_SERVER['REMOTE_ADDR'];
if(!$ip) {
$ip = $proxy;
}
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
return explode(',', $ip . ',' . $proxy)[0];
}
/**
* 压缩IPv6地址
* @param $addr
* @return mixed|string
*/
public function cut($addr) {
// 压缩IPv6地址
if(!self::ipv6_check($addr)) {
return $addr;
}
$addr = self::fill($addr);
$arr = explode(':', $addr);
$arr2 = [];
foreach($arr as $a) {
$arr2[] = preg_replace('/^0{1,3}(\w+)/', '\1', $a);
}
$addr = join(':', $arr2);
$olen = strlen($addr);
for($i = 6; $i > 0; $i--) {
// 初步压缩
$addr = preg_replace('/:(0\:){' . $i . '}/', '::', $addr, 1);
if(strlen($addr) < $olen) {
break;
}
}
$addr = preg_replace('/^0\:\:/', '::', $addr);
$addr = preg_replace('/\:\:0$/', '::', $addr);
return $addr;
}
/**
* 将地址转换为标准IPv6地址
* @param $addr
* @return mixed|string
*/
public function fill($addr) {
// 标准IPv6格式
if(!self::ipv6_check($addr)) {
return $addr;
}
$addr = self::_fix_v4($addr);
$arr = explode(':', $addr);
$arr2 = [];
foreach($arr as $a) {
$l = strlen($a);
if($l > 0 && $l < 4) {
$arr2[] = str_repeat('0', 4 - $l) . $a;
} else {
$arr2[] = $a;
}
}
$addr = join(':', $arr2);
$fil = ':' . str_repeat('0000:', 9 - count($arr));
$addr = str_replace('::', $fil, $addr);
$addr = preg_replace('/^\:/', '0000:', $addr);
$addr = preg_replace('/\:$/', ':0000', $addr);
return $addr;
}
/**
* ip转换为128位二进制地址
* @param $addr
* @return bool|string
*/
public function ip2bin($addr) {
$type = self::type($addr);
if($type === 0) {
return false;
} elseif($type === 4) {
$addr = self::ip426($addr);
} else {
$addr = self::fill($addr);
}
$hexstr = str_replace(':', '', $addr);
return pack('H*', $hexstr);
}
/**
* ipv6二进制转为为非压缩型地址
* @param $bin
* @return bool|string
*/
public function bin2ip6($bin) {
if(strlen($bin) !== 16) {
return false;
}
$arr = str_split(join('', unpack('H*', $bin)), 4);
$addr = join(':', $arr);
return $addr;
}
/**
* ipv4二进制转换为字符型
* @param $bin string 必须为16个字符或者4个字符
* @return bool|string
*/
public function bin2ipv4($bin) {
$len = strlen($bin);
if($len !== 16 && $len !== 4) {
return false;
}
if($len === 16) {
$bin = substr($bin, 12);
}
$arr = str_split(join('', unpack('H*', $bin)), 2);
$arr[0] = hexdec($arr[0]);
$arr[1] = hexdec($arr[1]);
$arr[2] = hexdec($arr[2]);
$arr[3] = hexdec($arr[3]);
$addr = join('.', $arr);
return $addr;
}
/**
* IPv4转换为IPv6地址
* @param $addr
* @return string
*/
public function ip426($addr) {
// IPv4 to IPv6
if(!self::ipv4_check($addr)) {
return $addr;
}
$hex = dechex(self::ip2long($addr));
$hex = str_repeat('0', 8 - strlen($hex)) . $hex;
$ipv6 = '0000:0000:0000:0000:0000:0000:';
$ipv6 .= substr($hex, 0, 4) . ':' . substr($hex, 4, 4);
return $ipv6;
}
/**
* 检测IP地址是否由IPv4转换而来
* @param $ipv6_bin
* @return bool
*/
public function ipv6_is_ipv4($ipv6_bin) {
if(strlen($ipv6_bin) !== 16) {
return false;
}
$unpack = join('', unpack("H*", $ipv6_bin));
//IPv4只有32位所以前96位全部为0
return strpos($unpack, "000000000000000000000000") === 0;
}
/**
* 判断IP地址的类型
* @param $addr
* @return int 无法判断时返回0
*/
public function type($addr) {
if(self::ipv6_check($addr)) {
return 6;
} elseif(self::ipv4_check($addr)) {
return 4;
} else {
return 0;
}
}
/**
* 检测是否为IPv4地址
* @param $addr
* @return bool
*/
public function ipv4_check($addr) {
$arr = explode('.', $addr);
$l = count($arr);
for($i = 0; $i < $l; $i++) {
if(strlen($arr[$i]) > 3) {
return false;
}
if(!is_numeric($arr[$i])) {
return false;
}
$a = intval($arr[$i], 10);
if($a > 255 || $a < 0) {
return false;
}
}
return true;
}
/**
* 检测是否为IPv6地址
* @param $addr
* @return bool
*/
public function ipv6_check($addr) {
$addr = self::_fix_v4($addr);
if(strpos($addr, '.')) {
return false;
}
$l1 = count(explode('::', $addr));
if($l1 > 2) {
return false;
}
$l2 = count(explode(':', $addr));
if($l2 < 3 || $l2 > 8) {
return false;
}
if($l2 < 8 && $l1 !== 2) {
return false;
}
preg_match('/^([0-9a-f]{0,4}\:)+[0-9a-f]{0,4}$/i', $addr, $arr);
if(!$arr[0]) {
return false;
}
return true;
}
/**
* 将IPv4地址转换为长整型
* @param $addr
* @return bool|int 地址格式错误时返回false
*/
public function ip2long($addr) {
$arr = explode('.', $addr);
$l = count($arr);
$long = 0;
for($i = 0; $i < $l; $i++) {
if(strlen($arr[$i]) > 3) {
return false;
}
if(!is_numeric($arr[$i])) {
return false;
}
$a = intval($arr[$i], 10);
if($a > 255 || $a < 0) {
return false;
}
$long += $a * pow(2, 24 - $i * 8);
}
return $long;
}
/**
* 检测一个地址是否为外网地址,不确保正确性,以IANA为准
* @param $addr
* @return bool
*/
public function wan_ip($addr) {
// 检查外网可用地址
if(self::ipv6_check($addr)) {
$addr = self::fill($addr);
// IPv4类地址处理
$v4p = substr($addr, 0, 29);
if($v4p == '0000:0000:0000:0000:0000:0000' || strtolower($v4p) == 'ffff:0000:0000:0000:0000:0000') {
$t = str_replace($v4p, '', $addr);
$t = str_replace(':', '', $t);
$ipv4 = long2ip(hexdec($t));
return self::_wan_ipv4($ipv4);
}
// 取前16位进行比较
$v6p = substr($addr, 0, 4);
$bin = decbin(hexdec($v6p));
$p = str_repeat(0, 16 - strlen($bin)) . $bin;
if((($p & '1110000000000000') == '0010000000000000') //2000::/3
|| (($p & '1111111000000000') == '1111110000000000') //FC00::/7
|| (($p & '1111111111000000') == '1111111010000000') //FE80::/10
|| (($p & '1111111100000000') == '1111111100000000') //FF00::/8
) {
return false;
}
return true;
} else {
return self::_wan_ipv4($addr);
}
}
/**
* IPv4外网地址检测
* @param $addr
* @return bool
*/
private function _wan_ipv4($addr) {
if(!self::ipv4_check($addr)) {
return false;
}
$arr = explode('.', $addr);
$bin = decbin($arr[0] * 256 + $arr[1]);
$p = str_repeat(0, 16 - strlen($bin)) . $bin;
$p8 = $p & '1111111100000000';
$p16 = & $p;
if(($p8 == '0000000000000000') // 0/8
|| ($p8 == '0000010100000000') // 5/8
|| ($p8 == '0000101000000000') // 10/8
|| ($p8 == '0001011100000000') // 23/8
|| ($p8 == '0010010000000000') // 36/8
|| ($p8 == '0010010100000000') // 37/8
|| ($p8 == '0010011100000000') // 39/8
|| ($p8 == '0010101000000000') // 42/8
|| ($p8 == '0110010000000000') // 100/8
|| ($p8 == '0110011000000000') // 102/8
|| ($p8 == '0110011100000000') // 103/8
|| ($p8 == '0110100000000000') // 104/8
|| ($p8 == '0110100100000000') // 105/8
|| ($p8 == '0110101000000000') // 106/8
|| ($p8 == '0111111100000000') // 127/8
|| ($p16 == '1010100111111110') // 169.254/16
|| (($p & '1111111111110000') == '1010110000010000') // 172.16/12
|| ($p8 == '1011001100000000') // 179/8
|| ($p8 == '1011100100000000') // 185/8
|| ($p16 == '1100000010101000') // 192.168/16
|| (($p & '1110000000000000') == '1110000000000000') // 224/8-255/8
) {
return false;
}
return true;
}
/**
* 修正IPv4位址类IPv6格式为标准IPv6格式,不验证合法性
* @param $addr
* @return string
*/
private function _fix_v4($addr) {
if(!strpos($addr, '.')) {
return $addr;
}
preg_match('/(\d+\.){3}\d+$/', $addr, $arr);
if(!self::ipv4_check($arr[0])) {
return $addr;
}
$hex = dechex(self::ip2long($arr[0]));
$hex = str_repeat('0', 8 - strlen($hex)) . $hex;
$v4p = substr($hex, 0, 4) . ':' . substr($hex, 4, 4);
$p1 = str_replace($arr[0], '', $addr);
strtolower($p1) === 'ffff:' && $p1 = '::' . $p1;
$addr = $p1 . $v4p;
return $addr;
}
}
这是参考模板?
别人写的
哈哈。。过来了额
新年快乐