3

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 ****.

Top-Master
  • 7,611
  • 5
  • 39
  • 71
Nawin
  • 1,653
  • 2
  • 14
  • 23

7 Answers7

8

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]
    the first character (capture group #1)
  • str_repeat("*", max($minFill, mb_strlen($m[2], 'UTF-8')))
    measure the multibyte length of capture group #2 using 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])
    the last character before the @ (capture group #3); if the element is empty in the $m array, then use the first element's value -- it will always be populated.
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
2

Here is the simple version:

$em = 'abcde@gmail.com'; // 'a****e@gmail.com'
$em = 'abcdefghi@gmail.com'; // 'a*******i@gmail.com'

Using PHP String functions

$stars = 4; // Min Stars to use
$at = strpos($em,'@');
if($at - 2 > $stars) $stars = $at - 2;
print substr($em,0,1) . str_repeat('*',$stars) . substr($em,$at - 1);
Kae Cyphet
  • 185
  • 2
  • 6
1

Regex: ^.\K[a-zA-Z\.0-9]+(?=.@) canbe changed to this ^[a-zA-Z]\K[a-zA-Z\.0-9]+(?=[a-zA-Z]@)

1. ^.\K This will match first character of email and \K will reset the match

2. [a-zA-Z\.0-9]+(?=.@) this will match string and positive look ahead for any character then @

In the second statement of code we are creating same no. of *'s as the no. of characters in match.

In the third statement we are using preg_replace to remove matched string with *'s

Try this code snippet here

<?php
$string='abcedf@gmail.com';
preg_match('/^.\K[a-zA-Z\.0-9]+(?=.@)/',$string,$matches);//here we are gathering this part bced

$replacement= implode("",array_fill(0,strlen($matches[0]),"*"));//creating no. of *'s
echo preg_replace('/^(.)'.preg_quote($matches[0])."/", '$1'.$replacement, $string);

Output: a****f@gmail.com

Dharman
  • 30,962
  • 25
  • 85
  • 135
Sahil Gulati
  • 15,028
  • 4
  • 24
  • 42
1

Late answer but you can use:

$email = "abcdef@gmail.com";
print preg_replace_callback('/(\w)(.*?)(\w)(@.*?)$/s', function ($matches){
    return $matches[1].preg_replace("/\w/", "*", $matches[2]).$matches[3].$matches[4];
}, $email);

# a****f@gmail.com
Pedro Lobito
  • 94,083
  • 31
  • 258
  • 268
0

In certain cases, you would like to show partial email to give users hint about their email id. If you are looking for similar, you can take half characters of email username and replace with certain characters. Here is the PHP function that you can use for your project to hide email address.

<?php
function hide_email($email) {
        // extract email text before @ symbol
        $em = explode("@", $email);
        $name = implode(array_slice($em, 0, count($em) - 1), '@');

        // count half characters length to hide
        $length = floor(strlen($name) / 2);

        // Replace half characters with * symbol
        return substr($name, 0, $length) . str_repeat('*', $length) . "@" . end($em);
}

echo hide_email("contactus@gmail.com");
?>

// Output: cont****@gmail.com

Deepak Rajpal
  • 811
  • 1
  • 8
  • 11
  • 1
    Your answer does not meet the brief described in the question and is therefore incorrect. Please never change the requirements of the question to suit your answer. Imagine if all answerers did this -- the pages would spin out of control. `array_slice($em, 0, count($em) - 1)` is more simply expressed as `array_slice($em, 0, -1)`. Declaring the glue after the array in `implode()` is deprecated in PHP7.4 and generates an Error in PHP8. `floor()` can be replace with a non-functional technique -- cast the value as an int `(int)(strlen($name) / 2)`. – mickmackusa Jul 05 '21 at 10:44
  • @mickmackusa Thanks for the correction. I will try to be precise next time. :) – Deepak Rajpal Jul 30 '21 at 19:21
0

Can help someone.

<?php
echo  hide_mail( "email@example.com.br" );

function hide_mail($email) {
    $hideAfter = 1;
    $mail_part = explode("@", $email);
    $part1 = substr($mail_part[0],0,$hideAfter);
    $part2 = substr($mail_part[0],$hideAfter);
    $part2 = str_repeat("*", strlen($part2));
    $mail_part[0] = $part1.$part2;
    return implode("@", $mail_part);
}
0

I found a simpler solution. Keep in mind, this is not a validation, that would need to be done separately.

$email = 'some-email@gmail.com';

preg_match('/^(.)(.+)([@])(.+)$/i', $email, $matches); 

$matches[2] = preg_replace('/./', '*', $matches[2]);

echo $matches[1] . $matches[2] . $matches[3] . $matches[4];

// output should be s*********@gmail.com.

Here's the link to the page I used. It's fairly simple to use and it has some functions available that you can copy and past.

https://www.phpliveregex.com/

Adan A
  • 1