在PHP中检测IPv6地址并将其正确存储在MySQL中。怎么用?
我读了一些已经提出的问题,我发现这是有用的,尽管我没有尝试过 不过,假设我在MySQL中有一个“bans”表。我将如何存储IPv6地址?该方法必须是通用的,即该字段必须能够包含ipv4或ipv6地址。这也必须适用于“我的用户”表中的“我的ip地址”字段 我通常会检查在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
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