在MySQL中存储IPv6地址

在MySQL中存储IPv6地址,mysql,sql,Mysql,Sql,正如“”中所要求的,目前没有用于存储IPv6地址的MySQL函数。建议存储/插入的数据类型/功能是什么?(我不打算将它们存储为字符串)。我也不想将IPv6地址分成两个整数。如何: BINARY(16) 这应该足够有效 目前,MySQL服务器中没有将文本IPv6地址从/转换为二进制的功能,如该错误报告中所述。您可能需要在应用程序中执行此操作,也可能需要在MySQL服务器中创建一个UDF(用户定义函数)来执行此操作 更新: MySQL 5.6.3支持IPv6地址,请参见以下内容:“” 数据类型是V

正如“”中所要求的,目前没有用于存储IPv6地址的MySQL函数。建议存储/插入的数据类型/功能是什么?(我不打算将它们存储为字符串)。我也不想将IPv6地址分成两个整数。

如何:

BINARY(16)
这应该足够有效

目前,MySQL服务器中没有将文本IPv6地址从/转换为二进制的功能,如该错误报告中所述。您可能需要在应用程序中执行此操作,也可能需要在MySQL服务器中创建一个UDF(用户定义函数)来执行此操作

更新:

MySQL 5.6.3支持IPv6地址,请参见以下内容:“”

数据类型是
VARBINARY(16)
,而不是我前面建议的
BINARY(16)
。唯一的原因是MySQL函数同时适用于IPv6和IPv4地址
BINARY(16)
可以只存储IPv6地址并保存一个字节<在处理IPv6和IPv4地址时,应使用code>VARBINARY(16)


对于MySQL和MariaDB的旧版本的实现,请参见以下内容:“。

没有人给出完整的工作答案(许多示例使用Windows
::1
,这对于实时(或“生产”)环境可能会产生非常大的误导)任何地方(至少我可以找到),因此:

  • 用于存储的格式
  • 示例
    INSERT
    使用相当复杂的IPv6 IP地址进行查询
  • 示例
    选择
    查询您将能够
    回显
    IPv6 IP地址到客户端
  • 故障排除以确保您没有遗漏任何遗留代码
  • 我将所有列名更改为
    ipv6
    ,以反映它们正确地支持ipv6(这允许您保持旧列
    ip
    不变)。可以将
    ip
    列存储在
    ipv6
    列中,然后在确定转换工作正常后,只
    DROP
    ip列;当我真的有时间的时候,我会把它添加到这篇文章中

    IPv6数据类型

    如前所述,
    VARBINARY 16
    是一种理想的方式,直到AMD允许我们使用128位CPU,并且数据库更新为支持128位整数(我说得对吗?)。IPv6是128位,而不是64位

    CREATE TABLE `example`
    (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `ipv6` VARBINARY(16) NOT NULL,
    PRIMARY KEY (`id`)
    )
    COLLATE='utf8mb4_unicode_520_ci'
    ENGINE=InnoDB;
    

    IPv6插入查询

    显然,我们需要先存储一个IPv6 IP地址,然后才能
    选择它;以下是PHP/SQL代码:

    $ipv6 = mysqli_real_escape_string($db,'FE80:0000:0000:0000:0202:B3FF:FE1E:8329');
    $query1 = "INSERT INTO example (ipv6) VALUES (INET6_ATON('$ipv6'));";
    
    $ipv6 = mysqli_real_escape_string($db,'FE80:0000:0000:0000:0202:B3FF:FE1E:8329');
    $query2 = "SELECT INET6_NTOA(ipv6) AS ipv6 FROM example WHERE ipv6=INET6_ATON('$ipv6');";
    

    IPv6选择查询

    PHP/SQL代码:

    $ipv6 = mysqli_real_escape_string($db,'FE80:0000:0000:0000:0202:B3FF:FE1E:8329');
    $query1 = "INSERT INTO example (ipv6) VALUES (INET6_ATON('$ipv6'));";
    
    $ipv6 = mysqli_real_escape_string($db,'FE80:0000:0000:0000:0202:B3FF:FE1E:8329');
    $query2 = "SELECT INET6_NTOA(ipv6) AS ipv6 FROM example WHERE ipv6=INET6_ATON('$ipv6');";
    
    这将返回
    fe80::202:b3ff:fe1e:8329
    ;不,不是完整的IPv6(它是
    FE80:0000:0000:0000:0202:B3FF:FE1E:8329
    ),它是压缩/速记版本。有代码使其成为正式的完整版本,但这是为了节省我和其他人的时间,因为这个Q/A是不断出现的

    重要提示:仅仅因为某些IPv6地址看起来适合
    bigint
    并不意味着两分钟后,拥有更大IPv6地址的人不会路过这里,造成严重破坏

    希望这能让一些人不再疯狂地打开另外24个标签。当我将来有时间时,我将添加额外的PHP代码,将压缩的IPv6扩展为完整的正式格式


    故障排除

    如果出于某种原因,存储和/或检索IPv6地址对您不起作用,那么为自己准备一份(在Wine中的工作速度比Linux本机的
    grep
    更快);主要用于查找,而不是替换。确保您的代码在软件中的任何地方都是一致的

    • 所有
      $ip
      变量都必须转换为
      $ipv6
      ,这样您就知道已经涵盖了该位
    • 在接下来的四个步骤中,不要忘记删除结尾
    • 搜索PHP
      inet\u pton(
      函数)的所有实例并删除它们
    • 搜索PHP
      inet\u ntop(
      函数)的所有实例并删除它们
    • 搜索SQL
      INET\u ATON(
      函数)的所有实例并将其删除
    • 搜索SQL
      INET\u NTOA(
      函数)的所有实例并将其删除
    • 搜索
      $ipv6
      的所有实例,并确保所有IP-IN-TO-SQL实例都使用
      INET6\u-ATON(“$ipv6”)
      ,并且所有IP-FROM-SQL的实例都使用
      INET6\u-NTOA(ipv6)作为ipv6
    • 搜索
      $row1['ip']
      的所有实例,并将其替换为
      $row1['ipv6']
    • 确保
      $ipv6=
      的所有实例都使用以下代码(数据库对象引用已更改):
      $ipv6=(isset($\u SERVER['REMOTE\u ADDR'])和&strlen($\u SERVER['REMOTE\u ADDR'])>0)?mysqli\u real\u escape\u字符串($db,$\u SERVER['REMOTE\u ADDR']):mysqli\u real\u escape\u字符串($db,getenv('REMOTE ADDR'))
    • 如果您在开始调试之前意识到有问题,请确保您的测试使用新测试的IP地址,而不是潜在的错误版本

      • 很好的例子,但我注意到以下几点。 只有当一个版本的
        mysql
        具有
        INET6\u ATON
        的as函数时,这才有效。
        否则,错误消息可能是这样的:该
        函数
        不存在
        可能是完美时间的重复!在我发布问题后大约一个月:PYou是正确的,我的vesion真的很旧,没有那种能力:(14.14发行版5.1.41版)