PHP – IPv6通用类v1.0,为IPv6做好准备

来源:互联网 发布:qt socket 多线程编程 编辑:程序博客网 时间:2024/04/29 19:03
本IPv6类共12个函数或方法:
addr([addr]) 获取或格式化IPv6地址
realip() 穿过代理获取真实IP地址
cut(addr) 压缩IPv6地址
fill(addr) 标准IPv6格式
ip2bin(addr) 打包IPv6地址为二进制流,16字节宽
ip2bin(bin) 解二进制流为IPv6地址格式
ip426(addr) 把一个标准IPv4地址转换为IPv6地址
type(addr) 检测IP地址类型
ipv4_check(addr) 检测IPv4地址是否合法
ipv6_check(addr) 检测IPv6地址是否合法
ip2long(addr) 自定义的ip2long函数,修复了PHP自带函数错误处理含前导0的IPv4地址的问题

wan_ip(addr) 检测IP地址是否为公网可用地址,以IANA官网为准


<?php/* PHP-IPv6 V1.0. * Copyright (c) 2010 Mr.Bin <bin_jly@163.com> */class ipv6 {    function addr($addr=null) {        // 常规获取IPv6地址或格式化IP地址为IPv6格式        !$addr && ($addr = $_SERVER['REMOTE_ADDR']);        $type = self::type($addr);        if ( $type === 6 && self::ipv6_check($addr) ) return $addr;        elseif ( $type === 4 ) return self::ip426($addr);        else return 'Unknown';    }     function realip() {        /* 穿过代理获取真实IP地址         * 返回值为数组,array[0]为真实IP,array[1]为代理IP(可能为空)         * 若array[0]和array[1]相等,则实际真实IP可能无法获取(高度匿名?)         */        $is_proxy = false;        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;        }        if ( $is_proxy ) {            $proxy = $_SERVER['REMOTE_ADDR'];            if (!$ip) $ip = $proxy;        } else {            $ip = $_SERVER['REMOTE_ADDR'];        }        return explode(',', $ip.','.$proxy);    }     function cut($addr) {        // 压缩IPv6地址        if (!self::ipv6_check($addr)) return $addr;        $addr = self::fill($addr);        $arr = explode(':',$addr);        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;    }     function fill($addr) {        // 标准IPv6格式        if (!self::ipv6_check($addr)) return $addr;        $addr = self::_fix_v4($addr);        $arr = explode(':',$addr);        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;    }     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);    }     function bin2ip($bin) {        if ( strlen($bin) !== 16 ) return false;        $arr = str_split(join('',unpack('H*', $bin)), 4);        $addr = join(':',$arr);        return $addr;    }     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;    }     function type($addr) {        if ( self::ipv6_check($addr) ) return 6;        elseif ( self::ipv4_check($addr) ) return 4;        else return 0;    }     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;    }     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;    }     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;    }     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);        }    }     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;    }     private function _fix_v4($addr) {        // 修正IPv4位址类IPv6格式为标准IPv6格式,不验证合法性        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;    }}?>