4

我知道这个问题已经被问过很多次了,但我找不到任何最终解决方案;所以这里是:

在不知道数据库的情况下,如何在数据库中使用最佳实践存储 IP(IPv4 和 IPv6)?这以用于 DB 抽象目的,例如 PHP PDO。

顺便说一句,我有 PHP 5.2.17,因为我需要 Windows 上的 PEAR。

人们一直建议将其存储为 varbinary(16) 并使用 mysql 函数 inet6_ntop 和 inet6_pton 将 IP 作为字符串来回传递;就像建议用 IPv6 函数扩展 MySQL 5一样。在 PHP 中,函数 inet_pton() 和 inet_ntop() 可以将 IPv4 和 IPv6 来回转换为二进制格式,正如这个问题中的ThiefMaster所建议的那样,但不清楚如何将二进制内容传递到 SQL INSERT/UPDATE 字符串(以及这些 php 函数仅在 windows 上的 php 5.3.0 中提供,即使可以对这些函数进行逆向工程)。我真的很喜欢Jake所做的事情以及他关于 DB 中 IP 的整数表示的结果,如果我要在我的数据库中实现它,这可能会在某个遥远的、不可预见的未来派上用场,但是我不确定使用 PHP PDO 进行数据库抽象的数据库交叉兼容性。这篇文章似乎提供了一个关于存储二进制值的接近答案,但是未转义的二进制注入字符串不是潜在的危险吗?此外,如果您遵循这条路线,如果某些开发人员想要进行一些快速查找,有多少 DB 可以将 varbinary(16)/int(128bit) 转换为代表性 IP?

在我看来,最简单的方法是将ip 字符串按原样插入到varchar(45)中。但是那些想要遵循复杂路线的人将如何使用 inet_ntop() 和 inet_pton() 函数在 PHP 中(反向工程为 djmaze(AT)dragonflycms(.)orgFF dot st的 MagicalTux 建议)存储并以二进制形式检索 IPv6?有人可以举一个使用 PDO from 的例子<?php $strIP = "2001:4860:b002::68"; ?>,使用 INSERT 然后 SELECT 准备好的语句吗?

正如你所看到的,我已经完成了我的研究,但这个 IPv6 的最终良好实践对我来说并不清楚。

4

1 回答 1

2

就像您的研究表明,将 IP 地址存储为规范形式的字符串、二进制字符串或整数有好处和问题。也许有一个中间地带将 IP 地址存储在数据库中。

如何将它们存储为字符串,但扩展到最大长度。这样您仍然可以比较它们(==、>、< 等),但它们仍然是可读的,并且您不需要特殊字符的特殊输入和输出编码。

你可以如何做到这一点的一个例子:

function expand_ip_address($addr_str) {
  /* First convert to binary, which also does syntax checking */
  $addr_bin = @inet_pton($addr_str);
  if ($addr_bin === FALSE) {
    return FALSE;
  }

  /* Then differentiate between IPv4 and IPv6 */
  if (strlen($addr_bin) == 4) {
    /* IPv4: print each byte as 3 digits and add dots between them */
    return implode('.', array_map(
      create_function('$byte', 'return sprintf("%03d", ord($byte));'),
      str_split($addr_bin)
    ));
  } else {
    /* IPv6: print as hex and add colons between each group of 4 hex digits */
    return implode(':', str_split(bin2hex($addr_bin), 4));
  }
}

还有一些例子:

/* Test IPv4 */
var_dump(expand_ip_address('192.0.2.55'));

/* Test IPv6 */
var_dump(expand_ip_address('2001:db8::abc'));

/* Test invalid */
var_dump(expand_ip_address('192:0:2:55'));

哪个产品:

string(15) "192.000.002.055"
string(39) "2001:0db8:0000:0000:0000:0000:0000:0abc"
bool(false)
于 2013-01-21T11:49:34.707 回答