如何在IPv4 PHP中处理IPv6地址

时间:2011-09-03 00:47:41

标签: php mysql ip ipv6

我是一名iphone开发者 - 网络开发人员的新手,所以请耐心等待!我目前正在使用MAMP进行本地测试。

我的网站上有一个高度安全的部分。除了需要用户/通行证 - 它还会检查用户的IP。如果以前未使用该IP帐户,则会将该IP以及唯一ID添加到保留表中,并向用户发送一封电子邮件,要求确认从该位置访问其帐户。

如果用户登录,并且他们的IP与我的“允许”表中与其用户ID关联的任何IP都不匹配,则会执行上述任务,然后他们会收到一封电子邮件。

我用来生成他们点击链接的网址的代码看起来有点像这样:

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访问过(即两个正则表达式都不满意)。我查看了包含请求的保留表,请求的IP是:fe80::da30:62ff:fe18:6681

我猜那是ipv6? - 我需要知道的是:

  • 我应该期待ipv6 addressess在我的网站上线时点击它吗?
  • 我如何判断它是否是本地请求(例如我的正则表达式为192.168 ......以及127 ...)

我非常感谢任何关于此的建议,因为我觉得它真的令人困惑

2 个答案:

答案 0 :(得分:7)

如果要确保不发生IPv6连接,可以将Listen 0.0.0.0:80添加到您的apache配置中。但是大多数网络主机不支持IPv6(我知道,我们是在2011年),因此人们甚至不可能通过IPv6连接到你。你看到这个的唯一原因是因为bonjour(使.local地址工作的原因)在IPv6上运行。

如果您想准备好IPv6代码,几乎不需要进行任何更改,因为大多数IP PHP功能都可以在IPv4和IPv6上运行。我记得的唯一变化是将MySQL表中的varchar数据类型增加到IPv6地址的最大长度(39)。

我不确定IPv6是否遵循与IPv4相同的subnet规则,但我认为验证IPv6地址是本地的将会更加困难。

编辑:

fe80::/10似乎是本地链接地址,可能就像检查前4位数一样简单。

答案 1 :(得分:2)

要查看IPv6地址是否为本地,您必须知道本地使用的是哪些地址。 IPv6不执行NAT(通常)。有些网络在内部使用ULA(唯一本地地址),但许多网络只使用内部从ISP获得的地址。

您必须考虑的一件事是,有些(大多数?这些天)使用隐私扩展。这意味着他们的IPv6地址将随时间而变化。这将导致您的表增长很多,它将使用户一遍又一遍地重新进行身份验证。我认为你最好的选择是只存储子网(前64位)并匹配它。

以防您不知道IPv6地址语法:地址使用十六进制数字并且格式为ssss:ssss:ssss:ssss:nnnn:nnnn:nnnn:nnnn其中s是子网,n是节点/主办。省略了每个4位数的块中的前导零,并且用:: once替换多个0的块。所以fe80::da30:62ff:fe18:6681实际上是fe80:0000:0000:0000:da30:62ff:fe18:6681。我自己的网络服务器的地址为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";