diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php
index 37b448df9f..3c049a1153 100644
--- a/phpBB/includes/constants.php
+++ b/phpBB/includes/constants.php
@@ -141,6 +141,12 @@ define('BBCODE_UID_LEN', 5);
// Number of core BBCodes
define('NUM_CORE_BBCODES', 12);
+// Magic url types
+define('MAGIC_URL_EMAIL', 1);
+define('MAGIC_URL_FULL', 2);
+define('MAGIC_URL_LOCAL', 3);
+define('MAGIC_URL_WWW', 4);
+
// Profile Field Types
define('FIELD_INT', 1);
define('FIELD_STRING', 2);
diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php
index c7d77da408..079d09ac94 100644
--- a/phpBB/includes/functions.php
+++ b/phpBB/includes/functions.php
@@ -2599,6 +2599,113 @@ function generate_text_for_edit($text, $uid, $flags)
);
}
+/**
+* A subroutine of make_clickable used with preg_replace
+* It places correct HTML around an url, shortens the displayed text
+* and makes sure no entities are inside URLs
+*/
+function make_clickable_callback($type, $whitespace, $url, $relative_url, $class)
+{
+ $append = '';
+ $url = htmlspecialchars_decode($url);
+ $relative_url = htmlspecialchars_decode($relative_url);
+
+ // make sure no HTML entities were matched
+ $chars = array('<', '>', '"');
+ $split = false;
+ foreach ($chars as $char)
+ {
+ $next_split = strpos($url, $char);
+ if ($next_split !== false)
+ {
+ $split = ($split !== false) ? min($split, $next_split) : $next_split;
+ }
+ }
+
+ if ($split !== false)
+ {
+ // an HTML entity was found, so the URL has to end before it
+ $append = substr($url, $split) . $relative_url;
+ $url = substr($url, 0, $split);
+ $relative_url = '';
+ }
+ else if ($relative_url)
+ {
+ // same for $relative_url
+ $split = false;
+ foreach ($chars as $char)
+ {
+ $next_split = strpos($relative_url, $char);
+ if ($next_split !== false)
+ {
+ $split = ($split !== false) ? min($split, $next_split) : $next_split;
+ }
+ }
+
+ if ($split !== false)
+ {
+ $append = substr($relative_url, $split);
+ $relative_url = substr($relative_url, 0, $split);
+ }
+ }
+
+ // if the last character of the url is a punctuation mark, exclude it from the url
+ $last_char = ($relative_url) ? $relative_url[strlen($relative_url) - 1] : $url[strlen($url) - 1];
+
+ switch ($last_char)
+ {
+ case '.':
+ case '?':
+ case '!':
+ case ':':
+ case ',':
+ $append = $last_char;
+ if ($relative_url)
+ {
+ $relative_url = substr($relative_url, 0, -1);
+ }
+ else
+ {
+ $url = substr($url, 0, -1);
+ }
+ }
+
+ switch ($type)
+ {
+ case MAGIC_URL_LOCAL:
+ $tag = 'l';
+ $relative_url = preg_replace('/[&?]sid=[0-9a-f]{32}$/', '', preg_replace('/([&?])sid=[0-9a-f]{32}&/', '$1', $relative_url));
+ $url = $url . '/' . $relative_url;
+ $text = ($relative_url) ? $relative_url : $url . '/';
+ break;
+
+ case MAGIC_URL_FULL:
+ $tag = 'm';
+ $text = (strlen($url) > 55) ? substr($url, 0, 39) . ' ... ' . substr($url, -10) : $url;
+ break;
+
+ case MAGIC_URL_WWW:
+ $tag = 'w';
+ $url = 'http://' . $url;
+ $text = (strlen($url) > 55) ? substr($url, 0, 39) . ' ... ' . substr($url, -10) : $url;
+ break;
+
+ case MAGIC_URL_EMAIL:
+ $tag = 'e';
+ $url = 'mailto:' . $url;
+ $text = (strlen($url) > 55) ? substr($url, 0, 39) . ' ... ' . substr($url, -10) : $url;
+ break;
+ }
+
+ $url = htmlspecialchars($url);
+ $text = htmlspecialchars($text);
+ $append = htmlspecialchars($append);
+
+ $html = "$whitespace$text$append";
+
+ return $html;
+}
+
/**
* make_clickable function
*
@@ -2627,20 +2734,20 @@ function make_clickable($text, $server_url = false, $class = 'postlink')
// Be sure to not let the matches cross over. ;)
// relative urls for this board
- $magic_url_match[] = '#(^|[\n\t (>])(' . preg_quote($server_url, '#') . ')/(' . get_preg_expression('relative_url_inline') . ')#ie';
- $magic_url_replace[] = "'\$1' . ((strlen('\$3')) ? preg_replace('/(&|\?)sid=[0-9a-f]{32}$/', '', preg_replace('/(&|\?)sid=[0-9a-f]{32}&/', '\\\\1', '\$3')) : '\$2/') . ''";
+ $magic_url_match[] = '#(^|[\n\t (>\]])(' . preg_quote($server_url, '#') . ')/(' . get_preg_expression('relative_url_inline') . ')#ie';
+ $magic_url_replace[] = "make_clickable_callback(MAGIC_URL_LOCAL, '\$1', '\$2', '\$3', '$local_class')";
// matches a xxxx://aaaaa.bbb.cccc. ...
- $magic_url_match[] = '#(^|[\n\t (>])(' . get_preg_expression('url_inline') . ')#ie';
- $magic_url_replace[] = "'\$1' . ((strlen('\$2') > 55) ? str_replace('&', '&', substr(str_replace('&', '&', '\$2'), 0, 39)) . ' ... ' . str_replace('&', '&', substr(str_replace('&', '&', '\$2'), -10)) : '\$2') . ''";
+ $magic_url_match[] = '#(^|[\n\t (>\]])(' . get_preg_expression('url_inline') . ')#ie';
+ $magic_url_replace[] = "make_clickable_callback(MAGIC_URL_FULL, '\$1', '\$2', '', '$class')";
// matches a "www.xxxx.yyyy[/zzzz]" kinda lazy URL thing
- $magic_url_match[] = '#(^|[\n\t (>])(' . get_preg_expression('www_url_inline') . ')#ie';
- $magic_url_replace[] = "'\$1' . ((strlen('\$2') > 55) ? str_replace('&', '&', substr(str_replace('&', '&', '\$2'), 0, 39)) . ' ... ' . str_replace('&', '&', substr(str_replace('&', '&', '\$2'), -10)) : '\$2') . ''";
+ $magic_url_match[] = '#(^|[\n\t (>\]])(' . get_preg_expression('www_url_inline') . ')#ie';
+ $magic_url_replace[] = "make_clickable_callback(MAGIC_URL_WWW, '\$1', '\$2', '', '$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[] = '/(^|[\n\t (>])(' . get_preg_expression('email') . ')/ie';
- $magic_url_replace[] = "'\$1' . ((strlen('\$2') > 55) ? substr('\$2', 0, 39) . ' ... ' . substr('\$2', -10) : '\$2') . ''";
+ $magic_url_match[] = '/(^|[\n\t (>\]])(' . get_preg_expression('email') . ')/ie';
+ $magic_url_replace[] = "make_clickable_callback(MAGIC_URL_EMAIL, array('\$1', '\$2'), '')";
}
return preg_replace($magic_url_match, $magic_url_replace, $text);
@@ -3303,6 +3410,33 @@ function get_preg_expression($mode)
return '';
}
+/**
+* Returns the first 4 blocks of the specified IPv6 address and as many
+* as specified in the length paramater additional ones.
+* If length is zero, then an empty string is returned.
+*/
+function short_ipv6($ip, $length)
+{
+ if ($length < 1)
+ {
+ return '';
+ }
+
+ // extend IPv6 addresses
+ $blocks = substr_count($ip, ':') + 1;
+ if ($blocks < 9)
+ {
+ $ip = str_replace('::', ':' . str_repeat('0000:', 9 - $blocks), $ip);
+ }
+ if ($ip[0] == ':')
+ {
+ $ip = '0000' . $ip;
+ }
+ $ip = implode(':', array_slice(explode(':', $ip), 0, 4 + $length));
+
+ return $ip;
+}
+
/**
* Truncates string while retaining special characters if going over the max length
* The default max length is 60 at the moment
diff --git a/phpBB/includes/message_parser.php b/phpBB/includes/message_parser.php
index 52bba31da3..9b3dcad871 100644
--- a/phpBB/includes/message_parser.php
+++ b/phpBB/includes/message_parser.php
@@ -1066,23 +1066,8 @@ class parse_message extends bbcode_firstpass
// Parse URL's
if ($allow_magic_url)
{
- $replaced = false;
-
- // We have the bbcode uid here, let's at least try to circumvent a specific bug...
- if ($allow_bbcode && strpos($this->message, '[/quote:' . $this->bbcode_uid . ']') !== false && strpos($this->message, '":' . $this->bbcode_uid . ']') !== false)
- {
- $this->message = str_replace('":' . $this->bbcode_uid . ']', '"":' . $this->bbcode_uid . ']', $this->message);
- $replaced = true;
- }
-
$this->magic_url(generate_board_url());
- // Revert our change above
- if ($replaced)
- {
- $this->message = str_replace('"":' . $this->bbcode_uid . ']', '":' . $this->bbcode_uid . ']', $this->message);
- }
-
if ($config['max_' . $mode . '_urls'])
{
$num_urls += preg_match_all('#\