user523736
user523736

Reputation: 549

Does PHP's built-in filter_input work correctly?

I tried PHP's built-in function: filter_input()

var_dump(filter_var('[email protected]', FILTER_VALIDATE_EMAIL));

Output:

string(19) "[email protected]"

Then I tried the latest release of Zend Framework (1.11.3):

$validator = new Zend_Validate_EmailAddress();  
if ($validator->isValid('[email protected]')) {
    echo 'OK';
} else {
    foreach ($validator->getMessages() as $message) {
            echo "$message\n";
    }
}

Output:

'john.doe.' can not be matched against dot-atom format
'john.doe.' can not be matched against quoted-string format
'john.doe.' is no valid local part for email address '[email protected]'

Either the built-in function should return FALSE or the Zend method 'OK'.

My hubmle question is:
Which one is right?

Upvotes: 5

Views: 1482

Answers (3)

cmbuckley
cmbuckley

Reputation: 42458

It also depends on the version of PHP you have. PHP 5.2.14 and above (as well as 5.3) have an updated regular expression (see the commit to the PHP source code). PHP 5.2.13RC2 and below have the old regular expression. See also Bug #49576.

Upvotes: 1

Justin
Justin

Reputation: 5069

http://framework.zend.com/manual/en/zend.validate.set.html doesn't really indicate wether they're being RFC-strict or not, so lets look at the source.

In the source, _validateLocalPart() defines the EBNF they're matching against:

    // Dot-atom characters are: 1*atext *("." 1*atext)
    // atext: ALPHA / DIGIT / and "!", "#", "$", "%", "&", "'", "*",
    //        "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~"
    if (preg_match('/^[' . $atext . ']+(\x2e+[' . $atext . ']+)*$/', $this->_localPart)) {

It looks like they definitely do stay strict to that - so the local part cannot begin or end with a dot.

The pattern above is exactly the same as in the rfc2822 spec: http://www.ietf.org/rfc/rfc2822.txt - and the isValid docblock in Zend/Validate/EmailAddress.php references it as using 2822.

So, if you want to be rfc2822 compliant, Zend_Validate_EmailAddress is doing it right, and likely, the filter_input is doing it out of spec.

Upvotes: 2

Kzqai
Kzqai

Reputation: 23062

It may simply be the case that the Zend_Engine is strictly matching the RFC (which is 3 miles long, for emails). I suspect that, strictly speaking, periods are allowed characters, but a period just before the @ position is not allowed, so that is probably the problem.

I'm going to assume that gmail would still allow the sending of [email protected]. If that's the case, the question becomes more of whether you actually want to strictly match the RFC, or just be permissive in the allowed email addresses for cases where it doesn't hurt your system.

If you're worried about sql injection, bind your variables in sql & escape your html, because there's no guarantee that a strict match of the rfc will actually prevent such problems.

If you're worried about emails being sendable/receivable, I advise simply sending with the expectation of receipt, or setting up an optional email confirmation system using a confirmation link.

If you're worried about email header injection, that's a good reason to use an email library when sending mail, I expect zend has a robust one.

TooLongDidn'tRead; my advice is:

  • Be permissive. (so use whichever option is more permissive, in this case filter_input)
  • Test whether an email works by sending the email, it's almost the only true test.
  • html-escape & sql-bind everything when it's time to use it in html or sql, and don't trust anything that would come from the dangerous world beyond whenever you use it.
  • Don't use the exploitable php mail(), use a library that will prevent mail header injection.

Upvotes: 1

Related Questions