php - 无法选择 ip=inet_pton($ip) 的位置
问题描述
我在数据库中有一个名为的唯一列ip
BINARY(16)
IP 地址在使用 PHP 函数转换后存储在此列中(没有排序规则)
$store_ip = inet_pton($ip);
当我尝试两次插入相同的 IP 时,它工作正常,但由于它是唯一的而失败,
但是当我尝试选择 IP 它不起作用并且总是返回 FALSE(未找到)
<?php
try {
$ip = inet_pton($_SERVER['REMOTE_ADDR']);
$stmt = $db->prepare("SELECT * FROM `votes` WHERE ip=?");
$stmt->execute([$ip]);
$get = $stmt->fetch();
if( ! $get){
echo 'Not found';
}else{
echo 'Found';
}
// close connection
$get = null;
$stmt = null;
} catch (PDOException $e) {
error_log($e->getMessage());
}
我插入IP的部分:
<?php
if( ! filter_var($ip, FILTER_VALIDATE_IP)){
return FALSE;
}
$ip = inet_pton($_SERVER['REMOTE_ADDR']);
try {
$stmt = $db->prepare("INSERT INTO votes(ip, answer) VALUES(?,?)");
$stmt->execute([$ip, $answer]);
$stmt = null;
} catch (PDOException $e) {
return FALSE;
}
解决方案
首先修复,这很简单:如果你想同时存储 IPv4 和 IPv6 地址,你应该使用VARBINARY(16)
而不是BINARY(16)
.
现在问题来了:为什么它不能按预期工作BINARY(16)
?
考虑我们有一个ips
只有一列的表ip BINARY(16) PRIMARY KEY
。我们将默认的本地 IPv4 地址存储为
$stmt = $db->prepare("INSERT INTO ips(ip) VALUES(?)");
$stmt->execute([inet_pton('127.0.0.1')]);
并在数据库中找到以下值:
0x7F000001000000000000000000000000
如您所见 - 它是一个 4 字节二进制值 ( 0x7F000001
),右填充零以适合 16 字节固定长度列。
当你现在尝试用
$stmt = $db->prepare("SELECT * FROM ips WHERE ip = ?");
$stmt->execute([inet_pton('127.0.0.1')]);
发生以下情况:PHP 将值0x7F000001
作为参数发送,然后与存储的值进行比较0x7F000001000000000000000000000000
。但由于两个不同长度的二进制值永远不相等,WHERE 条件总是返回 FALSE。你可以试试
SELECT 0x00 = 0x0000
这将返回0
(FALSE)。
注意:对于固定长度的非二进制字符串 ( CHAR(N)
),行为是不同的。
我们可以使用显式转换作为解决方法:
$stmt = $db->prepare("SELECT * FROM ips WHERE ip = CAST(? as BINARY(16))");
$stmt->execute([inet_pton('127.0.0.1')]);
它会找到该行。但是如果我们看看我们得到了什么
var_dump(inet_ntop($stmt->fetch(PDO::FETCH_OBJ)->ip));
我们会看到
string(8) "7f00:1::"
但这不是(真的)我们试图存储的东西。当我们现在尝试存储时7f00:1::
,我们会得到一个重复密钥错误,尽管我们还没有存储任何 IPv6 地址。
所以再一次:使用VARBINARY(16)
,你可以保持你的代码不变。如果您存储许多 IPv4 地址,您甚至可以节省一些存储空间。
推荐阅读
- mysql - 我写了一个查询,它给出了正确的数据集,但不知道为什么它没有被接受?
- java - 如何在 Spring 中模拟 ModelMapper?
- python - Python z-score 用平均值或其他值替换
- javascript - 滚动时更改导航栏
- arrays - Dafny reads 子句读取数组元素不足
- julia - 数组和向量之间的区别
- data-structures - 为什么只有当插入节点的叔叔是黑色时才旋转红黑树?有人可以解释其属性背后的逻辑吗?
- docker - 容器启动并运行 - 无法在 Web 浏览器中提供文件 - Docker
- python - 为什么在使用 execl() 时出现“execv(file, args)”错误?
- python-3.x - Python 3 中的文本模式匹配