我在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'];
答案 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);
}