Email Address class
This is the third of my easy to use everyday input-you-do-get-quite-often-validating classes: the email address. It ties in nicely with the last two articles, since an email address must end in either a domain name or an ip address.
class.EmailAddress.php
<?php
/*
* Represents an Email address
*/
class EmailAddress
{
/*
* Constructs an email address object from the given string
*/
public function __construct($email)
{
$parts = self::parse($email);
if ($parts === false) throw new Exception('Email address not valid');
$this->parts = $parts;
}
/*
* Parses the given string to a 2-item array: one@two. Returns false if the
* address is invalid.
*
* Use as validator:
* if (EmailAddress::parse($string) !== false) // string is valid address
*/
public static function parse($email)
{
$email = trim($email);
// First, we find the last @ sign (@ signs may occurr between quotes in the
// first part)
$atPos = strrpos($email, '@');
if ($atPos === false) return false; // no @ sign found
// Split around the found @ sign
$local = substr($email, 0, $atPos);
$domain = substr($email, $atPos+1);
// Check the lengths of both parts;
if (strlen($local) < 1 || strlen($local) > 64) return false;
if (strlen($domain) < 1 || strlen($domain) > 255) return false;
// Check part before @ sign
if ($local[0] == '"')
{
// Option one: quoted string
if (!preg_match('/^"[^"]+"$/', $local)) return false;
}
else
{
// Option two: dot-atom, ie a set of strings seperated by dots
// Escaped characters: \$ \/ \{ \}
if (!preg_match("/^[A-Za-z0-9!#\$%&'*+\/=?^_`\{|\}~-]+(\.[A-Za-z0-9!#\$%&'*+\/=?^_`\{|\}~-]+)*\$/", $local)) return false;
}
// Check the part after the @ sign
if (preg_match('/^\[?[0-9\.]+\]?$/', $domain))
{
// check ip
if (IPv4::parse($domain) === false) return false;
}
else
{
// check domain name
if (DomainName::parse($domain) === false) return false;
}
// return the seperated parts of the address;
return (array($local, $domain));
}
public function __toString()
{
return implode('@', $this->parts);
}
private $parts;
}
?>
The validating looks complicated but is really quite straightforward. First the lengths of the parts before and after the @ sign are checked (they must be at least 1 and at most x characters long). Then the address is split around the @ and the parts are checked individually.
The second part is easy, it must be either a domain name or an ip address. The first part is a bit more complicated, it must be either a quoted string ("like this") or a 'dot-atom'; a set of (non-empty) string, seperated by dots.
To see the script in action on some crazy email addresses, check here.
Hope this makes life a little easier for you.
Jul 9th, 2008
Comments
Michael wrote:
Today I noticed (or rather, I was notified) that the test script wasn't working. Turns out I forgot to fix the "ereg" use in the domain class --> patched!
Apr 12th, 2010
Michael wrote:
I've updated it a little to use preg_match again, now that ereg has been deprecated
Nov 12th, 2009
If you wish to add code to your comment you can use code tags, like this: <code class="php">yourCodeHere</code>.
Quite a large number of languages are supported, although I can't guarantee it'll be pretty. Inside the code tags you can use any characters except for the string "</code>".