如何与IPv4 PHP一起处理IPv6地址
我是一名iphone开发人员,刚接触网络开发人员,所以请耐心等待如何与IPv4 PHP一起处理IPv6地址,php,mysql,ip,ipv6,Php,Mysql,Ip,Ipv6,我是一名iphone开发人员,刚接触网络开发人员,所以请耐心等待我目前正在使用MAMP进行本地测试 我的网站上有一个高度安全的部分。除了需要用户/通行证外,它还检查用户的IP。如果该帐户以前从未从该IP使用过,它会将该IP以及唯一ID添加到保留表中,并向用户发送电子邮件,要求用户确认从该位置访问其帐户 如果用户登录,并且他们的IP与我的“允许”表中与他们的用户ID关联的任何IP都不匹配,它将执行上述任务,并且他们将收到一封电子邮件 我用来生成他们单击的链接的url的代码看起来有点像这样: if
我目前正在使用MAMP进行本地测试 我的网站上有一个高度安全的部分。除了需要用户/通行证外,它还检查用户的IP。如果该帐户以前从未从该IP使用过,它会将该IP以及唯一ID添加到保留表中,并向用户发送电子邮件,要求用户确认从该位置访问其帐户 如果用户登录,并且他们的IP与我的“允许”表中与他们的用户ID关联的任何IP都不匹配,它将执行上述任务,并且他们将收到一封电子邮件 我用来生成他们单击的链接的url的代码看起来有点像这样:
if (preg_match('/^127./',$ip)) {
// accessed from this machine
$val_url = "http://localhost:8888/mywebsite/admin/aproove_ip.php?email=$admin_email&val=$hash";
}
else if (preg_match('/^192\.168./',$ip)) {
// accessed form a local networked computer
$val_url = "http://super.local:8888/mywebsite/admin/aproove_ip.php?email=$admin_email&val=$hash";
// note super.local is my machine's address, 8888 is MAMP port
}
else {
// accessed from the WWW
$val_url = "http://www.mywebsite.com/admin/aproove_ip.php?email=$admin_email&val=$hash";
}
现在,在我的电脑上进行测试时,这已经非常有效了
然而,我决定(不要问为什么)从我的iPod Touch进行测试,在它发送给我的电子邮件中(验证IP),它给了我完整的在线地址,就好像它是从WWW访问的一样(即,两个Regex都不满意)。我查看了包含请求的保留表,请求的IP是:fe80::da30:62ff:fe18:6681
我猜那是ipv6我需要知道的是:
- 我是否应该期望ipv6 addressess在我的站点上线时出现
- 我如何判断它是否是本地请求(比如我的正则表达式为192.168…和127…)
如果您希望确保不会发生IPv6连接,并且可以添加到您的apache配置中,我将非常感谢您在这方面的任何建议,因为我发现这确实令人困惑。但是大多数网络主机还不支持IPv6(是的,我知道,我们在2011年),所以人们甚至不太可能通过IPv6与您连接。您看到这一点的唯一原因是因为bonjour(使
.local
地址工作的原因)在IPv6上运行
如果您想让您的代码准备好IPv6,几乎不需要做任何更改,因为大多数IP PHP函数都可以在IPv4和IPv6上工作。我记得所做的唯一更改是将MySQL表中的varchar数据类型增加到IPv6地址的最大长度(39
)
我不确定IPv6是否遵循与IPv4相同的规则,但我预计验证IPv6地址是否为本地地址会更加困难
编辑:
fe80::/10
似乎是本地链接地址,可能只需检查前4位数字即可。要查看IPv6地址是否为本地地址,您必须知道本地使用的地址。IPv6不进行NAT(通常)。一些网络在内部使用ULA(唯一本地地址),但许多网络只在内部使用从ISP获得的地址
你必须考虑的一件事是,有些(现在大多数)使用隐私扩展。这意味着它们的IPv6地址将随时间而改变。这将导致您的表大量增长,并使用户一次又一次地重新验证。我认为您最好的选择是只存储子网(前64位)并匹配该子网
以防您不知道IPv6地址语法:地址使用十六进制数字,格式为ssss:ssss:ssss:nnnn:nnnn:nnnnnn:nnnn,其中s是子网,n是节点/主机。省略每个4位块中的前导零,多个0块替换为::once。所以fe80::da30:62ff:fe18:6681
实际上是fe80:0000:0000:0000:da30:62ff:fe18:6681
。我自己的Web服务器有地址2001:4038:0:16::16
,它是2001:4038:0000:0016:0000:0000:0000:0016
的缩写,子网是2001:4038:0:16::/64
从地址获取子网的示例代码:
<?php
# Get the original IP address, for example from the command line
$original_ip_str = $argv[1];
# Converto to binary form (suppress errors, we handle them)
$original_ip_bin = @inet_pton($original_ip_str);
if ($original_ip_bin === FALSE) {
$subnet_str = FALSE;
$subnet_bin = FALSE;
} else {
if (strlen($original_ip_bin) == 16) {
# IPv6: Replace the last 64 bits with zeroes
$subnet_bin = substr_replace($original_ip_bin, str_repeat("\000", 8), -8);
}
# Convert the result back to readable form (optional)
$subnet_str = inet_ntop($subnet_bin);
}
# Show the result
echo "IPv6 address: $original_ip_str\n";
echo "IPv6 subnet: $subnet_str\n";
谢谢已经让我的varchar长了39个字符-我想我不应该真的担心bonjour,那只是为了测试,最后当它上线时,它会做我想做的事情,不管是不是IPv6!您不应该使用varchar来存储IP地址—无论是v4还是v6。它阻止您使用位掩码高效地查询它们,并浪费大量存储空间。请使用INET_ATON()和INET_NTOA()在MySQL中存储和检索(分别)IP地址。因为在一般应用程序中存储IP的大多数用途只是为了跟踪用户,而且由于MySQL不能证明是以可读方式存储IP的本机方法,我通常只是为了方便而使用varchar(特别是当它可能是IPv6或IPv4时)。只需澄清的是,fe80::
或fe10::
表示本地??AFAICT专用网络地址指定为fc00::/7,而不是fe。。。请参阅,您能否提供一些代码,以便仅从IPv6地址获取子网?-然后我将其代码存储在我的数据库中…当然!在答案+1中添加代码,以使您的代码符合IPv6!今天编写的太多程序仍然不支持IPv6,即使IPv4地址已经用完。