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?
Advertisement
Answer
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