Search code examples
phpemail-validation

split full email addresses into name and email?


There seems to be many acceptable email address formats in the To: and From: raw email headers ...

[email protected]
person <[email protected]>
person
Another Person <[email protected]>
'Another Person' <[email protected]>
"Another Person" <[email protected]>

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(
    '[email protected]',
    'monarch <[email protected]>',
    'blahblah',
    "'doc venture' <[email protected]>"
    );

foreach ($tests as $test){
    echo print_r( email_split($test), true );
}

Am I missing anything here? Can anyone recommend a better way?


Solution

  • I have managed to make one regex to your test cases:

    [email protected]
    person <[email protected]>
    person
    Another Person <[email protected]>
    'Another Person' <[email protected]>
    "Another Person" <[email protected]>
    

    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(
       '[email protected]',
       'monarch <[email protected]>',
       'blahblah',
       "'doc venture' <[email protected]>"
    );
    
    foreach ($tests as $test) {
       echo "<pre>";
       echo print_r(email_split($test), true);
       echo "</pre>";
    }
    

    Output I got:

    Array
    (
       [name] => 
       [email] => [email protected]
    )
    
    Array
    (
       [name] => monarch
       [email] => [email protected]
    )
    
    Array
    (
       [name] => blahblah
       [email] => 
    )
    
    Array
    (
       [name] => 'doc venture'
       [email] => [email protected]
    )