split full email addresses into name and email? - php

There seems to be many acceptable email address formats in the To: and From: raw email headers ...
person#place.com
person <person#place.com>
person
Another Person <person#place.com>
'Another Person' <person#place.com>
"Another Person" <person#place.com>
After not finding any effective PHP functions for splitting out names and addresses, I've written the following code.
You can DEMO IT ON CODEPAD to see the output...
// validate email address
function validate_email( $email ){
return (filter_var($email, FILTER_VALIDATE_EMAIL)) ? true : false;
}
// split email into name / address
function email_split( $str ){
$name = $email = '';
if (substr($str,0,1)=='<') {
// first character = <
$email = str_replace( array('<','>'), '', $str );
} else if (strpos($str,' <') !== false) {
// possibly = name <email>
list($name,$email) = explode(' <',$str);
$email = str_replace('>','',$email);
if (!validate_email($email)) $email = '';
$name = str_replace(array('"',"'"),'',$name);
} else if (validate_email($str)) {
// just the email
$email = $str;
} else {
// unknown
$name = $str;
}
return array( 'name'=>trim($name), 'email'=>trim($email) );
}
// test it
$tests = array(
'person#place.com',
'monarch <themonarch#tgoci.com>',
'blahblah',
"'doc venture' <doc#venture.com>"
);
foreach ($tests as $test){
echo print_r( email_split($test), true );
}
Am I missing anything here? Can anyone recommend a better way?

I have managed to make one regex to your test cases:
person#place.com
person <person#place.com>
person
Another Person <person#place.com>
'Another Person' <person#place.com>
"Another Person" <person#place.com>
using preg_match with this regex will surely help you bit.
function email_split( $str ){
$sPattern = "/([\w\s\'\"]+[\s]+)?(<)?(([\w-\.]+)#((?:[\w]+\.)+)([a-zA-Z]{2,4}))?(>)?/g";
preg_match($sPattern,$str,$aMatch);
if(isset($aMatch[1]))
{
echo $aMatch[1] //this is name;
}
if(isset($aMatch[3]))
{
echo $aMatch[3] //this is EmailAddress;
}
}
Note: I just noticed that single "person" i.e. your third test case could be discarded with this regex (just that because of space constraint in regex) so,at first line of your email_split function, append space at last place of your string.
Then it would be bang on target.
Thanks, Hope this helps.
Code I tried:
<?php
// validate email address
function validate_email($email) {
return (filter_var($email, FILTER_VALIDATE_EMAIL)) ? true : false;
}
// split email into name / address
function email_split($str) {
$str .=" ";
$sPattern = '/([\w\s\'\"]+[\s]+)?(<)?(([\w-\.]+)#((?:[\w]+\.)+)([a-zA-Z]{2,4}))?(>)?/';
preg_match($sPattern, $str, $aMatch);
//echo "string";
//print_r($aMatch);
$name = (isset($aMatch[1])) ? $aMatch[1] : '';
$email = (isset($aMatch[3])) ? $aMatch[3] : '';
return array('name' => trim($name), 'email' => trim($email));
}
// test it
$tests = array(
'person#place.com',
'monarch <themonarch#tgoci.com>',
'blahblah',
"'doc venture' <doc#venture.com>"
);
foreach ($tests as $test) {
echo "<pre>";
echo print_r(email_split($test), true);
echo "</pre>";
}
Output I got:
Array
(
[name] =>
[email] => person#place.com
)
Array
(
[name] => monarch
[email] => themonarch#tgoci.com
)
Array
(
[name] => blahblah
[email] =>
)
Array
(
[name] => 'doc venture'
[email] => doc#venture.com
)

How about this:
function email_split($str) {
$parts = explode(' ', trim($str));
$email = trim(array_pop($parts), "<> \t\n\r\0\x0B");
$name = trim(implode(' ', $parts), "\"\' \t\n\r\0\x0B");
if ($name == "" && strpos($email, "#") === false) { // only single string - did not contain '#'
$name = $email;
$email = "";
}
return array('name' => $name, 'email' => $email);
}
Looks like this is about twice as fast as the regex solution.
Note: the OPs third test case (for my purposes) is not needed. But in the interest of answering the OP I added the if stmt to produce the OPs expected results. This could have been done other ways (check the last element of $parts for '#').

use preg_match in php, http://php.net/manual/en/function.preg-match.php
or in my opinion, you can make your own function (let say get_email_address), it catch # character and then get the 'rest-left-string' from # until '<' character and 'rest-right-string' from # until '>' character.
for example, string monarch <themonarch#tgoci.com> will return 'rest-left-string' = themonarch and 'rest-right-string' = tgoci.com . finally, your function get_email_address will return themonarch#tgoci.com
hopefully it help.. :)

unfortunately the regex fails in a couple of conditions of the fullname:
non alphanumeric chars (eg. "Amazon.it")
non printable chars
emojs
i adjusted the expression this way
$sPattern = '/([^<]*)?(<)?(([\w-\.]+)#((?:[\w]+\.)+)([a-zA-Z]{2,4}))?(>)?/';
and now all chars are correctly recognized and splitted.
tested with
$address = "Test User # `` . !! 🔥 <test#email.com";
after 7 years, hope this helps :)

Related

Email validation with edu domains only

i have been trying to get the email address which has domains ends with .edu only using code below
$email = $_REQUEST['email'];
$school = substr($email, strpos($email, "#") + 1);
is there any way?
You just need to make a substring including the last 3 chars of the current string.
<?php
$tld = substr($email, strlen($email)-2, 3); // three last chars of the string
if ($tld = "edu") {
// do stuff
}
?>
It Should be work for get your domain name and domain extension:
$email = 'test#website.edu';
$getDomain = explode('#', $email);
$explValue = explode('.', $getDomain[1], 2);
print_r($explValue);
The out put is:
Array ( [0] => website [1] => edu )
After that you can check with
if($explValue[1] == 'edu'){
//your code here
}
If .edu is the last part of the email address, you could use strlen and substr:
$email = "test#test.edu";
$end = ".edu";
$string_end = substr($email, strlen($email) - strlen($end));
if ($end === $string_end) {
// Ok
}
Maybe it is also an option to use explode and split on #. Then use explode again and split on a dot and check if the array returned contains edu:
$strings = [
"test#test.edu",
"test#test.edu.pl",
"test#test.com"
];
foreach ($strings as $string) {
if (in_array("edu", explode(".", explode("#", $string)[1]))) {
// Etc..
}
}
Demo
strpos($email, ".edu."); it should be work.
for example gensek#metu.edu.tr
You can use substr And get last 4 characters if this is valid as per your requirement so the email is valid else it not.
$string = "xyzasd.edu";
echo $txt = substr($string,-4);
if($txt == ".edu"){
//Valid
}else{
//Not Valid
}

Return part of string in array

So I'm trying to make this little script work for fun and just cant get it to work,
I have an array of random names that are assigned their 'random' email addresses, I want to check if the email address have extension:
'#hotmail.com',
'#hotmail.ca', or
'#yahoo.ca' . if they are then echo something like 'Daniel, your email addresses extension is $extension, you qualify'
and if they don't just say 'Kayla, your email address is $extension, you don't qualify.
I want to add a foreach statement explaining that for each person in the array $ClassRoom2, i've tried using strstr() but it doesn't work inside the foreach because it can only have one string.
heres what i got so far:
qualify = "";
$ClassRoom2 = array(
'Daniel' => 'fresco#hotmail.com',
'Mike' => 'dkoko#yahoo.ca',
'Meranda' => 'brunnn_23#hotmail.ca',
'Will' => 'yumyum03#wp.pl',
'Brittey' => 's0sd#outlook.com',
'Kayla' => 'hocklife#freebie.com' );
switch ($ClassRoom2) {
case '#hotmail.com':
echo 'You are using extension '. $final; $qualify = 1; break;
case '#hotmail.ca':
echo 'You are using extension '. $final; $qualify = 1; break;
case '#yahoo.com':
echo 'You are using extension '. $final; $quality = 1; break;
case '#yahoo.ca':
echo 'You are using extension '. $final; $qualify = 1; break;
case '#live.ca':
echo 'You are using extension '. $final; $quality = 1; break;
default:
echo 'its something else'; $qualify = 0;
break;
}
if ($qualify == 1) {
echo "Congratulations, you quality for the contest. The extension you chose was <b>$final</b>";
} else {
echo "Sorry mate! you didn't quality for the contest.";
}
Use explode() to get the domain part and compare it
$parts = explode("#", "johndoe#domain.com");
echo ($parts[1]=='domain.com') ? 'qualify' : 'not qualify';
Sorry for my late reaction, I was still testing my code example.
If you want to stick with the switch you currently designed, you could use a simple preg_match to extract the string you need. Here is a little example (you can remove the comment and put in your switch there):
<?php
$ClassRoom2 = array(
'Daniel' => 'fresco#hotmail.com',
'Mike' => 'dkoko#yahoo.ca',
'Meranda' => 'brunnn_23#hotmail.ca',
'Will' => 'yumyum03#wp.pl',
'Brittey' => 's0sd#outlook.com',
'Kayla' => 'hocklife#freebie.com'
);
foreach ($ClassRoom2 as $name=>$email) {
$matches = [];
preg_match( "/(#.+)/", $email, $matches);
// Do things with $matches[0] here (your switch for eg)
// switch ($matches[0]) {
// case '#hotmail.com':
// ...
print '<br/> ' . $matches[0];
}
?>
If you want, you can fiddle arround with preg matches on this website: regexr
Update You can actually do a lot with preg_match, once you get the hang of it :)
foreach ($ClassRoom2 as $name=>$email) {
$matches = preg_match( "/#(hotmail.com|hotmail.ca|yahoo.ca|yahoo.com|live.ca)/", $email);
// if ($matches) // or simply replace the preg_match in the if
print '<br/> ' . $email . ($matches ? ' qualifies' : ' <strong>does not qualify</strong> ') . 'for the email test';
}
I would put the list of entries and the qualifying extensions on separate arrays then check each people entry and parse their information to see if each qualify, like this:
$peoplelist = array(
'Daniel' => 'fresco#hotmail.com',
'Mike' => 'dkoko#yahoo.ca',
'Meranda' => 'brunnn_23#hotmail.ca',
'Will' => 'yumyum03#wp.pl',
'Brittey' => 's0sd#outlook.com',
'Kayla' => 'hocklife#freebie.com'
);
$qualify = array(
'hotmail.com',
'hotmail.ca',
'yahoo.com',
'yahoo.ca',
'live.ca',
);
foreach( $peoplelist as $name => $email )
{
$parts = explode( "#", $email );
$extension = strtolower( trim( array_pop( $parts ) ) );
echo "Hi, ".$name.". You are using extension #".$extension.". <br /> \n";
if( in_array( $extension, $qualify ) )
{
echo "Congratulations, you quality for the contest. <br /> \n";
}
}

mask mail with Alternative words using php

Mentioned below is a dummy Email ID say,
abcdefghij#gmail.com
How to mask this email ID partially using PHP?
Output i need as
a*c*e*g*i*#gmail.com
I have tried the below code, But it not works for below requirement
$prop=3;
$domain = substr(strrchr($Member_Email, "#"), 1);
$mailname=str_replace($domain,'',$Member_Email);
$name_l=strlen($mailname);
$domain_l=strlen($domain);
for($i=0;$i<=$name_l/$prop-1;$i++)
{
$start.='*';
}
for($i=0;$i<=$domain_l/$prop-1;$i++)
{
$end.='*';
}
$MaskMail = substr_replace($mailname, $start,2, $name_l/$prop).substr_replace($domain, $end, 2, $domain_l/$prop);
Give a try like this.
$delimeter = '#';
$mail_id = 'abcdefghij#gmail.com';
$domain = substr(strrchr($mail_id, $delimeter), 1);
$user_id = substr($mail_id,0,strpos($mail_id, $delimeter));
$string_array = str_split($user_id);
$partial_id = NULL;
foreach($string_array as $key => $val){
if($key % 2 == 0){
$partial_id .=$val;
}else{
$partial_id .='*' ;
}
}
echo $partial_id.$delimeter.$domain;
Here's a no loop approach to replace every second character of an email username with a mask.
Custom PHP function using native functions split, preg_replace with regex /(.)./, and implode:
echo email_mask('abcdefghi#gmail.com');
// a*c*e*g*i*k*#gmail.com
function email_mask($email) {
list($email_username, $email_domain) = split('#', $email);
$masked_email_username = preg_replace('/(.)./', "$1*", $email_username);
return implode('#', array($masked_email_username, $email_domain));
}
Regex Explanation:
The regular expression starts at the beginning of the string, matches 2 characters and captures the first of those two, replaces the match with the first character followed by an asterisk *. preg_replace repeats this throughout the remaining string until it can no longer match a pair of characters.
$mail='abcdefghij#gmail.com';
$mail_first=explode('#',$mail);
$arr=str_split($mail_first[0]);
$mask=array();
for($i=0;$i<count($arr);$i++) {
if($i%2!=0) {
$arr[$i]='*';
}
$mask[]=$arr[$i];
}
$mask=join($mask).'#'.$mail_first[1];
echo $mask;
Result is :
a*c*e*g*i*#gmail.com
Does it need to have that many asterisks?
It's so hard to read that way.
I will suggest you keep things simple.
Maybe something like this is enough
https://github.com/fedmich/PHP_Codes/blob/master/mask_email.php
Masks an email to show first 3 characters and then the last character before the # sign
ABCDEFZ#gmail.com becomes
A*****Z#gmail.com
Here is the full code that is also in that Github link
function mask_email( $email ) {
/*
Author: Fed
Simple way of masking emails
*/
$char_shown = 3;
$mail_parts = explode("#", $email);
$username = $mail_parts[0];
$len = strlen( $username );
if( $len <= $char_shown ){
return implode("#", $mail_parts );
}
//Logic: show asterisk in middle, but also show the last character before #
$mail_parts[0] = substr( $username, 0 , $char_shown )
. str_repeat("*", $len - $char_shown - 1 )
. substr( $username, $len - $char_shown + 2 , 1 )
;
return implode("#", $mail_parts );
}

Get part of array string

Hello my output PHP code is :
Array ( [country] => BG - Bulgaria )
... and he comes from here :
<?php
$ip = $_SERVER['REMOTE_ADDR'];
print_r(geoCheckIP($ip));
//Array ( [domain] => dslb-094-219-040-096.pools.arcor-ip.net [country] => DE - Germany [state] => Hessen [town] => Erzhausen )
//Get an array with geoip-infodata
function geoCheckIP($ip)
{
//check, if the provided ip is valid
if(!filter_var($ip, FILTER_VALIDATE_IP))
{
throw new InvalidArgumentException("IP is not valid");
}
//contact ip-server
$response=#file_get_contents('http://www.netip.de/search?query='.$ip);
if (empty($response))
{
throw new InvalidArgumentException("Error contacting Geo-IP-Server");
}
//Array containing all regex-patterns necessary to extract ip-geoinfo from page
$patterns=array();
$patterns["country"] = '#Country: (.*?) #i';
//Array where results will be stored
$ipInfo=array();
//check response from ipserver for above patterns
foreach ($patterns as $key => $pattern)
{
//store the result in array
$ipInfo[$key] = preg_match($pattern,$response,$value) && !empty($value[1]) ? $value[1] : '';
}
return $ipInfo;
}
?>
How can I get ONLY the name of the Country like in my case "Bulgaria"? I think it will happen with preg_replace or substr but i dont know what is the better solution now.
substr's probably easiest:
$bad_country = 'BG - Bulgaria';
$good_country = substr($bad_country, 5); // start at char 5, 'B'
if the country is always separated from the acronym by ' - ', do it like this:
list($acrn, $country) = explode(' - ', $var);
If you are guaranteed that the output will always be in the same format(ie BG - Bulgaria, US - United States, etc), you could use explode():
$array['country'] = "BG - Bulgaria";
$country = explode(" - ", $array['country']);
echo $country[1];
This will output "Bulgaria".
try:
foreach( $list as $v) {
$temp = explode(' - ', $v);
$countries[] = $temp[1];
}
$patterns["country"] = '#Country:.*-\s+(\w+?) #i';
try this one as your pattern
Change your pattern to this:
'#Country: [a-z]{2,} - (.*?) #i'
Assuming the pattern won't change

Assign regex pattern as key to an array

I have an array of regular expressions and am trying to loop through a text document to find the first pattern, assign that as the key to an array then continue through find the second pattern and assign that as the value. Whenever I come across pattern 1 I want that to always be assigned as a key and all pattern 2 matches that follow until I come across a new key will be assigned to that first key as values.
Text document structure:
Subject: sometext
Email: someemail#email.com
source: www.google.com www.stackoverflow.com www.reddit.com
So I have an array of expressions:
$expressions=array(
'email'=>'(\b[a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b)',
'url'=>'([A-Za-z][A-Za-z0-9+.-]{1,120}:[A-Za-z0-9/](([A-Za-z0-9$_.+!*,;/?:#&~=-])|%[A-Fa-f0-9]{2}){1,333}(#([a-zA-Z0-9][a-zA-Z0-9$_.+!*,;/?:#&~=%-]{0,1000}))?)'
);
I want to loop through my text document and match the email address then assign that as the key to an array then assign all urls that follow as the values, s the output to the above text would be:
array(
'someemail#email.com' => array (
0 => 'www.google.com',
1 => 'www.stackoverflow.com',
2 => 'www.reddit.com'
)
One way to do such a thing:
$parts = preg_split("/(emailexpr)/",$txt,-1,PREG_SPLIT_DELIM_CAPTURE);
$res = array();
// note: $parts[0] will be everything preceding the first emailexpr match
for ( $i=1; isset($parts[$i]); $i+=2 )
{
$email = $parts[$i];
$chunk = $parts[$i+1];
if ( preg_match_all("/domainexpr/",$chunk,$match) )
{
$res[$email] = $match[0];
}
}
replace emailexpr and domainexpr with your regexp gibberish.
I would do:
$lines = file('input_file', FILE_SKIP_EMPTY_LINES);
$array = array();
foreach($lines as $line) {
if(preg_match('/^Subject:/', $line) {
$email = '';
} elseif(preg_match('/^Email: (.*)$/', $line, $m)) {
if(preg_match($expressions['email'], $m[1])) {
$email = $m[1];
}
} elseif(preg_match('/^source: (.*)$/', $line, $m) && $email) {
foreach(explode(' ', $m[1]) as $url) {
if(preg_match($expressions['url'], $url)) {
$array[$email][] = $url;
}
}
}
}

Categories