From fa1c61f608aaa8e5b228be5604acc8c95d2de0b6 Mon Sep 17 00:00:00 2001 From: rxu Date: Tue, 17 Feb 2015 17:24:30 +0700 Subject: [PATCH 1/2] [ticket/13433] Fix parsing of email addresses Currently email addresses are parsed incorrectly due to the regex structure. Namely, if localpart consists of several dot separated parts, only the last part with the trailing dot will be captured. The patch change this behavior to capture the whole localpart. PHPBB3-13433 --- phpBB/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 940484a0ea..4159af5678 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -3347,7 +3347,7 @@ function get_preg_expression($mode) case 'email': // Regex written by James Watts and Francisco Jose Martin Moreno // http://fightingforalostcause.net/misc/2006/compare-email-regex.php - return '([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*(?:[\w\!\#$\%\'\*\+\-\/\=\?\^\`{\|\}\~]|&)+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,63})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)'; + return '((?:[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*(?:[\w\!\#$\%\'\*\+\-\/\=\?\^\`{\|\}\~]|&)+)@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,63})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)'; break; case 'bbcode_htm': From 950c72a8a578905b3c08b7fdf6f1a0df2a09f384 Mon Sep 17 00:00:00 2001 From: rxu Date: Tue, 17 Feb 2015 21:03:39 +0700 Subject: [PATCH 2/2] [ticket/13433] Add make_clickable() test for emails PHPBB3-13433 --- tests/functions/make_clickable_email_test.php | 222 ++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 tests/functions/make_clickable_email_test.php diff --git a/tests/functions/make_clickable_email_test.php b/tests/functions/make_clickable_email_test.php new file mode 100644 index 0000000000..4c802d0487 --- /dev/null +++ b/tests/functions/make_clickable_email_test.php @@ -0,0 +1,222 @@ + +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; +require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php'; + +class phpbb_functions_make_clickable_email_test extends phpbb_test_case +{ + protected function setUp() + { + parent::setUp(); + + global $config, $user, $request; + $user = new phpbb_mock_user(); + $request = new phpbb_mock_request(); + } + + /** + * 'e' tag for email addresses html + **/ + public function data_test_make_clickable_email_positive() + { + return array( + array( + 'nobody@phpbb.com', + 'nobody@phpbb.com' + ), + array( + 'Nobody@sub.phpbb.com', + 'Nobody@sub.phpbb.com' + ), + array( + 'alice.bob@foo.phpbb.com', + 'alice.bob@foo.phpbb.com' + ), + array( + 'alice-foo@bar.phpbb.com', + 'alice-foo@bar.phpbb.com' + ), + array( + 'alice_foo@bar.phpbb.com', + 'alice_foo@bar.phpbb.com' + ), + array( + 'alice+tag@foo.phpbb.com', + 'alice+tag@foo.phpbb.com' + ), + array( + 'alice&tag@foo.phpbb.com', + 'alice&tag@foo.phpbb.com' + ), + array( + 'alice@phpbb.australia', + 'alice@phpbb.australia' + ), + + // Test shortened text for email > 55 characters long + // Email text should be turned into: first 39 chars + ' ... ' + last 10 chars + array( + 'alice@phpbb.topZlevelZdomainZnamesZcanZbeZupZtoZsixtyZthreeZcharactersZlong', + 'alice@phpbb.topZlevelZdomainZnamesZcanZ ... ctersZlong' + ), + array( + 'l3tt3rsAndNumb3rs@domain.com', + 'l3tt3rsAndNumb3rs@domain.com' + ), + array( + 'has-dash@domain.com', + 'has-dash@domain.com' + ), + array( + 'hasApostrophe.o\'leary@domain.org', + 'hasApostrophe.o\'leary@domain.org' + ), + array( + 'uncommonTLD@domain.museum', + 'uncommonTLD@domain.museum' + ), + array( + 'uncommonTLD@domain.travel', + 'uncommonTLD@domain.travel' + ), + array( + 'uncommonTLD@domain.mobi', + 'uncommonTLD@domain.mobi' + ), + array( + 'countryCodeTLD@domain.uk', + 'countryCodeTLD@domain.uk' + ), + array( + 'countryCodeTLD@domain.rw', + 'countryCodeTLD@domain.rw' + ), + array( + 'numbersInDomain@911.com', + 'numbersInDomain@911.com' + ), + array( + 'underscore_inLocal@domain.net', + 'underscore_inLocal@domain.net' + ), + array( + 'IPInsteadOfDomain@127.0.0.1', + 'IPInsteadOfDomain@127.0.0.1' + ), + array( + 'IPAndPort@127.0.0.1:25', + 'IPAndPort@127.0.0.1:25' + ), + array( + 'subdomain@sub.domain.com', + 'subdomain@sub.domain.com' + ), + array( + 'local@dash-inDomain.com', + 'local@dash-inDomain.com' + ), + array( + 'dot.inLocal@foo.com', + 'dot.inLocal@foo.com' + ), + array( + 'a@singleLetterLocal.org', + 'a@singleLetterLocal.org' + ), + array( + 'singleLetterDomain@x.org', + 'singleLetterDomain@x.org' + ), + array( + '&*=?^+{}\'~@validCharsInLocal.net', + '&*=?^+{}\'~@validCharsInLocal.net' + ), + array( + 'foor@bar.newTLD', + 'foor@bar.newTLD' + ), + ); + } + + public function data_test_make_clickable_email_negative() + { + return array( + array('foo.example.com'), // @ is missing + array('.foo.example.com'), // . as first character + array('Foo.@example.com'), // . is last in local part + array('foo..123@example.com'), // . doubled + array('a@b@c@example.com'), // @ doubled + + // Emails with invalid characters + // (only 'valid' pieces having localparts prepended with one of the \n \t ( > chars should parsed if any) + array('()[]\;:,<>@example.com'), // invalid characters + array('abc(def@example.com', 'abc(def@example.com'), // invalid character ( + array('abc)def@example.com'), // invalid character ) + array('abc[def@example.com'), // invalid character [ + array('abc]def@example.com'), // invalid character ] + array('abc\def@example.com'), // invalid character \ + array('abc;def@example.com'), // invalid character ; + array('abc:def@example.com'), // invalid character : + array('abc,def@example.com'), // invalid character , + array('abcdef@example.com', 'abc>def@example.com'), // invalid character > + + // http://fightingforalostcause.net/misc/2006/compare-email-regex.php + array('missingDomain@.com'), + array('@missingLocal.org'), + array('missingatSign.net'), + array('missingDot@com'), + array('two@@signs.com'), + // Trailing colon is ignored + array('colonButNoPort@127.0.0.1:', 'colonButNoPort@127.0.0.1:'), + + array(''), + // Trailing part after the 3rd dot is ignored + array('someone-else@127.0.0.1.26', 'someone-else@127.0.0.1.26'), + + array('.localStartsWithDot@domain.com'), + array('localEndsWithDot.@domain.com'), + array('two..consecutiveDots@domain.com'), + array('domainStartsWithDash@-domain.com'), + array('domainEndsWithDash@domain-.com'), + array('numbersInTLD@domain.c0m'), + array('missingTLD@domain.'), + array('! "#$%(),/;<>[]`|@invalidCharsInLocal.org'), + array('invalidCharsInDomain@! "#$%(),/;<>_[]`|.org'), + array('local@SecondLevelDomainNamesAreInvalidIfTheyAreLongerThan64Charactersss.org'), + // The domain zone name part after the 63rd char is ignored + array( + 'alice@phpbb.topZlevelZdomainZnamesZcanZbeZupZtoZsixtyZthreeZcharactersZlongZ', + 'alice@phpbb.topZlevelZdomainZnamesZcanZ ... ctersZlongZ' + ), + ); + } + + /** + * @dataProvider data_test_make_clickable_email_positive + */ + public function test_email_matching_positive($email, $expected) + { + $this->assertSame($expected, make_clickable($email)); + } + + /** + * @dataProvider data_test_make_clickable_email_negative + */ + public function test_email_matching_negative($email, $expected = null) + { + $expected = ($expected) ?: $email; + $this->assertSame($expected, make_clickable($email)); + } +}