起初,我以为strpos()
on @
会给我地址的“本地”部分的长度,我可以使用substr_replace()
简单地注入星号但是一个有效的电子邮件地址可以有多个@在当地的部分 https://stackoverflow.com/a/38787343/2943403并且多字节支持是任何实际项目的必要内容。这意味着mb_strpos()
将是一个充分的替代品strpos()
,但还没有本地人mb_substr_replace()
php 中的函数,因此设计非正则表达式片段的卷积变得越来越没有吸引力。
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 [email protected] /cdn-cgi/l/email-protection
and [email protected] /cdn-cgi/l/email-protection
as preliminary unit tests.
我要遵循的代码片段不会验证电子邮件地址;假设您的项目将使用适当的方法来验证地址,然后再允许它进入您的系统。该代码片段的强大功能/实用性在于它是多字节安全的,并且它将在所有情况下添加星号,并且当本地部分中只有一个字符时,前导字符会在@
这样变异的地址就更难猜测了。哦,为了更简单的维护,要添加的星号数量被声明为变量。
Code: (Demo https://3v4l.org/7mM1A) (PHP7.4+ 演示 https://3v4l.org/j3Dj3) (正则表达式演示 https://regex101.com/r/ZnVE6r/1)
$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
);
输入输出:
'[email protected] /cdn-cgi/l/email-protection' => 'a****[email protected] /cdn-cgi/l/email-protection',
'[email protected] /cdn-cgi/l/email-protection' => 'a****[email protected] /cdn-cgi/l/email-protection',
'[email protected] /cdn-cgi/l/email-protection' => 'a****[email protected] /cdn-cgi/l/email-protection',
'[email protected] /cdn-cgi/l/email-protection' => 'a****[email protected] /cdn-cgi/l/email-protection',
'[email protected] /cdn-cgi/l/email-protection' => 'a****[email protected] /cdn-cgi/l/email-protection',
'[email protected] /cdn-cgi/l/email-protection' => 'a****[email protected] /cdn-cgi/l/email-protection',
'[email protected] /cdn-cgi/l/email-protection' => 'a*****[email protected] /cdn-cgi/l/email-protection',
'Ф@example.com' => 'Ф****Ф@example.com',
'ФѰ@example.com' => 'Ф****Ѱ@example.com',
'ФѰД@example.com' => 'Ф****Д@example.com',
'ФѰДӐӘӔӺ@example.com' => 'Ф*****Ӻ@example.com',
'"a@tricky@one"@example.com' => '"************"@example.com',
正则表达式解释:
/ #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
回调说明:
-
$m[1]
第一个字符(捕获组#1)
-
str_repeat("*", max($minFill, mb_strlen($m[2], 'UTF-8')))
使用以下命令测量捕获组 #2 的多字节长度UTF-8
编码,然后使用计算出的长度和声明的长度之间的较高值$minFill
,然后重复该字符*
从返回的次数max()
call.
-
($m[3] ?: $m[1])
之前的最后一个字符@
(捕获组#3);如果元素为空$m
数组,然后使用第一个元素的值——它将始终被填充。