代码之家  ›  专栏  ›  技术社区  ›  Christian

php将ipv6转换为二进制(/memory)表示

  •  2
  • Christian  · 技术社区  · 14 年前

    我已经为ipv4“做”了这个;

    $ip = '127.0.0.1'; // example
    $ip = explode('.',$ip);
    if( count($ip) != 4 ) $ip = array(0,0,0,0); // wrong ip format, default to 0.0.0.0
    return chr($ip[0]) . chr($ip[1]) . chr($ip[2]) . chr($ip[3]);
    

    我也需要为ipv6做上面的工作。读过ipv6规范,(我承认我没有读过 全部的 其中),我看到了一些奇怪之处(“例外”),比如一组0可以压缩为一个双冒号:“:0000:0000”=>“:”(如果我的理解是正确的话)。 我还看到了如何在ipv6字符串中使用ipv4样式的字符串:0:0:0:0:0:0:127.0.0.1

    我们先说我不知道从哪里开始。


    多亏了阿尔瓦罗,现在我有了一个纯PHP的inet-pton实现:

    /**
     * @copyright   2004-2007 Aidan Lister <aidan@php.net>, Arpad Ray <arpad@php.net>
     * @link        http://php.net/inet_pton
     * @author      Arpad Ray <arpad@php.net>
     */
    function php_compat_inet_pton($address) {
        $r = ip2long($address);
        if ($r !== false && $r != -1) return pack('N', $r);
        $delim_count = substr_count($address, ':');
        if ($delim_count < 1 || $delim_count > 7) return false;
        $r = explode(':', $address);
        $rcount = count($r);
        if (($doub = array_search('', $r, 1)) !== false) {
            $length = (!$doub || $doub == $rcount - 1 ? 2 : 1);
            array_splice($r, $doub, $length, array_fill(0, 8 + $length - $rcount, 0));
        }
        $r = array_map('hexdec', $r);
        array_unshift($r, 'n*');
        $r = call_user_func_array('pack', $r);
        return $r;
    }
    

    问题是,我不太明白它在做什么。问题是,我不能 只是 使用这样一个函数,因为(一方面)我知道它将IP打包成不同于我正在(或想要)的格式。

    2 回复  |  直到 12 年前
        1
  •  3
  •   Álvaro González    14 年前

    ip2long() inet_pton() .

    编辑:在 PHP_Compat 包裹。

    更新

    我已经为您评论了函数。请注意,我对ipv6地址格式不太了解,所以我可以大致告诉您 什么 它确实没有 为什么 .

    <?php
    
    /**
     * @copyright   2004-2007 Aidan Lister <aidan@php.net>, Arpad Ray <arpad@php.net>
     * @link        http://php.net/inet_pton
     * @author      Arpad Ray <arpad@php.net>
     */
    function php_compat_inet_pton($address) {
        // Convert to IPv4 (numeric representation)
        $r = ip2long($address);
    
        // ip2long() will return FALSE if it's an invalid IPv4 address (or -1 if PHP earlier than 5.0.0)
        if ($r !== false && $r != -1)
            // if it didn't, then it *is* a valid IPv4 address
            // We pack the number as unsigned long (always 32 bit, big endian byte order) and we're done
            return pack('N', $r);
    
        // Count the number of delimiters (:)
        $delim_count = substr_count($address, ':');
    
        // If none or more than 7, the address is not valid
        if ($delim_count < 1 || $delim_count > 7) return false;
    
        // Create an array with the delimited substrings
        $r = explode(':', $address);
    
        // Count the number of items
        $rcount = count($r);
    
        // If we have empty items, fetch the position of the first one
        if (($doub = array_search('', $r, 1)) !== false) {
    
            // We fill a $length variable with this rule:
            // - If it's the first or last item ---> 2
            // - Otherwhise                     ---> 1
            $length = (!$doub || $doub == $rcount - 1 ? 2 : 1);
    
            // Remove a portion of the array and replace it with something else
            array_splice($r,
    
                // We skip items before the empty one
                $doub,
    
                // We remove one or two items
                $length,
    
                // We replace each removed value with zeros
                array_fill(0, 8 + $length - $rcount, 0)
    
            );
        }
    
        // We convert each item from hexadecimal to decimal
        $r = array_map('hexdec', $r);
    
        // We add 'n*' at the beginning of the array (just a trick to use pack on all the items)
        array_unshift($r, 'n*');
    
        // We pack all the items as unsigned shorts (always 16 bit, big endian byte order)
        $r = call_user_func_array('pack', $r);
    
        // Return the resulting string
        return $r;
    }
    
        2
  •  1
  •   Christian    14 年前

    我将使用以下URL来编写我需要的函数:

    http://www.zytrax.com/tech/protocols/ipv6.html

    我将用函数代码进行编辑。

    编辑 希望人们能发现这一点。

    class Connect {
        /**
         * Returns the IP in it's fullest format.
         * @example
         *          ::1              => 0000:0000:0000:0000:0000:0000:0000:0001
         *          220F::127.0.0.1  => 220F:0000:0000:0000:0000:0000:7F00:0001
         *          2F:A1::1         => 002F:00A1:0000:0000:0000:0000:0000:0001
         * @param string $ip Original/compressed/packed IPv6.
         * @return string Full IP.
         */
        protected static function fixIpv6($ip){
            // fix double colon
            if(strpos($ip,'::')!==false)$ip=str_replace('::',str_repeat(':',9-substr_count($ip,':')),$ip);
            // fix each slot
            $ip=explode(':',$ip);
            foreach($ip as $k=>$v){
                // fix empty/compressed slots
                $ip[$k]=$v=str_pad($v,4,'0',STR_PAD_LEFT);
                // fix ipv4-style slot
                if(strpos($v,'.')!==false){
                    // initially empty buffer
                    $ip[$k]='';
                    // replace each number(byte) with a two-digit hex representation
                    foreach(explode('.',$v) as $v2){
                        $v=dechex(min((int)$v2,255));
                        if(strlen($v)==1)$v='0'.$v;
                        $ip[$k].=$v;
                    }
                    // add colon in between two pairs(bytes) (FFFFFFFF=>FFFF:FFFF)
                    $ip[$k]=implode(':',str_split($ip[$k],4));
                }
            }
            return strtoupper(implode(':',$ip));
        }
        /**
         * Compresses an IP to it's binary representation.
         * @param string $ip A well-formatted full IPv4 or IPv6 address.
         * @return string Binary representation of address.
         */
        public static function compressIp($ip){
            if(strpos($ip,':')!==false){ // ipv6
            $ip=str_split(str_replace(':','',self::fixIpv6($ip)),2);
            foreach($ip as $k=>$v)$ip[$k]=chr(hexdec($v));
            return implode('',$ip);
            }elseif(strpos($ip,'.')!==false){ // ipv4
                $ip=explode('.',$ip);
                if(count($ip)!=4)$ip=array(0,0,0,0);
                return chr($ip[0]).chr($ip[1]).chr($ip[2]).chr($ip[3]);
            }else throw new Exception('Unrecognized IP format: '.MB_SECURITY::snohtml($ip));
        }
    }