【问题标题】:Calculating IP Address Long Form Number for IPv6 Compared to IPv4 Using PHP使用 PHP 计算 IPv6 与 IPv4 的 IP 地址长格式编号
【发布时间】:2015-12-28 19:35:02
【问题描述】:

目前我有两种计算 IPv4 长整数的方法:

//IPv4 format: w.x.y.z
$ip_number = (16777216 * $w) + (65536 * $x) + (256 * $y) + $z;
$ip_number = ip2long($ip);

但是如何将 IPv6 计算为长整数?

我正在寻找一个函数或不需要我安装任何 PHP 扩展的东西。

编辑:

我需要长整数,这样我就可以比较它以进行 IP 范围查询。这是 IPv6 范围查询的示例行:

"58569075684585412230123897272863293440","58569076873007849944088961176022548479","MU","Mauritius"

【问题讨论】:

  • 您需要 128 位整数来处理 IPv6 地址。您可能需要使用整数数组。
  • 据我所知,IPv6 的最高 IP 整数长度为 38 位。我觉得整个 128 位的东西非常令人困惑......
  • 表示大多数“数字”需要不止一位。
  • 肯定有一些简单的公式来计算吧?它只是一个整数(虽然很长)不是吗? :)
  • IPv6 字符串长度可以是 32 个十六进制数字(IPv6 地址中的八个字中的每个字都有四个十六进制数字)。每个十六进制数字代表 4 位,所以4*32=128 位。

标签: php ipv6 ipv4


【解决方案1】:

建议:

长期存储不是一个合适的方法。使用,

string inet_ntop ( string $in_addr )

此函数转换 32 位 IPv4 或 128 位 IPv6 地址(如果 PHP 在启用 IPv6 支持的情况下构建)到地址系列中 适当的字符串表示。

你也应该看到,

string inet_pton ( string $address )

inet_ntop() 示例

<?php
$packed = chr(127) . chr(0) . chr(0) . chr(1);
$expanded = inet_ntop($packed);

/* Outputs: 127.0.0.1 */
echo $expanded;

$packed = str_repeat(chr(0), 15) . chr(1);
$expanded = inet_ntop($packed);

/* Outputs: ::1 */
echo $expanded;
?>

范围比较

以下两个函数是在 PHP 5.1.0 中引入的,inet_ptoninet_pton。他们的目的是将人类可读的 IP 地址转换成他们打包的in_addr 表示。由于结果不是纯二进制,我们需要使用unpack 函数来应用位运算符。

这两个函数都支持 IPv6 和 IPv4。唯一的区别是您如何从结果中解压缩地址。使用 IPv6,您将使用 A16 解包内容,使用 IPv4,您将使用 A4 解包。

为了更好地理解前面的内容,这里有一个小示例输出以帮助澄清:

// Our Example IP's
$ip4= "10.22.99.129";
$ip6= "fe80:1:2:3:a:bad:1dea:dad";


// ip2long examples
var_dump( ip2long($ip4) ); // int(169239425)
var_dump( ip2long($ip6) ); // bool(false)


// inet_pton examples
var_dump( inet_pton( $ip4 ) ); // string(4)
var_dump( inet_pton( $ip6 ) ); // string(16)

我们在上面证明了 inet_* 系列支持 IPv6 和 v4。我们的下一步是将打包结果转换为解包变量。

// Unpacking and Packing
$_u4 = current( unpack( "A4", inet_pton( $ip4 ) ) );
var_dump( inet_ntop( pack( "A4", $_u4 ) ) ); // string(12) "10.22.99.129"


$_u6 = current( unpack( "A16", inet_pton( $ip6 ) ) );
var_dump( inet_ntop( pack( "A16", $_u6 ) ) ); //string(25) "fe80:1:2:3:a:bad:1dea:dad"

注意:当前函数返回数组的第一个索引。相当于说 $array[0]。

解包打包后,我们可以看到我们得到了和输入一样的结果。这是一个简单的概念证明,可确保我们不会丢失任何数据。

终于用上了,

if ($ip <= $high_ip && $low_ip <= $ip) {
  echo "in range";
}

参考:php.net

【讨论】:

  • 我不打算存储它。我将它与 ip 范围表进行比较。这就是为什么我需要它的长格式 - 用于查询:)
  • 查看编辑后的答案。至少你会得到一些概念
  • 谢谢,我认为您为我指明了正确的方向。必须阅读有关此的所有文档:)
【解决方案2】:

好的,这就是我最终解决它的方法:

function ipaddress_to_ipnumber($ipaddress) {
    $pton = @inet_pton($ipaddress);
    if (!$pton) { return false; }
    $number = '';
    foreach (unpack('C*', $pton) as $byte) {
        $number .= str_pad(decbin($byte), 8, '0', STR_PAD_LEFT);
    }
    return base_convert(ltrim($number, '0'), 2, 10);
}

https://inkplant.com/code/ipv6-to-number

【讨论】:

    猜你喜欢
    • 2011-06-09
    • 2013-07-02
    • 1970-01-01
    • 2018-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-16
    相关资源
    最近更新 更多