使用 PHP preg_replace 匿名化 IPv4 和 IPv6 地址?
Anonymize IPv4 and IPv6 addresses with PHP preg_replace?
我需要匿名化 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 和一些正则表达式魔术的优雅解决方案?
你可以试试:
$string = $_SERVER['REMOTE_ADDR'];
if (strlen($string) <= 12) {
echo htmlentities(preg_replace('/(\d+\.\d+.\d+.)(\d+)/', "XXX", $string), ENT_QUOTES);
} else {
echo htmlentities(preg_replace('/((?:[0-9a-f]+:){6})(\w+:\w+)/', "XXXX:XXXX", $string), ENT_QUOTES);
}
不使用正则表达式,可以根据.
或:
展开,替换最后两块:
<?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
尽管我确信在某些模糊(或不那么多)的情况下这会中断,所以一定要先对其进行彻底的测试。
正则表达式:[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
不需要条件。您可以为单个 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
我需要匿名化 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 和一些正则表达式魔术的优雅解决方案?
你可以试试:
$string = $_SERVER['REMOTE_ADDR'];
if (strlen($string) <= 12) {
echo htmlentities(preg_replace('/(\d+\.\d+.\d+.)(\d+)/', "XXX", $string), ENT_QUOTES);
} else {
echo htmlentities(preg_replace('/((?:[0-9a-f]+:){6})(\w+:\w+)/', "XXXX:XXXX", $string), ENT_QUOTES);
}
不使用正则表达式,可以根据.
或:
展开,替换最后两块:
<?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
尽管我确信在某些模糊(或不那么多)的情况下这会中断,所以一定要先对其进行彻底的测试。
正则表达式:[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
不需要条件。您可以为单个 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