无法选择ip = inet

编程入门 行业动态 更新时间:2024-10-25 18:36:32
本文介绍了无法选择ip = inet_pton($ ip)的位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我在数据库中有一个唯一的列,名为ip

I have a unique column in database which is named ip

使用PHP函数转换IP地址后,IP地址将以BINARY(16)的形式存储在此列中(不带排序规则)

IP addresses are stored in this column as BINARY(16) (with no collation) after converting them using the PHP function

$store_ip = inet_pton($ip);

当我尝试两次插入相同的IP时,它可以正常工作,并且因为它是唯一的而失败,

When I try to insert the same IP twice it works fine and fails because it is unique,

但是,当我尝试选择IP时不起作用,并且总是返回FALSE(未找到)

But when I try to select the IP it doesn't work and always returns FALSE (not found)

<?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).

First the fix, which is quite simple: If you want to store both, IPv4 and IPv6 addresses, you should use VARBINARY(16) instead of BINARY(16).

现在出现问题:为什么BINARY(16)无法正常工作?

Now to the problem: Why doesn't it work as expected with BINARY(16)?

考虑一下,我们有一个只有一个列ip BINARY(16) PRIMARY KEY的表ips. 我们将默认的本地IPv4地址存储为

Consider we have a table ips with only one column ip BINARY(16) PRIMARY KEY. We store the default local IPv4 address with

$stmt = $db->prepare("INSERT INTO ips(ip) VALUES(?)"); $stmt->execute([inet_pton('127.0.0.1')]);

,然后在数据库中找到以下值:

and find the following value in the database:

0x7F000001000000000000000000000000

如您所见-这是一个4字节的二进制值(0x7F000001) 右填充零以适合16字节固定长度的列.

As you see - It's a 4 byte binary value (0x7F000001) right-padded with zeros to fit the 16 byte fixed-length column.

当您现在尝试使用

$stmt = $db->prepare("SELECT * FROM ips WHERE ip = ?"); $stmt->execute([inet_pton('127.0.0.1')]);

发生以下情况: PHP发送值0x7F000001作为参数,然后将其进行比较 与存储的值0x7F000001000000000000000000000000. 但是由于两个不同长度的二进制值永远不会相等, WHERE条件将始终返回FALSE. 您可以尝试使用

the following happens: PHP sends the value 0x7F000001 as parameter which is then compared with the stored value 0x7F000001000000000000000000000000. But since two binary values of different length are never equal, the WHERE condition will always return FALSE. You can try it with

SELECT 0x00 = 0x0000

,它将返回0(FALSE).

which will return 0 (FALSE).

注意:对于固定长度的非二进制字符串(CHAR(N)),其行为是不同的.

Note: The behavior is different for fixed length non binary strings (CHAR(N)).

我们可以使用显式强制转换作为解决方法:

We could use explicit casting as a workaround:

$stmt = $db->prepare("SELECT * FROM ips WHERE ip = CAST(? as BINARY(16))"); $stmt->execute([inet_pton('127.0.0.1')]);

,它将找到该行.但是如果我们看看我们得到了什么

and it will find the row. But if we look at what we get

var_dump(inet_ntop($stmt->fetch(PDO::FETCH_OBJ)->ip));

我们将会看到

string(8) "7f00:1::"

但这不是(确实)我们尝试存储的内容. 当我们现在尝试存储7f00:1::时, 我们将收到一个重复键错误, 尽管我们尚未存储任何IPv6地址.

But that is not (really) what we have tried to store. And when we now try to store 7f00:1::, we will get a duplicate key error, though we have never stored any IPv6 address yet.

因此再次:使用VARBINARY(16),您可以使代码保持不变. 如果您存储许多IPv4地址,甚至可以节省一些存储空间.

So once again: Use VARBINARY(16), and you can keep your code untouched. You will even save some storage, if you store many IPv4 addresses.

更多推荐

无法选择ip = inet

本文发布于:2023-10-19 14:37:32,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1507820.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:ip   inet

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!