Reputation: 4367
I have a class that validates every input before I send it to the database layer. Note that my problem is not about escaping or anything. My database layer will handle the SQL Injection problem. All I want to do is validate if the email is valid or not because later that email might be used as a 'send to'. For instance, the user will recover access to his account through a link sent to the e-mail. I read a lot about filter_var
and there are a bunch of people being against it and other bunch being in favor. Keeping the focus on 'I just want to validate email and not filter it for database or for html or XSS or whatever', is there a problem in using filter_var
?
Upvotes: 27
Views: 23198
Reputation: 1932
In 2024, No. filter_var
's validation implementation (as of PHP 8.3) does not verify international domain names, which I consider is big enough of a reason to ditch.
Symfony's own Email Validation also uses a Regex that has no UTF-8 support.
Use https://github.com/egulias/EmailValidator. It follows the email RFC and can also check MX records to further verify that the domain does exist.
Upvotes: 5
Reputation: 7327
Some of the comments I saw didn't match my testing so I wanted to point out the functionality I found with PHP 5.x. If you first SANITIZE the email it will remove all of the chars you don't want, then you can VALIDATE. I have two functions in case someone wanted to just do one or the other.
Check if email is valid:
function isValidEmailAddress($email = '', $check_domain = false)
{
if (empty($email)) {
return false;
} else {
$success = true;
}
if (!filter_var((string) $email, FILTER_VALIDATE_EMAIL)) {
$success = false;
}
if ($check_domain && $success) {
list($name, $domain) = explode('@', trim($email) . "@");
if (!checkdnsrr($domain, 'MX')) {
$success = false;
}
}
return array("success" => $success, "email" => $email);
}
Remove <> and UTF8 etc :
function sanitizeEmailAddress($email = '') {
if (!empty($email)) {
$email = filter_var(strtolower(trim($email)), FILTER_SANITIZE_EMAIL);
}
return $email;
}
Sample Usage:
// test --
$list = array('goodÂ@bad.com', '[email protected]', '[email protected]', 'quick@us', '', '<[email protected]>', '[email protected]', '[email protected]', '[email protected]', '[email protected]', '[email protected]');
foreach($list as $email) {
$ret = isValidEmailAddress( sanitizeEmailAddress($email), false );
if ($ret['success']) {
echo "GOOD " . $ret['email'];
} else {
echo "BAD " .$email;
}
echo "\n";
}
Results :
GOOD [email protected]
GOOD [email protected]
GOOD [email protected]
BAD quick@us
BAD
GOOD [email protected]
GOOD [email protected]
GOOD [email protected]
GOOD [email protected]
GOOD [email protected]
GOOD [email protected]
if you use the domain option: $ret = isValidEmailAddress( sanitizeEmailAddress($email), true );
GOOD [email protected]
GOOD [email protected]
GOOD [email protected]
BAD quick@us
BAD
GOOD [email protected]
GOOD [email protected]
GOOD [email protected]
BAD [email protected]
BAD [email protected]
BAD [email protected]
Upvotes: 1
Reputation: 2545
Unfortunately, filter_var
does not support UTF8 in the local part (before the @) of the address, and to support international domain names you will need to run the domain name through idn_to_ascii
separately (which is a hassle and not obvious).
This makes filter_var
fairly useless in my opinion: the more unicode email addresses appear in the wild, the more legitimate email addresses will fail, which is especially the case for countries like China or Brazil, where there is an obvious demand for these addresses. filter_var
also does not allow email addresses like root@localhost
, which are valid and may be useful in a server context.
It would be really useful if an email library existed to validate according to specific instructions - are only domain names allowed, or also arbitrary hosts like localhost, or is there a whitelist for custom domains which should be valid? Should unicode be allowed? What are common typos for freemail domain names (like @homail.com) that should also fail?
Also, validating some domain names in more specific manner would be sensible - hotmail.com does not allow unicode characters for now and has specific limitations on useable characters. As most used email addresses in PHP applications are concentrated on maybe 100 different domains, this could be used to validate these domain names in a better way. Unfortunately, no such library exists yet, as far as I know.
Upvotes: 3
Reputation: 547
Yes. But checkdnsrr()
may also be worth a mention here.
filter_var()
will approve domains that seem to be incomplete because it could be valid in a local context (e.g. someone@localhost). This can lead to false positives where people just miss off the TLD or the dot in the domain name (e.g. hattie.jacques@gmailcom)
Catch these by doing a checkdnsrr()
lookup on the domain - if you can find an MX record for the domain and the address is valid then you've pretty much done your best.
Example code:
if(filter_var($email, FILTER_VALIDATE_EMAIL))
{
list($userName, $mailDomain) = explode("@", $email);
if (!checkdnsrr($mailDomain, "MX"))
{
// Email is unreachable.
}
}
else
{
// Email is bad.
}
checkdnsrr()
is pretty instant (in my experience) and I've not yet found an environment in which it doesn't work.
Upvotes: 8
Reputation: 352
Yes, you should use filter_var
and this is how you can incorporate it :
if( filter_var( $email ,FILTER_VALIDATE_EMAIL ) )
{
/*
* Rest of your code
*/
}
Upvotes: 11
Reputation: 20753
Yes, you should.
Using the standard library validation instead of a home brew one has multiple benefits:
However checking the format of an email address is only the first line of defense, if you really want to know that it's real or not, you will have to send a message to it.
Upvotes: 29