PHP inet_ntop()在真实VPS上的表现不同

时间:2015-06-12 21:42:40

标签: php

我在VPS上部署了我的应用程序,它正常工作,期待inet_ntop()功能。在我的本地Web服务器上,它运行正常,没有错误消息。

我将IP地址存储在binary(16)列中。在我将它们存储到数据库之前,我将它们转换。我上次登录的IP是:4e43b7,二进制数:00110100 01100101 00110100 00110011 01100010 00110111和可读格式:78.92.67.183。因此它在VPS上运行警告消息:Warning: inet_ntop(): Invalid in_addr value in home/...

出了什么问题?根据PHP文档,该函数适用于PHP 5.1或更高版本,VPS有5.5,但我使用的是5.6。版本差异会导致问题吗?此行会导致警告:

$ip = inet_ntop($datas['ip_address'];

2 个答案:

答案 0 :(得分:2)

根据manual

  

当存储BINARY值时,它们用填充值右填充到指定的长度。填充值为0x00(零字节)。

因此您不会拔出32位IPv4地址。您正在提取16x8bit = 128bit的值,并将其提供给inet_ntop()。

答案 1 :(得分:1)

正如Marc B所说,你的BINARY列正在用零填充,然后丢弃你的解码。这不是处理这种问题的超级好方法,尤其是在MySQL中。

但是,IPv6有一种内置的封装IPv4地址的方法6to4。使用此功能,您可以以可维护且易于处理的方式并排存储v4和v6地址。

function fourToSix($addr) {
    $haddr = str_pad(dechex(ip2long($addr)), 8, '0', STR_PAD_LEFT);
    $v6 = sprintf('2002:%s::', implode(':', str_split($haddr, 2)));
    return $v6;
}

function sixToFour($addr) {
    return long2ip(hexdec(implode('', array_slice(explode(':', $addr), 1, 4))));
}

function isSixToFour($addr) {
    return explode(':', $addr)[0] == '2002';
}

$v4 = '10.1.2.3';
$v6 = '2002:0a:01:02:03::';
var_dump(
    fourToSix($v4),
    isSixToFour($v6),
    sixToFour($v6),
    bin2hex(inet_pton($v6))
);

输出:

string(18) "2002:0a:01:02:03::"
bool(true)
string(8) "10.1.2.3"
string(32) "2002000a000100020003000000000000"

修改

商店示例:

$stmt = $dbh->prepare('INSERT INTO table (id, addr) VALUES(?, ?);');
// convert IP if it is v4
if( ip2long($ip_addr) !== false ) {
    $ip_addr = fourToSix($ip_addr);
}
$stmt->execute(1, inet_pton($ip_addr));

检索示例:

$addr_raw = $dbh->query('SELECT addr FROM table WHERE id=1')->fetch(PDO::FETCH_ASSOC)['addr'];

$addr_str = inet_ntop($addr_raw);
if( isSixToFour($addr_str) ) {
    printf("IPv4 address is: %s\n", sixToFour($addr_str));
} else {
    printf("IPv6 address is: %s\n", $addr_str);
}