Validating Email Addresses in PHP

A very quick snippet today because I've told two people to use this approach in the last few days and both of them told me they didn't know about it. How to check if an email address is valid in PHP: use one of the Filter functions, like this:

 
$email1 = "nonsense.something@dottiness";  // not a valid email
$email2 = "dotty@something.whatever";  // valid email
 
$clean_email1 = filter_var($email1, FILTER_VALIDATE_EMAIL); // $clean_email1 = false
$clean_email2 = filter_var($email2, FILTER_VALIDATE_EMAIL); // $clean_email2 = dotty@something.whatever

The Filter extension was new in PHP 5.2, but is one of the unsung heroes of the language. It's rare for me to ever describe one approach as the "right" way to do something - but for validating data, Filter really is excellent, offering both validating and sanitising filters and generally making it super-easy to clean up incoming variables. Many of the frameworks offer equivalents, and I'm sure many of those are wrapping this too.

21 thoughts on “Validating Email Addresses in PHP

  1. Email validation with filter_var() can produce different results with different versions of PHP. There are some differences between how filter_var() acts in 5.2 and 5.3 (if i remember it correctly).

    • I'm not aware of that and didn't spot anything in the manual. Do you have a link to more information? I'd be interested

      • For example those two:
        filter_var('lorna..jane@gmail.com', FILTER_VALIDATE_EMAIL);
        filter_var('lornajaneaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@gmail.com', FILTER_VALIDATE_EMAIL);

        In 5.2.10 they will be good. In 5.2.17 they will give false (the same with 5.4). I dont know in which version behavior changed. However that's the reason why I have trust issues in filter_var() for validating email (if i dont know on which version it will run i cant predict he outcome).

  2. email@com, user@localmachine, "john smith"@example.com, localuser

    All valid email addresses that filter_var() returns FALSE for.

    • Indeed that was my first impression when I saw the example e-mail address "nonsense.something@dottiness", which is a very valid e-mail address according to the RFC. Practically though, you can't send an e-mail to that address, unless your DNS server happens to know where "dottiness" is located, which means it's not a *useful* e-mail address in most circumstances.

      Indeed filter_var( ) does tell you some valid e-mail addresses aren't valid, but in day-to-day use in a webapplication, it will suffice easily.

    • Valid according to who? Anything without a TLD isn't going to work on the internet, and I've never once in my life seen an email address with a space in it. So, IMO, it's a good thing that those don't pass the test.

      • Anything without a dot in the domain may not work on the internet today, but ICANN is busy approving a whole stack of new TLDs, many of which will be owned by a single company. They may well want use those new TLDs to set up email addresses like "name@company" without any dots in the domain.

        Also, some systems may need to send email internally within a local network, in which case it's perfectly legitimate for the local domain to be unqualified.

        And as for you never having seen an email address with a space in it.... well, that's lucky for you. They do exist. And so do a bunch of other weird combinations. You can basically have anything you like in front of the @ symbol, and there are people out there who do. I suspect those people find they have a lot of trouble filling in web forms, though.

        Validating email addresses easy. Validating them correctly is *hard*. It looks like it ought to be easy, but it isn't. Most of the tutorials on the web telling you how to do it are wrong.

      • According to RFC822 and its descendants.

        There are lots of places where local email addresses are likely to crop up. For example logging and monitoring.

        • David - I can only sigh at your response.

          For logging and monitoring you'll be specifying an email address yourself, and won't be validating it.

          For websites that collect email addresses in the wild, you simply aren't going to receive addresses in those formats, and if you do it's likely to be an error. Works as designed.

          • Um. If you don't want to conform to RFCs... or Postel's Law... well, ok, I guess. Good luck.

  3. It's true. PHP5.2 (I believe...) has a bug where foo.@bar.com, but a period cannot be the last character in the local part.

    I've taken to using a multi-step method for validating an email...

    [code]
    <?php
    $email = $_POST['email'];
    if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
    continue_with_processing();
    } else if (strpos($email, '@') !== false) {
    ask_if_they_are_sure();
    } else {
    reject_input();
    }
    [/code]

    The basic premise is: the only darn thing that can really validate an email is the receiving mailserver. Offering helpful feedback saying it doesn't *look* right is as far as I go (if it has an '@' in it.) After all, before they can setup their account they do have to click the link I send to their email.

  4. While I agree with the approach used in this article I still have to point out that this will not work for email addresses. The reason is internationalization. Let's say you have an address like post@øl.no (www.øl.no) is a valid domain with content. This method will return false.

    So to be sure that your email validation actually is 100% successfull in all cases you will have to do use idn_to_ascii():

    $email = 'post@øl.no';
    list($user, $domain) = explode('@', $email);
    $user = idn_to_ascii($user);
    $domain = idn_to_ascii($domain);
    $email = $user . '@' . $domain;
    $result = filter_var($email, FILTER_VALIDATE_EMAIL);

    This will convert the user and domain to the same format used by DNS servers when resolving internationalized domain names.

    PS: You will have to have PHP's intl module installed to be able to use the idn_* functions

Leave a Reply

Please use [code] and [/code] around any source code you wish to share.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>