I needed to anonymize IPv4 and IPv6 addresses so I coded this crude solution:
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);
}
It works fine with full length IPv4 and IPv6 addresses like
207.142.131.005
2001:0db8:0000:08d3:0000:8a2e:0070:7344
but not with abbreviated addresses like
207.142.131.5
2001:0db8::8d3::8a2e:7:7344
I wonder if there is an elegant solution with preg_replace and some regular expression magic?
No conditional is necessary. You can write two patterns and two replacements for a single preg_replace()
call to process.
Target the optional numbers after the last literal dot in the string for replacement. Then target the alphanumeric colon-delimited substrings at the end of the string.
Code: (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);
Output:
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',
)
Pattern Explanations:
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