I have this mail address
abcedf@example.com
.
How to convert it into this mail address
a****f@example.com
I tried using strpos
and get @
but I cannot get middle values and change it to ****
.
At first, I thought that strpos()
on @
would get me the length of the "local" part of the address and I could use substr_replace()
to simply inject the asterisks BUT a valid email address can have multiple @
in the local part AND multibyte support is a necessary inclusion for any real-world project. This means that mb_strpos()
would be an adequate replacement for strpos()
, but there isn't yet a native mb_substr_replace()
function in php, so the convolution of devising a non-regex snippet became increasingly unattractive.
If you want to see my original answer, you can check the edit history, but I no longer endorse its use. My original answer also detailed how other answers on this page fail to obfuscate email addresses which have 1 or 2 characters in the local substring. If you are considering using any other answers, but sure to test against a@example.com
and ab@example.com
as preliminary unit tests.
My snippet to follow DOES NOT validate an email address; it is assumed that your project will use appropriate methods to validate the address before bothering to allow it into your system. The power/utility of this snippet is that it is multibyte-safe and it will add asterisks in all scenarios and when there is only a single character in the local part, the leading character is repeated before the @
so that the mutated address is harder to guess. Oh, and the number of asterisks to be added is declared as a variable for simpler maintenance.
Code: (Demo) (PHP7.4+ Demo) (Regex Demo)
$minFill = 4;
echo preg_replace_callback(
'/^(.)(.*?)([^@]?)(?=@[^@]+$)/u',
function ($m) use ($minFill) {
return $m[1]
. str_repeat("*", max($minFill, mb_strlen($m[2], 'UTF-8')))
. ($m[3] ?: $m[1]);
},
$email
);
Input/Output:
'a@example.com' => 'a****a@example.com',
'ab@example.com' => 'a****b@example.com',
'abc@example.com' => 'a****c@example.com',
'abcd@example.com' => 'a****d@example.com',
'abcde@example.com' => 'a****e@example.com',
'abcdef@example.com' => 'a****f@example.com',
'abcdefg@example.com' => 'a*****g@example.com',
'Ф@example.com' => 'Ф****Ф@example.com',
'ФѰ@example.com' => 'Ф****Ѱ@example.com',
'ФѰД@example.com' => 'Ф****Д@example.com',
'ФѰДӐӘӔӺ@example.com' => 'Ф*****Ӻ@example.com',
'"a@tricky@one"@example.com' => '"************"@example.com',
Regex-planation:
/ #pattern delimiter
^ #start of string
(.) #capture group #1 containing the first character
(.*?) #capture group #2 containing zero or more characters (lazy, aka non-greedy)
([^@]?) #capture group #3 containing an optional single non-@ character
(?=@[^@]+$) #require that the next character is @ then one or more @ until the end of the string
/ #pattern delimiter
u #unicode/multibyte pattern modifier
Callback explanation:
$m[1]
str_repeat("*", max($minFill, mb_strlen($m[2], 'UTF-8')))
UTF-8
encoding, then use the higher value between that calculated length and the declared $minFill
, then repeat the character *
the number of times returned from the max()
call.($m[3] ?: $m[1])
@
(capture group #3); if the element is empty in the $m
array, then use the first element's value -- it will always be populated.For anyone seeking a less sophisticated approach, the following preg_replace()
call will replace the local part of the email from the second (non-last) character to the second-last (non-first) charcter in a 1-to-1 fashion using the \G
(continue) metacharacter. There are fringe cases where this technique fails to redact any characters -- so use with caution.
echo preg_replace("/(?:^.\K|\G(?!^))[^@](?!@)/u", '*', $email);
Input/Output:
'a@example.com' => 'a@example.com', // not good
'ab@example.com' => 'ab@example.com', // not good
'abc@example.com' => 'a*c@example.com',
'abcd@example.com' => 'a**d@example.com',
'abcde@example.com' => 'a***e@example.com',
'abcdef@example.com' => 'a****f@example.com',
'abcdefg@example.com' => 'a*****g@example.com',
'Ф@example.com' => 'Ф@example.com', // not good
'ФѰ@example.com' => 'ФѰ@example.com', // not good
'ФѰД@example.com' => 'Ф*Д@example.com',
'ФѰДӐӘӔӺ@example.com' => 'Ф*****Ӻ@example.com',
'"a@tricky@one"@example.com' => '"a@tricky@one"@example.com', // not good