在PHP中检测IPv6地址并将其正确存储在MySQL中。怎么用?

在PHP中检测IPv6地址并将其正确存储在MySQL中。怎么用?,php,ipv6,Php,Ipv6,我读了一些已经提出的问题,我发现这是有用的,尽管我没有尝试过 不过,假设我在MySQL中有一个“bans”表。我将如何存储IPv6地址?该方法必须是通用的,即该字段必须能够包含ipv4或ipv6地址。这也必须适用于“我的用户”表中的“我的ip地址”字段 我通常会检查if(getip==$bans['ip']){do something} 但是我的getip函数是针对ipv4 afaik的,我想知道它是否能工作 我使用的函数是 function getip() { if(isset($_S

我读了一些已经提出的问题,我发现这是有用的,尽管我没有尝试过

不过,假设我在MySQL中有一个“bans”表。我将如何存储IPv6地址?该方法必须是通用的,即该字段必须能够包含ipv4或ipv6地址。这也必须适用于“我的用户”表中的“我的ip地址”字段

我通常会检查
if(getip==$bans['ip']){do something}
但是我的getip函数是针对ipv4 afaik的,我想知道它是否能工作

我使用的函数是

function getip()
{
    if(isset($_SERVER['REMOTE_ADDR']))
    {
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    elseif(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
    {
    if(preg_match_all("#[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}#s", $_SERVER['HTTP_X_FORWARDED_FOR'], $addresses))
    {
        foreach($addresses[0] as $key => $val)
        {
            if(!preg_match("#^(10|172\.16|192\.168)\.#", $val))
            {
                $ip = $val;
                break;
            }
        }
    }
}

if(!isset($ip))
{
    if(isset($_SERVER['HTTP_CLIENT_IP']))
    {
        $ip = $_SERVER['HTTP_CLIENT_IP'];
    }
    else
    {
        $ip = '';
    }
}

$ip = preg_replace("#([^.0-9 ]*)#", "", $ip);
return $ip;
}
不过,假设我在MySQL中有一个“bans”表。我将如何存储IPv6地址

您可以将其存储在VARCHAR(40)的简单列中。
考虑到示例IPv6最大值为40字节:

2001:0DB8:0000:0000:0000:0000:1428:57ab 

coulmn也可以包含IPv4

我最近在mysql中搜索用于存储ipv6地址的最佳数据类型。我没有找到使用VARCHAR()的好理由,只有好理由使用VARCHAR()

我对二进制(16)、两个BIGINT无符号和十进制数据类型进行了一些性能测试

我创建了以下表格,其中包含来自100个随机网络的2000000个随机ip地址

CREATE TABLE ipv6_address_binary (
    id SERIAL NOT NULL AUTO_INCREMENT PRIMARY KEY,
    addr BINARY(16) NOT NULL UNIQUE
);

CREATE TABLE ipv6_address_twobigints (
    id SERIAL NOT NULL AUTO_INCREMENT PRIMARY KEY,
    haddr BIGINT UNSIGNED NOT NULL,
    laddr BIGINT UNSIGNED NOT NULL,
    UNIQUE uidx (haddr, laddr)
);

CREATE TABLE ipv6_address_decimal (
    id SERIAL NOT NULL AUTO_INCREMENT PRIMARY KEY,
    addr DECIMAL(39,0) NOT NULL UNIQUE
);
然后,我为每个网络选择所有ip地址并记录响应时间。twobigints表的平均响应时间约为1秒,而二进制表的平均响应时间约为百分之一秒

以下是问题

注:

X_u0;[高/低]是X的最高/最低有效64位

当NETMASK_LOW为0时,条件被忽略,因为它总是产生true。对性能影响不大


您忘记了IPv6地址可以以较短的格式存储。示例:fe80:0000:0000:0000:0202:b3ff:fe1e:8329可能是fe80:0:0:202:b3ff:fe1e:8329。这将不同于DB@dikidera:为什么不以规范的方式存储它,并与规范的方式进行比较?@dikidera:没错。现在,在mysql中调用它们之前,只需将:0:替换为:0000:就可以了。在wiki上,它说短版本也可以变短,即fe80:0:0:202:b3ff:fe1e:8329可以变为fe80::202:b3ff:fe1e:8329,所以这也不起作用。我还需要一些工作函数,因为这对我来说还是第一次。@yes123:不,不是。它的意思是“具有所需长度的一串零”<代码>::1(环回)并不意味着
:0000:1
,它意味着
0000:0000:0000:0000:0000:0000:0001
,而
2001:db8::1428:57ab
意味着
2001:0db8:0000:0000:0000:1428:57ab
SELECT COUNT(*) FROM ipv6_address_twobigints
WHERE haddr & NETMASK_HIGH = NETWORK_HIGH
AND laddr & NETMASK_LOW = NETWORK_LOW

SELECT COUNT(*) FROM ipv6_address_binary
WHERE addr >= NETWORK
AND addr <= BROADCAST

SELECT COUNT(*) FROM ipv6_address_decimal
WHERE addr >= NETWORK
AND addr <= BROADCAST
BINARY_InnoDB  0.0119529819489
BINARY_MyISAM  0.0139244818687
DECIMAL_InnoDB 0.017379629612
DECIMAL_MyISAM 0.0179929423332
BIGINT_InnoDB  0.782350552082
BIGINT_MyISAM  1.07809265852