<?php

/*
 * Check Email string for validity
 * Paul Gregg <pgregg@pgregg.com>
 * January 2002, Updated Nov 2003, Logic fix May 2006
 * Updated May 2008 - rewrote localpart/domainpart splitting
 * Updated Feb 2020 - added iana TLD domain link and recognition that TLDs are
 *                    now up to 24 bytes long (this may get longer)
 * Updated Mar 2021 - added EAI support
 * http://www.pgregg.com/projects/php/code/validate_email.inc.phps
 * Copyright 2002-2021, Paul Gregg.
 *
 * Open Source Code:   If you use this code on your site for public
 * access (i.e. on the Internet) then you must attribute the author and
 * source web site: http://pgregg.com/projects/php/code/validate_email.inc.phps
 *
 * Email Validation (syntax/format only) is frequently a hotly discussed
 * topic on forums, irc channels and blogs.  Some people believe that to be
 * "correct" your pattern should be RFC 822/2822 complient, others fall into
 * the take anything camp.
 * Personally, I believe a more liberal approach is necessary - the spirit of
 * RFCs is "Be strict in what you send and liberal in what you receive".
 * Many email addresses might not be strictly to RFC pattern spec, but they
 * work just fine, and in these days of multibyte characters and "foreign"
 * character sets, the picture becomes a lot more complicated.
 *
 */

Function ValidateEmail($emailstr) {
    
// Make the email address lower case and remove whitespace
    
$emailstr strtolower(trim($emailstr));
    
    
// Split it up into before and after the @ symbol
    
$email_components explode('@'$emailstr);
    
    
// Everything after the last @ is the domain, before is the local part
    
$domain_part array_pop($email_components);
    
$local_part implode('@'$email_components);

    
// sanitize quoted parts
    
$local_part preg_replace('/\\\./''_'$local_part);
    
$local_part preg_replace('/"[^"]+"/''.'$local_part);

    
// comments ( this is a comment ) are permitted in domain parts
    
$domain_part preg_replace('/\([^()]*\)/'''$domain_part);

    
// Make sure there are no more @ (we sanitized valid ones above)
    
if (strpos($local_part'@')!==false)
        return 
FALSE;
    
    
// Check that the username is >= 1 char
    
if (mb_strlen($local_part) == 0)
        return 
FALSE;
    
    
// Split the domain part into the dotted parts
    
$domain_components explode('.'$domain_part);
    
    
// check there are at least 2
    
if (count($domain_components) < 2)
        return 
FALSE;
    
    
// Check each domain part to ensure it doesn't start or end with a bad char
    
foreach ($domain_components as $domain_component)
        if (
mb_strlen($domain_component) > 0) {
            if (
preg_match('/[\.-]/'$domain_component[0])
                || 
preg_match('/[\.-]/'$domain_component[mb_strlen($domain_component)-1]) )
                return 
FALSE;
        } else
            return 
FALSE;


    
// Check the last domain component has 2-24 chars (.uk to .XN--VERMGENSBERATUNG-PWB)
    // New TLDs are easily purchased from ICANN, TLD list at http://data.iana.org/TLD/tlds-alpha-by-domain.txt
    // At time of update, the longest punycode domain was 24 bytes.
    
$domain_last array_pop($domain_components);
    if (
mb_strlen($domain_last) < || mb_strlen($domain_last) > 24)
        return 
FALSE;
    
    
// Check for valid chars - Domains can only have A-Z, 0-9, ., and the - chars,
    // or be in the form [123.123.123.123]
    
if ( preg_match('/^\[(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\]$/'$domain_part$ipnum) )
        return (
ip2long($ipnum[1]) === false false true);

    
// Check for invalid characters in domain
    
if (mb_check_encoding($domain_part'ASCII')) {
        if (
preg_match('/[^a-z0-9\.-]/'$domain_part))
            return 
FALSE;
    } else {
        if (
preg_match('/[\(\),:;<>@\[\\\]]/'$domain_part))
            return 
false;
    }

    
// If we get here then it passed
    
return TRUE;
}
?>