【问题标题】:Anonymize IPv4 and IPv6 addresses with PHP preg_replace?使用 PHP preg_replace 匿名 IPv4 和 IPv6 地址?
【发布时间】:2018-07-23 20:34:16
【问题描述】:

我需要匿名化 IPv4 和 IPv6 地址,所以我编写了这个粗略的解决方案:

if (strlen($_SERVER['REMOTE_ADDR']) <= 15) {  // Sorry: 15 NOT 12
    echo htmlentities(substr_replace($_SERVER['REMOTE_ADDR'], 'XXX', -3), ENT_QUOTES);
} else {
    echo htmlentities(substr_replace($_SERVER['REMOTE_ADDR'], 'XXXX:XXXX', -9), ENT_QUOTES);
}

它适用于全长 IPv4 和 IPv6 地址,例如

207.142.131.005

2001:0db8:0000:08d3:0000:8a2e:0070:7344

但不能使用缩写地址,例如

207.142.131.5

2001:0db8::8d3::8a2e:7:7344

我想知道 preg_replace 和一些正则表达式魔术是否有一个优雅的解决方案?

【问题讨论】:

  • preg_replace('/^.*$/', 'ANONYMOUS', $_SERVER['REMOTE_ADDR']) 将用 "ANONYMOUS" 替换所有内容......可能不是你想要的,但它符合简短:P
  • 顺便说一下 localhost 是 ::1 肯定少于 12 个字符,所以 strlen 可能不是区分 v4 和 v6 的最佳方法
  • 不需要htmlentities()。 IP 地址仅包含数字 (0..9) 和点 (.) (IPv4) 或十六进制数字 (0..9, a..f)和冒号 (:) (IPv6)。这些字符在 HTML 中并不特殊,htmlentities() 返回未修改的输入字符串。
  • 确实,你不能只看长度。例如,全球 IPv6 地址2600:: 是有效的,并且是 Internet 上的路由器。

标签: php regex preg-replace ipv6 ipv4


【解决方案1】:

你可以试试:

$string = $_SERVER['REMOTE_ADDR'];
if (strlen($string) <= 12) {
    echo htmlentities(preg_replace('/(\d+\.\d+.\d+.)(\d+)/', "$1XXX",  $string), ENT_QUOTES);
} else {
    echo htmlentities(preg_replace('/((?:[0-9a-f]+:){6})(\w+:\w+)/', "$1XXXX:XXXX", $string), ENT_QUOTES);
}

【讨论】:

  • 兄弟,请注意,有一些语法错误,$string 未在您的 sn-p 中定义。
【解决方案2】:

不使用正则表达式,你可以通过.:相应地分解并替换最后两部分:

<?php
function anonIp($ip)
{
    if (strpos($ip, ".") !== false) { // detect IP type by dots instead of length
        $pieces = explode(".", $ip);
        $nPieces = count($pieces);
        $pieces[$nPieces - 1] = $pieces[$nPieces - 2] = "XXX";
        return implode(".", $pieces);
    } else {
        $pieces = explode(":", $ip);
        $nPieces = count($pieces);
        $pieces[$nPieces - 1] = $pieces[$nPieces - 2] = "XXXX";
        return implode(":", $pieces);
    }
}
var_dump(anonIp("207.142.131.005")); // 207.142.XXX.XXX
var_dump(anonIp("2001:0db8:0000:08d3:0000:8a2e:0070:7344")); // 2001:0db8:0000:08d3:0000:8a2e:XXXX:XXXX
var_dump(anonIp("207.142.131.5")); // 207.142.XXX.XXX
var_dump(anonIp("2001:0db8::8d3::8a2e:7:7344")); // 2001:0db8::8d3::8a2e:XXXX:XXXX
var_dump(anonIp("::1")); // :XXXX:XXXX
var_dump(anonIp("127.0.0.1")); // 127.0.XXX.XXX

Demo

虽然我确信有一些晦涩的(或不是很多)情况会破坏它,但请务必先对其进行彻底的测试。

【讨论】:

    【解决方案3】:

    正则表达式[0-9]+$ and [0-9]*:[0-9]+$\d+$\d*:\d+$

    详情:

    • $ 在行尾断言位置
    • [] 匹配列表中存在的单个字符
    • + 匹配一次到无限次
    • * 匹配零次和无限次

    PHP 代码

    function mask($ip)
    {
      if (strpos($ip, ".") == true) {
        print_r(preg_replace('~[0-9]+$~', 'XXX', $ip) . "\n");
      } else {
        print_r(preg_replace('~[0-9]*:[0-9]+$~', 'XXXX:XXXX', $ip) . "\n");
      }
    }
    

    输出:

    207.142.131.XXX
    207.142.131.XXX
    2001:0db8:0000:08d3:0000:8a2e:XXXX:XXXX
    2001:0db8::8d3::8a2e:XXXX:XXXX
    :XXXX:XXXX
    

    Code demo

    【讨论】:

      【解决方案4】:

      不需要条件。您可以为单个 preg_replace() 调用编写两个模式和两个替换来处理。

      将字符串中最后一个文字点之后的可选数字作为替换目标。然后定位字符串末尾的字母数字冒号分隔的子字符串。

      代码:(Demo)

      $tests = [
          "207.142.131.005",
          "2001:0db8:0000:08d3:0000:8a2e:0070:7344",
          "2001:0db8:0000:08d3:0000:8a2e:0070:734a",
          "207.142.131.5",
          "2001:0db8::8d3::8a2e:7:7344",
          "::1",
          "127.0.0.1"
      ];
      
      $tests = preg_replace(
                   ['/\.\d*$/', '/[\da-f]*:[\da-f]*$/'],
                   ['.XXX', 'XXXX:XXXX'],
                   $tests
               );
      
      var_export($tests);
      

      输出:

      array (
        0 => '207.142.131.XXX',
        1 => '2001:0db8:0000:08d3:0000:8a2e:XXXX:XXXX',
        2 => '2001:0db8:0000:08d3:0000:8a2e:XXXX:XXXX',
        3 => '207.142.131.XXX',
        4 => '2001:0db8::8d3::8a2e:XXXX:XXXX',
        5 => ':XXXX:XXXX',
        6 => '127.0.0.XXX',
      )
      

      模式说明:

      IPv4:

      /         #Pattern delimiter
      \.        #Match dot literally
      \d*       #Match zero or more digits
      $         #Match the end of the string
      /         #Pattern delimiter
      

      IPv6

      /         #Pattern delimiter
      [\da-f]*  #Match zero or more (digits or a b c d e f)
      :         #Match colon
      [\da-f]*  #Match zero or more (digits or a b c d e f)
      $         #Match the end of the string
      /         #Pattern delimiter
      

      【讨论】:

        猜你喜欢
        • 2011-08-31
        • 2011-11-09
        • 1970-01-01
        • 1970-01-01
        • 2023-04-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-18
        相关资源
        最近更新 更多