September 15, 2012

Validate an E-Mail Address with PHP

What is an email address? Following are the requirements for an e-mail address, with relevant references:

  1. An e-mail address consists of local part and domain separated by an at sign (@) character (RFC 2822 3.4.1)
  2. The local part may consist of alphabetic and numeric characters, and the following characters: !, #, $, %, &, ‘, *, +, -, /, =, ?, ^, _, `, {, |, } and ~, possibly with dot separators (.), inside, but not at the start, end or next to another dot separator (RFC 2822 3.2.4).
  3. The local part may consist of a quoted string—that is, anything within quotes (“), including spaces (RFC 2822 3.2.5).
  4. Quoted pairs (such as @) are valid components of a local part, though an obsolete form from RFC 822 (RFC 2822 4.4).
  5. The maximum length of a local part is 64 characters (RFC 2821 4.5.3.1).
  6. A domain consists of labels separated by dot separators (RFC1035 2.3.1).
  7. Domain labels start with an alphabetic character followed by zero or more alphabetic characters, numeric characters or the hyphen (-), ending with an alphabetic or numeric character (RFC 1035 2.3.1).
  8. The maximum length of a label is 63 characters (RFC 1035 2.3.1).
  9. The maximum length of a domain is 255 characters (RFC 2821 4.5.3.1).
  10. The domain must be fully qualified and resolvable to a type A or type MX DNS address record (RFC 2821 3.6).

Best solution is one developed by Dave Child’s:

function check_email_address($email) {
  // First, we check that there's one @ symbol, 
  // and that the lengths are right.
  if (!ereg("^[^@]{1,64}@[^@]{1,255}$", $email)) {
    // Email invalid because wrong number of characters 
    // in one section or wrong number of @ symbols.
    return false;
  }
  // Split it into sections to make life easier
  $email_array = explode("@", $email);
  $local_array = explode(".", $email_array[0]);
  for ($i = 0; $i < sizeof($local_array); $i++) {
    if
(!ereg("^(([A-Za-z0-9!#$%&'*+/=?^_`{|}~-][A-Za-z0-9!#$%&
↪'*+/=?^_`{|}~.-]{0,63})|("[^(|")]{0,62}"))$",
$local_array[$i])) {
      return false;
    }
  }
  // Check if domain is IP. If not, 
  // it should be valid domain name
  if (!ereg("^[?[0-9.]+]?$", $email_array[1])) {
    $domain_array = explode(".", $email_array[1]);
    if (sizeof($domain_array) < 2) {
        return false; // Not enough parts to domain
    }
    for ($i = 0; $i < sizeof($domain_array); $i++) {
      if
(!ereg("^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|
↪([A-Za-z0-9]+))$",
$domain_array[$i])) {
        return false;
      }
    }
  }
  return true;
}

The only major flaw in the code collectively developed at ILoveJackDaniel’s is that it fails to allow for quoted characters, such as @, in the user name. It will reject an address with more than one at sign, so that it does not get tripped up splitting the user name and domain parts using explode(“@”, $email). A subjective criticism is that the code expends a lot of effort checking the length of each component of the domain portion—effort better spent simply trying a domain lookup. Others might appreciate the due diligence paid to checking the domain before executing a DNS lookup on the network.

After some changes we got a complete E-mail Validation Function:

/**
Validate an email address.
Provide email address (raw input)
Returns true if the email address has the email 
address format and the domain exists.
*/
function validEmail($email)
{
   $isValid = true;
   $atIndex = strrpos($email, "@");
   if (is_bool($atIndex) && !$atIndex)
   {
      $isValid = false;
   }
   else
   {
      $domain = substr($email, $atIndex+1);
      $local = substr($email, 0, $atIndex);
      $localLen = strlen($local);
      $domainLen = strlen($domain);
      if ($localLen < 1 || $localLen > 64)
      {
         // local part length exceeded
         $isValid = false;
      }
      else if ($domainLen < 1 || $domainLen > 255)
      {
         // domain part length exceeded
         $isValid = false;
      }
      else if ($local[0] == '.' || $local[$localLen-1] == '.')
      {
         // local part starts or ends with '.'
         $isValid = false;
      }
      else if (preg_match('/../', $local))
      {
         // local part has two consecutive dots
         $isValid = false;
      }
      else if (!preg_match('/^[A-Za-z0-9-.]+$/', $domain))
      {
         // character not valid in domain part
         $isValid = false;
      }
      else if (preg_match('/../', $domain))
      {
         // domain part has two consecutive dots
         $isValid = false;
      }
      else if
(!preg_match('/^(.|[A-Za-z0-9!#%&`_=/$'*+?^{}|~.-])+$/',
                 str_replace("","",$local)))
      {
         // character not valid in local part unless 
         // local part is quoted
         if (!preg_match('/^"("|[^"])+"$/',
             str_replace("","",$local)))
         {
            $isValid = false;
         }
      }
      if ($isValid && !(checkdnsrr($domain,"MX") || 
 ↪checkdnsrr($domain,"A")))
      {
         // domain not found in DNS
         $isValid = false;
      }
   }
   return $isValid;
}
PHP # , ,
Share: / / /

You might also like

Leave a Reply

Your email address will not be published. Required fields are marked *

Pin It on Pinterest

Share This