|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2007-11-25 22:22 UTC] nobody at example dot org
Description:
------------
The regex used in php_filter_validate_email does not permit all valid atom chars from RFC2822 (eg: ASCII 61, 63).
Reproduce code:
---------------
<?php
$valid="!#$%&'*+-/=.?^_`{|}~@[1.0.0.127]";
echo filter_var($valid, FILTER_VALIDATE_EMAIL)? 'Valid': 'Invalid', "\n";
Expected result:
----------------
Valid
Actual result:
--------------
Invalid
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Mon Nov 03 16:00:02 2025 UTC |
--TEST-- RFC2822 conformance for local atoms --SKIPIF-- <?php if (!extension_loaded("filter")) die("skip"); ?> --FILE-- <?php $var = "!#$%&'*+-/=.?^_`{|}~@[1.0.0.127]"; var_dump(filter_var($var, FILTER_VALIDATE_EMAIL)); ?> --EXPECT-- bool(true) # Apologies for bug spamI may be missing something about the unit tests, following regex update to php_filter_validate_email() will not pass my test case (after doing rm ext/filter/tests/*.o ext/filter/tests/*.lo, clearing .out .log .exp .diff from tests and doing make; make test). const char regexp[] = "/^((\\\"[^\\\"\\f\\n\\r\\t\\b]+\\\")|([\\w\\!\\#\\$\\%\\&\\'\\*\\+\\-\\~\\/\\^\\`\\|\\{\\}\\=\\?]+(\\.[\\w\\!\\#\\$\\%\\&\\'\\*\\+\\-\\~\\/\\^\\`\\|\\{\\}\\=\\?]+)*))@((\\[(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))\\])|(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))|((([A-Za-z0-9\\-])+\\.)+[A-Za-z\\-]+))$/D"; Yet the equivalent regex works as expected in both PHP and my patched install. <?php error_reporting(E_ALL|E_STRICT); function validate_email($_) { /* Original from PEAR QuickForm Email.php rev: 1.4 */ $r = '/^((\"[^\"\f\n\r\t\v\b]+\")|([\w\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}\=\?]+(\.[\w\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}\=\?]+)*))@((\[(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))\])|(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))|((([A-Za-z0-9\-])+\.)+[A-Za-z\-]+))$/D'; return (bool) preg_match($r, $_); } $test = array('nobody@example.org'=>true, '.fails@example.org'=>false, "!#$%&'*+-/=.?^_`{|}~@[1.0.0.127]"=>true, ); $failed = 0; $fail = array(); foreach ($test as $k => $v){ if (!(validate_email($k) === $v)){ $failed++; $fail[].= $k; } } if ($failed > 0){ echo "Failed $failed of ",count($test), " tests using PHP func\n"; print_r($fail); } $failed = 0; $fail = array(); foreach ($test as $k => $v){ if (!((bool)filter_var($k, FILTER_VALIDATE_EMAIL) == (bool)$v)){ $failed++; $fail[].= $k; } } if ($failed > 0){ echo "Failed $failed of ",count($test), " tests using filter func\n"; print_r($fail); }I see no reason support for hostnames can't be added. filter_var ($addr, FILTER_VALIDATE_EMAIL, FILTER_PERMIT_NON_FQDNS); That's fine on a LAN and the additional flag stops web miscreants doing what would, if this were the default behaviour, otherwise be inevitable. Back on topic, FILTER_VALIDATE_EMAIL validates nothing. It fails to ensure an address is syntactically valid. <?php function _ ($_, $inv = false) { $bool = (filter_var ($_, FILTER_VALIDATE_EMAIL) === $_); echo (($inv)? !$bool: $bool)? 'OK ': 'ERR ', "$_\n"; } // RFC2821 // 4.1.2 // Should pass _ ('escaped\"quote@example.org'); // 4.5.3.1 // should both fail _ ('this-local-part-is-over-64-chars-in-length-' .'and-therefore-not-valid@na.tld', true); _ ('test@'.str_repeat('d', 256).'.com', true); // RFC2822 ('=' and '?' still fail as of PHP 5.3.0alpha3-dev) _ ("!#$%&'*+-/=.?^_`{|}~@[1.0.0.127]");