应该使用哪种MySQL数据类型来存储IP地址?

103

我想从$_SERVER['REMOTE_ADDR']和其他一些$_SERVER变量中获取IP地址,哪种数据类型是正确的?

VARCHAR(n)吗?

可能重复:
如何在MySQL中存储IP


请查看此讨论 - Ragnar123
16
我不同意这是一个重复的问题,因为另一个问题具体针对存储大量IP地址的性能问题。那个问题的答案对于不关心最大化空间利用或性能的人可能不相关。 - User
@用户 我大约一年半前曾经问过这个问题;) 但感谢您分享您的观点。 - ComFreek
4
尽管这个问题可能是一个重复的问题,但我在这里找到了更好的答案。那些将其标记为重复的人让我浪费了时间。:-P - Pathros
1
有人能否取消这个问题的重复标记?真正的答案在这个问题中。 - theking2
感觉每次我搜索 Stack Overflow 上的每三个答案,顶部结果都是“[重复]”。我认为有些人喜欢关闭问题,不管这是否正确并不重要。 - Glenn Maynard
3个回答

158

由于IPv4地址长度为4字节,因此可以使用恰好为4字节的INT (UNSIGNED)

`ipv4` INT UNSIGNED

使用INET_ATONINET_NTOA函数进行转换:

INSERT INTO `table` (`ipv4`) VALUES (INET_ATON("127.0.0.1"));
SELECT INET_NTOA(`ipv4`) FROM `table`;

对于IPv6地址,您可以使用BINARY代替:

`ipv6` BINARY(16)

使用PHP的inet_ptoninet_ntop进行转换:

'INSERT INTO `table` (`ipv6`) VALUES ("'.mysqli_real_escape_string(inet_pton('2001:4860:a005::68')).'")'
'SELECT `ipv6` FROM `table`'
$ipv6 = inet_pton($row['ipv6']);

9
5.1版本的语法应为INT UNSIGNED,而不是UNSIGNED INT。 - Vinko Vrsalovic
1
通过建议的方法 - 如何查找具有匹配子网的地址? - Alexander Farber
1
@AlexanderFarber 检查IP是否在子网中 - Gumbo
1
如果它可以是两者之一呢? - Jeff Davis
1
新更新:INET6_ATON() 用于IPV6,INET6_NTOA() - user5890979
当以二进制格式存储时,使用INET6_NTOA()和INET6_ATON()来存储IPv6地址 - 使用HEX()和UNHEX()以提高可读性。如果您基于IP地址获取某些内容,请确保在此列上使用索引,并且查询实际上在执行过程中使用该索引 - 在此处检查http://www.rathishkumar.in/2017/08/how-to-store-ip-address-in-mysql.html - Rathish Kumar B

57
你有两种选择(用于IPv4地址):
1. 使用varchar(15),如果你想将IP地址存储为字符串 - 例如:192.128.0.15 2. 使用integer(4字节),如果你将IP地址转换为整数 - 例如:3229614095,这是我之前使用的IP地址
第二个解决方案在数据库中需要更少的空间,可能是一个更好的选择,即使在存储和检索数据时需要进行一些操作(将其转换为/从字符串)。
关于这些操作,请参考PHP端的`ip2long()`和`long2ip()`函数,或者MySQL端的`inet_aton()`和`inet_ntoa()`函数。

但是我听说在 $_SERVER['REMOTE_ADDR'] 中它也可以是一个IPv6地址。那么我该如何将类似 xxx.xx.xx.xxx 的内容转换为像你所说的整数(4个字节)呢? - ComFreek
1
对于 IPv6 地址,您将需要超过 4 个字节 -- https://secure.wikimedia.org/wikipedia/en/wiki/IPv6 表示它使用 128 位,因此需要 16 个字节 ;; 在 PHP 中,请参阅 http://fr2.php.net/manual/en/function.inet-pton.php - Pascal MARTIN
16字节的数据类型应该选择哪种? - ComFreek
1
考虑到整数数据类型都不超过8个字节(请参见http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html),我认为您将不得不回退到某种基于字符的类型。 - Pascal MARTIN
@ComFreek或其他看到这条消息的人,192256256256 + 128256*256 + 15 = 3229614095。 - Saurabh Rana
BINARY(128) 可用于存储 IPv6 地址。 - Ether

5

对于IPv4地址,您可以使用VARCHAR将它们存储为字符串,但也可以考虑将它们存储为长整数 INT(11) UNSIGNED。 您可以使用MySQL的INET_ATON()函数将它们转换为整数表示形式。 这样做的好处是可以轻松地进行比较,例如BETWEEN查询。

INET_ATON() MySQL函数


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接