diff --git a/phpBB/includes/functions_content.php b/phpBB/includes/functions_content.php index b89eec9593..bfd6b179cd 100644 --- a/phpBB/includes/functions_content.php +++ b/phpBB/includes/functions_content.php @@ -921,13 +921,17 @@ function make_clickable_callback($type, $whitespace, $url, $relative_url, $class } /** -* make_clickable function -* -* Replace magic urls of form http://xxx.xxx., www.xxx. and xxx@xxx.xxx. -* Cuts down displayed size of link if over 50 chars, turns absolute links -* into relative versions when the server/script path matches the link -*/ -function make_clickable($text, $server_url = false, $class = 'postlink') + * Replaces magic urls of form http://xxx.xxx., www.xxx. and xxx@xxx.xxx. + * Cuts down displayed size of link if over 50 chars, turns absolute links + * into relative versions when the server/script path matches the link + * + * @param string $text Message text to parse URL/email entries + * @param bool|string $server_url The server URL. If false, the board URL will be used + * @param string $class CSS class selector to add to the parsed URL entries + * + * @return string A text with parsed URL/email entries + */ +function make_clickable($text, $server_url = false, string $class = 'postlink') { if ($server_url === false) { @@ -948,39 +952,70 @@ function make_clickable($text, $server_url = false, $class = 'postlink') $magic_url_match_args = array(); } - // relative urls for this board - $magic_url_match_args[$server_url][] = array( - '#(^|[\n\t (>.])(' . preg_quote($server_url, '#') . ')/(' . get_preg_expression('relative_url_inline') . ')#iu', - MAGIC_URL_LOCAL, - $local_class, - ); + // Check if the match for this $server_url and $class already exists + $element_exists = false; + if (isset($magic_url_match_args[$server_url])) + { + array_walk_recursive($magic_url_match_args[$server_url], function($value) use (&$element_exists, $static_class) + { + if ($value == $static_class) + { + $element_exists = true; + return; + } + } + ); + } - // matches a xxxx://aaaaa.bbb.cccc. ... - $magic_url_match_args[$server_url][] = array( - '#(^|[\n\t (>.])(' . get_preg_expression('url_inline') . ')#iu', - MAGIC_URL_FULL, - $class, - ); + // Only add new $server_url and $class matches if not exist + if (!$element_exists) + { + // relative urls for this board + $magic_url_match_args[$server_url][] = [ + '#(^|[\n\t (>.])(' . preg_quote($server_url, '#') . ')/(' . get_preg_expression('relative_url_inline') . ')#iu', + MAGIC_URL_LOCAL, + $local_class, + $static_class, + ]; - // matches a "www.xxxx.yyyy[/zzzz]" kinda lazy URL thing - $magic_url_match_args[$server_url][] = array( - '#(^|[\n\t (>])(' . get_preg_expression('www_url_inline') . ')#iu', - MAGIC_URL_WWW, - $class, - ); + // matches a xxxx://aaaaa.bbb.cccc. ... + $magic_url_match_args[$server_url][] = [ + '#(^|[\n\t (>.])(' . get_preg_expression('url_inline') . ')#iu', + MAGIC_URL_FULL, + $class, + $static_class, + ]; - // matches an email@domain type address at the start of a line, or after a space or after what might be a BBCode. - $magic_url_match_args[$server_url][] = array( - '/(^|[\n\t (>])(' . get_preg_expression('email') . ')/iu', - MAGIC_URL_EMAIL, - '', - ); + // matches a "www.xxxx.yyyy[/zzzz]" kinda lazy URL thing + $magic_url_match_args[$server_url][] = [ + '#(^|[\n\t (>])(' . get_preg_expression('www_url_inline') . ')#iu', + MAGIC_URL_WWW, + $class, + $static_class, + ]; + } + + if (!isset($magic_url_match_args[$server_url]['email'])) + { + // matches an email@domain type address at the start of a line, or after a space or after what might be a BBCode. + $magic_url_match_args[$server_url]['email'] = [ + '/(^|[\n\t (>])(' . get_preg_expression('email') . ')/iu', + MAGIC_URL_EMAIL, + '', + ]; + } } foreach ($magic_url_match_args[$server_url] as $magic_args) { if (preg_match($magic_args[0], $text, $matches)) { + // Only apply $class from the corresponding function call argument (excepting emails which never has a class) + if ($magic_args[3] != $static_class && $magic_args[1] != MAGIC_URL_EMAIL) + { + continue; + } + $text = preg_replace_callback($magic_args[0], function($matches) use ($magic_args) { $relative_url = isset($matches[3]) ? $matches[3] : ''; diff --git a/tests/functions/make_clickable_test.php b/tests/functions/make_clickable_test.php index d8d5eb5e0e..e01a86b023 100644 --- a/tests/functions/make_clickable_test.php +++ b/tests/functions/make_clickable_test.php @@ -27,131 +27,173 @@ class phpbb_functions_make_clickable_test extends phpbb_test_case **/ public function data_test_make_clickable_url_positive() { - return array( - array( + return [ + [ 'http://www.phpbb.com/community/', 'http://www.phpbb.com/community/' - ), - array( + ], + [ 'http://www.phpbb.com/path/file.ext#section', 'http://www.phpbb.com/path/file.ext#section' - ), - array( + ], + [ 'ftp://ftp.phpbb.com/', 'ftp://ftp.phpbb.com/' - ), - array( + ], + [ 'sip://bantu@phpbb.com', 'sip://bantu@phpbb.com' - ), - array( + ], + [ 'www.phpbb.com/community/', 'www.phpbb.com/community/' - ), - array( + ], + [ 'http://testhost/viewtopic.php?t=1', 'viewtopic.php?t=1' - ), - array( + ], + [ 'javascript://testhost/viewtopic.php?t=1', 'javascript://testhost/viewtopic.php?t=1' - ), - array( + ], + [ "java\nscri\npt://testhost/viewtopic.php?t=1", "java\nscri\npt://testhost/viewtopic.php?t=1" - ), - array( + ], + [ 'email@domain.com', 'email@domain.com' - ), + ], // Test appending punctuation mark to the URL - array( + [ 'http://testhost/viewtopic.php?t=1!', 'viewtopic.php?t=1!' - ), - array( + ], + [ 'www.phpbb.com/community/?', 'www.phpbb.com/community/?' - ), + ], // Test shortened text for URL > 55 characters long // URL text should be turned into: first 39 chars + ' ... ' + last 10 chars - array( + [ 'http://www.phpbb.com/community/path/to/long/url/file.ext#section', 'http://www.phpbb.com/community/path/to/ ... xt#section' - ), - ); + ], + ]; } public function data_test_make_clickable_url_idn() { - return array( - array( + return [ + [ 'http://www.täst.de/community/', 'http://www.täst.de/community/' - ), - array( + ], + [ 'http://www.täst.de/path/file.ext#section', 'http://www.täst.de/path/file.ext#section' - ), - array( + ], + [ 'ftp://ftp.täst.de/', 'ftp://ftp.täst.de/' - ), - array( + ], + [ 'javascript://täst.de/', 'javascript://täst.de/' - ), - array( + ], + [ 'sip://bantu@täst.de', 'sip://bantu@täst.de' - ), - array( + ], + [ 'www.täst.de/community/', 'www.täst.de/community/' - ), + ], // Test appending punctuation mark to the URL - array( + [ 'http://домен.рф/viewtopic.php?t=1!', 'http://домен.рф/viewtopic.php?t=1!' - ), - array( + ], + [ 'www.домен.рф/сообщество/?', 'www.домен.рф/сообщество/?' - ), + ], // Test shortened text for URL > 55 characters long // URL text should be turned into: first 39 chars + ' ... ' + last 10 chars - array( + [ 'http://www.домен.рф/сообщество/путь/по/длинной/ссылке/file.ext#section', 'http://www.домен.рф/сообщество/путь/по/ ... xt#section' - ), + ], // IDN with invalid characters shouldn't be parsed correctly (only 'valid' part) - array( + [ 'http://www.täst╫.de', 'http://www.täst╫.de' - ), + ], // IDN in emails is unsupported yet - array('почта@домен.рф', 'почта@домен.рф'), - ); + ['почта@домен.рф', 'почта@домен.рф'], + ]; } public function data_test_make_clickable_local_url_idn() { - return array( - array( + return [ + [ 'http://www.домен.рф/viewtopic.php?t=1', 'viewtopic.php?t=1' - ), + ], // Test appending punctuation mark to the URL - array( + [ 'http://www.домен.рф/viewtopic.php?t=1!', 'viewtopic.php?t=1!' - ), - array( + ], + [ 'http://www.домен.рф/сообщество/?', 'сообщество/?' - ), - ); + ], + ]; + } + + public function data_test_make_clickable_custom_classes() + { + return [ + [ + 'http://www.домен.рф/viewtopic.php?t=1', + 'http://www.домен.рф', + 'class1', + 'viewtopic.php?t=1' + ], + [ + 'http://www.домен.рф/viewtopic.php?t=1!', + false, + 'class2', + 'http://www.домен.рф/viewtopic.php?t=1!' + ], + [ + 'http://www.домен.рф/сообщество/?', + false, + 'class3', + 'http://www.домен.рф/сообщество/?' + ], + [ + 'www.phpbb.com/community/', + false, + 'class2', + 'www.phpbb.com/community/' + ], + [ + 'http://testhost/viewtopic.php?t=1', + false, + 'class1', + 'viewtopic.php?t=1' + ], + [ + 'email@domain.com', + false, + 'class-email', + 'email@domain.com' + ], + ]; } protected function setUp(): void @@ -166,16 +208,9 @@ class phpbb_functions_make_clickable_test extends phpbb_test_case /** * @dataProvider data_test_make_clickable_url_positive - */ - public function test_urls_matching_positive($url, $expected) - { - $this->assertSame($expected, make_clickable($url)); - } - - /** * @dataProvider data_test_make_clickable_url_idn */ - public function test_urls_matching_idn($url, $expected) + public function test_urls_matching_positive($url, $expected) { $this->assertSame($expected, make_clickable($url)); } @@ -187,4 +222,12 @@ class phpbb_functions_make_clickable_test extends phpbb_test_case { $this->assertSame($expected, make_clickable($url, "http://www.домен.рф")); } + + /** + * @dataProvider data_test_make_clickable_custom_classes + */ + public function test_make_clickable_custom_classes($url, $server_url, $class, $expected) + { + $this->assertSame($expected, make_clickable($url, $server_url, $class)); + } } diff --git a/tests/functions_user/whois_test.php b/tests/functions_user/whois_test.php new file mode 100644 index 0000000000..b99854ba60 --- /dev/null +++ b/tests/functions_user/whois_test.php @@ -0,0 +1,51 @@ +getMockBuilder('\phpbb\user') + ->setConstructorArgs([ + new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)), + '\phpbb\datetime', + ]) + ->getMock(); + $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); + $config = new \phpbb\config\config([]); + $request = $this->getMockBuilder('\phpbb\request\request') + ->getMock(); + $symfony_request = $this->getMockBuilder('\phpbb\symfony_request') + ->disableOriginalConstructor() + ->getMock(); + } + + public function ips_data() + { + return [ + ['2001:4860:4860::8888'], // Google public DNS + ['64.233.161.139'], // google.com + ]; + } + + /** + * @dataProvider ips_data + */ + public function test_ip_whois($ip) + { + $ip_whois = user_ipwhois($ip); + $this->assertStringNotContainsString('Query terms are ambiguous', $ip_whois); + $this->assertStringNotContainsString('no entries found', $ip_whois); + $this->assertStringNotContainsString('ERROR', $ip_whois); + } +}