2011-10-11 68 views
-1

我对网络主题不是很了解,但是我必须为我的项目存储IP地址,并且我想准备好处理IPv4和IPv6。我读过的最好的解决方案似乎是两个BIGINT的无符号领域,其中一个是空在IPv4中的情况:
How to store IPv6-compatible address in a relational database 没有任何人有完整的解决方案?完整的PHP + MySQL IPv4和IPv6解决方案?

我需要的代码从一个字符串的地址去(如$ _ SERVER [“HTTP_CLIENT_IP”]生产),以数值,反之亦然。

非常感谢您的帮助。我想确保我正确地做到了这一点。

+0

嗨,我想你可以创建一个使用正则表达式 – Sudantha

回答

0

我实际上是按照人类写作的方式储存序号。因此,IPv6的8个16位无符号整数字段和IPv4的4个8位无符号整数字段。对我来说,这使得搜索某些网络很简单,但我可以看到2个unsigned bigint也可以很简单。

或者你可以将其存储在你拥有了它在大多数经常在你的代码,并且将检索它是这样的格式。这似乎是一个字符串,大约有40个字符。如果你这样做,你会想要使用rfc5952中建议的规范表示法。

我不能只为你写转换代码;你需要提供一些你未尝试过的方法,以及为什么。

+0

VARCHAR(40)应做的工作很好,烨列规则。 – CD001

+0

在我的情况下,效率有点令人担忧。我打算存储很多地址,并且我需要经常搜索唯一性(这个人/机器以前曾经访问过吗?)所以我主要需要一种方法,但解析是最难的部分。 IP地址可以以多种形式出现。 –

1

或者你可以使用像PostgreSQL这样的数据库,如果这是一个选项。它具有用于存储和搜索IPv4和IPv6地址和前缀的本机数据类型。输入和输出以字符串表示形式(通常)完成。

如果你使用MySQL这真的取决于你想如何使用地址。如果你想搜索子网,按前缀等组合,那么整数是最有用的。如果你只需要存储它们,那么varchar就是要走的路。

+0

不幸的是,我在主机上遇到了MySQL问题。 (还是)感谢你的建议。现在看来,MySQL似乎应该有一个本地解决方案... –

-1

对于IP地址(格式)的验证,我目前使用这个作为事物的一部分,我的工作 - 而不是100%肯定,这是完全正确的,但 - 需要它(和我不扔更多的数据“T喜欢我的私有成员使用的命名约定或者 - 但这是一个容易解决与重构):

class IPAddress { 

    //IP Address string 
    private $ip_address; 

    //IPv4 verification (RegExp insert) 
    private $match_ipv4; 

    //IPv6 verification (RegExp insert) 
    private $match_ipv6; 

    /** 
    * Constructor function 
    * 
    * The $sIPAddress parameter is optional - 
    * it allows you to set the IP address in 
    * the object at creation. 
    * 
    * @param string $sIPAddress 
    * @return void 
    */ 
    public function __construct($sIPAddress=null) { 
    //setup regexp inserts 
    //IPv4 decimal octets match 
    $sDecOctet = "([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"; 

    //IPv4 match 
    $this->match_ipv4 = "({$sDecOctet}\.){3}{$sDecOctet}"; 

    //Hex 16 match 
    $sH16 = "[0-9a-fA-F]{1,4}"; 

    //Char32 match 
    $sLS32 = "({$sH16}:{$sH16}|{$this->match_ipv4})"; 

    //IPv6 match 
    $this->match_ipv6 = "((({$sH16}:){6}" 
    . "|::({$sH16}:){5}" 
    . "|({$sH16})?::({$sH16}:){4}" 
    . "|(({$sH16}:){0,1}{$sH16})?::({$sH16}:){3}" 
    . "|(({$sH16}:){0,2}{$sH16})?::({$sH16}:){2}" 
    . "|(({$sH16}:){0,3}{$sH16})?::{$sH16}:" 
    . "|(({$sH16}:){0,4}{$sH16})?::" 
    . "){$sLS32}" 
    . "|((({$sH16}:){0,5}{$sH16})?::{$sH16}" 
    . "|(({$sH16}:){0,6}{$sH16})?::" 
    . "))"; 

    //set the IP address if required 
    if(!is_null($sIPAddress)) { 
     $this->setIPAddress($sIPAddress); 
    } 
    } 

    /** 
    * IP Address setter 
    * 
    * Sets the IP address string - this can 
    * be either IPv4 or IPv6 format. 
    * 
    * @param string $sIPAddress 
    * @return void 
    */ 
    public function setIPAddress($sIPAddress) { 
    $this->ip_address = $sIPAddress; 
    } 

    /** 
    * IP Address getter 
    * 
    * Returns the IP address string - this 
    * can be either IPv4 or IPv6 format. 
    * 
    * @return string 
    */ 
    public function getIPAddress() { 
    return $this->ip_address; 
    } 

    /** 
    * IPv4 RegExp getter 
    * 
    * Returns Regular Expression used to 
    * validate IPv4 addresses. 
    * 
    * @return string 
    */ 
    public function getIPv4RegExp() { 
    return '/^' . $this->match_ipv4 . '$/'; 
    } 

    /** 
    * IPv6 RegExp getter 
    * 
    * Returns the Regular Expression used to 
    * validate IPv6 addresses. 
    * 
    * @return string 
    */ 
    public function getIPv6RegExp() { 
    return '/^' . $this->match_ipv6 . '$/i'; 
    } 

    /** 
    * IPv4 validation 
    * 
    * Validates the stored IP address 
    * against the IPv4 pattern and returns 
    * a boolean denoting whether the address 
    * if of IPv4 format or not. 
    * 
    * @return bool 
    */ 
    public function validateIPv4() { 
    return ip2long($this->ip_address) && ip2long($this->ip_address) !== -1 ? true : false; 
    } 

    /** 
    * IPv6 validation 
    * 
    * Validates the stored IP address 
    * against the IPv6 pattern and returns 
    * a boolean denoting whether the address 
    * if of IPv6 format or not. 
    * 
    * @return bool 
    */ 
    public function validateIPv6() { 
    return preg_match($this->getIPv6RegExp(), $this->ip_address) ? true : false; 
    } 

    /** 
    * General validity check 
    * 
    * Validates the stored IP address against 
    * both the IPv4 and IPv6 patterns - if 
    * EITHER matches then true is returned 
    * (it's a correctly formatted IP address). 
    * 
    * Otherwise it's not a valid IP address 
    * and false is returned. 
    * 
    * @return bool 
    */ 
    public function isValid() { 
    return $this->validateIPv4() || $this->validateIPv6() ? true : false; 
    } 

    /** 
    * Reserved state checker 
    * 
    * This method checks wheter the stored IP address 
    * is part of the local network range (i.e. it's in 
    * the private reserved IP address range) 
    * 
    * A boolean is returned denoting this reserved state 
    * unless the IP address itself is invalid - in which 
    * case null is returned. 
    * 
    * @return bool 
    */ 
    public function isReserved() { 

    //IPv4 format 
    if($this->validateIPv4()) { 
     return $this->_getIPv4IsReserved($this->ip_address); 
    } 

    //IPv6 format 
    elseif($this->validateIPv6()) { 
     //IPv4 masking 
     // this falls over if the IPv4 part is short-handed 
     // for instance ::ffff:192.0.2.128 can be written as ::ffff:c000:280 
     $reIPv4Masking = '/^((0{1,4}:){6}|(0{1,4}:){1,5}ffff:|::ffff:)(([0-9]{1,3}\.){3}[0-9]{1,3})/'; 

     //standard reserved IPv6 addresses 
     //local loopback = 0:0:0:0:0:0:0:1 || ::1 
     if(preg_match('/^(0{1,4}:){1,7}1|::1|fc00:.*$/i', $this->ip_address)) { 
     return true; 
     } 

     //if this is really an IPv4 address stacked in IPv6... 
     elseif(preg_match($reIPv4Masking, $this->ip_address)) { 
     $sIPv4Address = preg_replace($reIPv4Masking, "$2", $this->ip_address); 
     return $this->_getIPv4IsReserved($sIPv4Address); 
     } 

     //not reserved 
     else { 
     return false; 
     } 
    } 

    //invalid format 
    else { 
     return null; 
    } 
    } 

    /** 
    * IPv4 reserved state checker 
    * 
    * Private method to determine whether an IPv4 address is in 
    * one of the reserved private brackets (e.g. it's probably local) 
    * 
    * Returns a boolean denoting whether it's a reserved IPv4 address 
    * or null should the IP address fail validation 
    * 
    * @param string $sIPv4Address 
    * @return bool 
    */ 
    private function _getIPv4IsReserved($sIPv4Address) { 
    $sIP = long2ip(ip2long($sIPv4Address)); 
    $reIPv4 = '/([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/$'; //just a quick and dirty RegExp without sanity checking since we've already done that 

    if(preg_match($reIPv4, $sIP)) { 
     //break the IP address into parts and cast to integers 
     $iIPp1 = VParse::toInt(preg_replace($reIPv4, "$1", $sIP)); 
     $iIPp2 = VParse::toInt(preg_replace($reIPv4, "$2", $sIP)); 
     $iIPp3 = VParse::toInt(preg_replace($reIPv4, "$3", $sIP)); 
     $iIPp4 = VParse::toInt(preg_replace($reIPv4, "$4", $sIP)); 

     //check for reserved IP addresses 
     // 127.0.0.1 (local loopback) 
     // 10.0.0.0 - 10.255.255.255 
     // 172.16.0.0 - 172.31.255.255 
     // 192.168.0.0 - 192.168.255.255 
     if(($iIPp1 == 127 && $iIPp2 == 0 && $iIPp3 == 0 && $iIPp4 == 1) || $iIPp1 == 10 || ($iIPp1 == 172 && $iIP2 >= 16 && $iIP2 <= 31) || ($iIPp1 == 192 && $iIPp2 == 168)) { 
     return true; 
     } 

     //not part of the standard private IP address ranges 
     else { 
     return false; 
     } 
    } 

    //invalid format 
    else { 
     return null; 
    } 
    } 

//end class 
} 

编辑:刚刚发现这依赖于我的变量解析类VParse - 你几乎可以取代使用PHP的标准(int)类型铸造功能的任何VParse::toInt()实例。