更好的ip转int的方式

2018年7月24日 0 作者 筱枫

今天看别人的代码,里面涉及到一段ip地址转成int的代码,看了下代码的逻辑…当时觉得有些不理解

function ipToInt($ip)
{
    $ipArr = explode('.', $ip);
    $num = 0;
    for ($i = 0; $i < count($ipArr); $i++) {
        $num += intval($ipArr[$i]) * pow(256, count($ipArr) - ($i + 1));
    }
    return $num;
}

其实远远不用这么复杂,这样涉及了平方,乘法之类的运算,效率不高,不如使用这种简洁的方式

$ipArr = explode('.', $ip);
return 
((int)$ipArr[0] << 24) |
((int)$ipArr[1] << 16) |
((int)$ipArr[2] << 8) |
((int)$ipArr[3]);

看上去有点难以理解?
其实很简单,这涉及到数据的存储方式,真要说起来其实很复杂,你可以把一个int看成一个00000000,一共八位的字符串,上面这段代码就是将其放入对应的地方中
变成这个样子 $ipArr[0]$ipArr[1]$ipArr[2]$ipArr[3]
但这是最底层存储的二进制格式的十六进制码,再经过计算机转换成十进制,就变成了你所看到的
例如,我们可以用这段代码来观察其中的存储方式

$ipArr = explode('.', '192.168.1.1');
    $num = 0;
    $dec = 8;
    
    foreach ($ipArr as $v)
    {
        $num = $num | (int)$v << (32-$dec);
        $dec += 8;

        echo decbin($num)."\n";
    }

结果是这样的
11000000 00000000 00000000 00000000
11000000 10101000 00000000 00000000
11000000 10101000 00000001 00000000
11000000 10101000 00000001 00000001
这是二进制,转换成16进制就是
c0 00 00 00
c0 a8 00 00
c0 a8 01 00
c0 a8 01 01
就是这样的原理,取出来也很简单,只要使用

$num & 0xff000000;
$num & 0x00ff0000;
$num & 0x0000ff00;
$num & 0x000000ff;

便可以取出对应的位来

其实,它本质上的一个思想就是将一个数当成一个容器,放入其他的数进去,这种方法在底层很常见,例如用c、c++编写很常见,php就比较少见了

你可能会有疑问,使用(int)$v过后的数据不应该是10进制吗?怎么就变成了16进制?或者二进制?
其实在最底层,一切的数据都是二进制的,所谓的十进制、十六进制、八进制,只不过是方便人类读写的罢了,计算机只认二进制

如果你对这方面有兴趣,建议看看汇编、计算机组成原理之类的相关数据。

祝好!