diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php
index 146dedf47..f51d7f27b 100644
--- a/src/Content/Text/BBCode.php
+++ b/src/Content/Text/BBCode.php
@@ -1289,6 +1289,310 @@ class BBCode extends BaseObject
// Handle attached links or videos
$text = self::convertAttachment($text, $simple_html, $try_oembed);
+ // leave open the posibility of [map=something]
+ // this is replaced in Item::prepareBody() which has knowledge of the item location
+ if (strpos($text, '[/map]') !== false) {
+ $text = preg_replace_callback(
+ "/\[map\](.*?)\[\/map\]/ism",
+ function ($match) use ($simple_html) {
+ return str_replace($match[0], '
' . Map::byLocation($match[1], $simple_html) . '
', $match[0]);
+ },
+ $text
+ );
+ }
+
+ if (strpos($text, '[map=') !== false) {
+ $text = preg_replace_callback(
+ "/\[map=(.*?)\]/ism",
+ function ($match) use ($simple_html) {
+ return str_replace($match[0], '' . Map::byCoordinates(str_replace('/', ' ', $match[1]), $simple_html) . '
', $match[0]);
+ },
+ $text
+ );
+ }
+
+ if (strpos($text, '[map]') !== false) {
+ $text = preg_replace("/\[map\]/", '
', $text);
+ }
+
+ // Check for headers
+ $text = preg_replace("(\[h1\](.*?)\[\/h1\])ism", '$1 ', $text);
+ $text = preg_replace("(\[h2\](.*?)\[\/h2\])ism", '$1 ', $text);
+ $text = preg_replace("(\[h3\](.*?)\[\/h3\])ism", '$1 ', $text);
+ $text = preg_replace("(\[h4\](.*?)\[\/h4\])ism", '$1 ', $text);
+ $text = preg_replace("(\[h5\](.*?)\[\/h5\])ism", '$1 ', $text);
+ $text = preg_replace("(\[h6\](.*?)\[\/h6\])ism", '$1 ', $text);
+
+ // Check for paragraph
+ $text = preg_replace("(\[p\](.*?)\[\/p\])ism", '$1
', $text);
+
+ // Check for bold text
+ $text = preg_replace("(\[b\](.*?)\[\/b\])ism", '$1 ', $text);
+
+ // Check for Italics text
+ $text = preg_replace("(\[i\](.*?)\[\/i\])ism", '$1 ', $text);
+
+ // Check for Underline text
+ $text = preg_replace("(\[u\](.*?)\[\/u\])ism", '$1 ', $text);
+
+ // Check for strike-through text
+ $text = preg_replace("(\[s\](.*?)\[\/s\])ism", '$1 ', $text);
+
+ // Check for over-line text
+ $text = preg_replace("(\[o\](.*?)\[\/o\])ism", '$1 ', $text);
+
+ // Check for colored text
+ $text = preg_replace("(\[color=(.*?)\](.*?)\[\/color\])ism", "$2 ", $text);
+
+ // Check for sized text
+ // [size=50] --> font-size: 50px (with the unit).
+ $text = preg_replace("(\[size=(\d*?)\](.*?)\[\/size\])ism", "$2 ", $text);
+ $text = preg_replace("(\[size=(.*?)\](.*?)\[\/size\])ism", "$2 ", $text);
+
+ // Check for centered text
+ $text = preg_replace("(\[center\](.*?)\[\/center\])ism", "$1
", $text);
+
+ // Check for list text
+ $text = str_replace("[*]", "", $text);
+
+ // Check for style sheet commands
+ $text = preg_replace_callback(
+ "(\[style=(.*?)\](.*?)\[\/style\])ism",
+ function ($match) {
+ return "" . $match[2] . " ";
+ },
+ $text
+ );
+
+ // Check for CSS classes
+ $text = preg_replace_callback(
+ "(\[class=(.*?)\](.*?)\[\/class\])ism",
+ function ($match) {
+ return "" . $match[2] . " ";
+ },
+ $text
+ );
+
+ // handle nested lists
+ $endlessloop = 0;
+
+ while ((((strpos($text, "[/list]") !== false) && (strpos($text, "[list") !== false)) ||
+ ((strpos($text, "[/ol]") !== false) && (strpos($text, "[ol]") !== false)) ||
+ ((strpos($text, "[/ul]") !== false) && (strpos($text, "[ul]") !== false)) ||
+ ((strpos($text, "[/li]") !== false) && (strpos($text, "[li]") !== false))) && (++$endlessloop < 20)) {
+ $text = preg_replace("/\[list\](.*?)\[\/list\]/ism", '', $text);
+ $text = preg_replace("/\[list=\](.*?)\[\/list\]/ism", '', $text);
+ $text = preg_replace("/\[list=1\](.*?)\[\/list\]/ism", '', $text);
+ $text = preg_replace("/\[list=((?-i)i)\](.*?)\[\/list\]/ism", '', $text);
+ $text = preg_replace("/\[list=((?-i)I)\](.*?)\[\/list\]/ism", '', $text);
+ $text = preg_replace("/\[list=((?-i)a)\](.*?)\[\/list\]/ism", '', $text);
+ $text = preg_replace("/\[list=((?-i)A)\](.*?)\[\/list\]/ism", '', $text);
+ $text = preg_replace("/\[ul\](.*?)\[\/ul\]/ism", '', $text);
+ $text = preg_replace("/\[ol\](.*?)\[\/ol\]/ism", '', $text);
+ $text = preg_replace("/\[li\](.*?)\[\/li\]/ism", ' $1 ', $text);
+ }
+
+ $text = preg_replace("/\[th\](.*?)\[\/th\]/sm", '$1 ', $text);
+ $text = preg_replace("/\[td\](.*?)\[\/td\]/sm", '$1 ', $text);
+ $text = preg_replace("/\[tr\](.*?)\[\/tr\]/sm", '$1 ', $text);
+ $text = preg_replace("/\[table\](.*?)\[\/table\]/sm", '', $text);
+
+ $text = preg_replace("/\[table border=1\](.*?)\[\/table\]/sm", '', $text);
+ $text = preg_replace("/\[table border=0\](.*?)\[\/table\]/sm", '', $text);
+
+ $text = str_replace('[hr]', ' ', $text);
+
+ // This is actually executed in Item::prepareBody()
+
+ $text = str_replace('[nosmile]', '', $text);
+
+ // Check for font change text
+ $text = preg_replace("/\[font=(.*?)\](.*?)\[\/font\]/sm", "$2 ", $text);
+
+ // Declare the format for [spoiler] layout
+ $SpoilerLayout = '$1 ';
+
+ // Check for [spoiler] text
+ // handle nested quotes
+ $endlessloop = 0;
+ while ((strpos($text, "[/spoiler]") !== false) && (strpos($text, "[spoiler]") !== false) && (++$endlessloop < 20)) {
+ $text = preg_replace("/\[spoiler\](.*?)\[\/spoiler\]/ism", "$SpoilerLayout", $text);
+ }
+
+ // Check for [spoiler=Author] text
+
+ $t_wrote = L10n::t('$1 wrote:');
+
+ // handle nested quotes
+ $endlessloop = 0;
+ while ((strpos($text, "[/spoiler]")!== false) && (strpos($text, "[spoiler=") !== false) && (++$endlessloop < 20)) {
+ $text = preg_replace("/\[spoiler=[\"\']*(.*?)[\"\']*\](.*?)\[\/spoiler\]/ism",
+ "" . $t_wrote . " $2 ",
+ $text);
+ }
+
+ // Declare the format for [quote] layout
+ $QuoteLayout = '$1 ';
+
+ // Check for [quote] text
+ // handle nested quotes
+ $endlessloop = 0;
+ while ((strpos($text, "[/quote]") !== false) && (strpos($text, "[quote]") !== false) && (++$endlessloop < 20)) {
+ $text = preg_replace("/\[quote\](.*?)\[\/quote\]/ism", "$QuoteLayout", $text);
+ }
+
+ // Check for [quote=Author] text
+
+ $t_wrote = L10n::t('$1 wrote:');
+
+ // handle nested quotes
+ $endlessloop = 0;
+ while ((strpos($text, "[/quote]")!== false) && (strpos($text, "[quote=") !== false) && (++$endlessloop < 20)) {
+ $text = preg_replace("/\[quote=[\"\']*(.*?)[\"\']*\](.*?)\[\/quote\]/ism",
+ "" . $t_wrote . "
$2 ",
+ $text);
+ }
+
+
+ // [img=widthxheight]image source[/img]
+ $text = preg_replace_callback(
+ "/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism",
+ function ($matches) use ($simple_html) {
+ if (strpos($matches[3], "data:image/") === 0) {
+ return $matches[0];
+ }
+
+ $matches[3] = self::proxyUrl($matches[3], $simple_html);
+ return "[img=" . $matches[1] . "x" . $matches[2] . "]" . $matches[3] . "[/img]";
+ },
+ $text
+ );
+
+ $text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", ' ', $text);
+ $text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*)\](.*?)\[\/zmg\]/ism", ' ', $text);
+
+ $text = preg_replace_callback("/\[img\=([$URLSearchString]*)\](.*?)\[\/img\]/ism",
+ function ($matches) use ($simple_html) {
+ $matches[1] = self::proxyUrl($matches[1], $simple_html);
+ $matches[2] = htmlspecialchars($matches[2], ENT_COMPAT);
+ return ' ';
+ },
+ $text);
+
+ // Images
+ // [img]pathtoimage[/img]
+ $text = preg_replace_callback(
+ "/\[img\](.*?)\[\/img\]/ism",
+ function ($matches) use ($simple_html) {
+ if (strpos($matches[1], "data:image/") === 0) {
+ return $matches[0];
+ }
+
+ $matches[1] = self::proxyUrl($matches[1], $simple_html);
+ return "[img]" . $matches[1] . "[/img]";
+ },
+ $text
+ );
+
+ $text = preg_replace("/\[img\](.*?)\[\/img\]/ism", ' ', $text);
+ $text = preg_replace("/\[zmg\](.*?)\[\/zmg\]/ism", ' ', $text);
+
+ // Shared content
+ $text = self::convertShare(
+ $text,
+ function (array $attributes, array $author_contact, $content, $is_quote_share) use ($simple_html) {
+ return self::convertShareCallback($attributes, $author_contact, $content, $is_quote_share, $simple_html);
+ }
+ );
+
+ $text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism", ' ', $text);
+ $text = preg_replace("/\[crypt(.*?)\](.*?)\[\/crypt\]/ism", ' ', $text);
+ //$Text = preg_replace("/\[crypt=(.*?)\](.*?)\[\/crypt\]/ism", ' ', $Text);
+
+ // Try to Oembed
+ if ($try_oembed) {
+ $text = preg_replace("/\[video\](.*?\.(ogg|ogv|oga|ogm|webm|mp4).*?)\[\/video\]/ism", '$1 ', $text);
+ $text = preg_replace("/\[audio\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mp3).*?)\[\/audio\]/ism", '$1 ', $text);
+
+ $text = preg_replace_callback("/\[video\](.*?)\[\/video\]/ism", $try_oembed_callback, $text);
+ $text = preg_replace_callback("/\[audio\](.*?)\[\/audio\]/ism", $try_oembed_callback, $text);
+ } else {
+ $text = preg_replace("/\[video\](.*?)\[\/video\]/ism",
+ '$1 ', $text);
+ $text = preg_replace("/\[audio\](.*?)\[\/audio\]/ism",
+ '$1 ', $text);
+ }
+
+ // html5 video and audio
+
+
+ if ($try_oembed) {
+ $text = preg_replace("/\[iframe\](.*?)\[\/iframe\]/ism", '', $text);
+ } else {
+ $text = preg_replace("/\[iframe\](.*?)\[\/iframe\]/ism", '$1 ', $text);
+ }
+
+ // Youtube extensions
+ if ($try_oembed) {
+ $text = preg_replace_callback("/\[youtube\](https?:\/\/www.youtube.com\/watch\?v\=.*?)\[\/youtube\]/ism", $try_oembed_callback, $text);
+ $text = preg_replace_callback("/\[youtube\](www.youtube.com\/watch\?v\=.*?)\[\/youtube\]/ism", $try_oembed_callback, $text);
+ $text = preg_replace_callback("/\[youtube\](https?:\/\/youtu.be\/.*?)\[\/youtube\]/ism", $try_oembed_callback, $text);
+ }
+
+ $text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text);
+ $text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/embed\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text);
+ $text = preg_replace("/\[youtube\]https?:\/\/youtu.be\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text);
+
+ if ($try_oembed) {
+ $text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", 'VIDEO ', $text);
+ } else {
+ $text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism",
+ 'https://www.youtube.com/watch?v=$1 ', $text);
+ }
+
+ if ($try_oembed) {
+ $text = preg_replace_callback("/\[vimeo\](https?:\/\/player.vimeo.com\/video\/[0-9]+).*?\[\/vimeo\]/ism", $try_oembed_callback, $text);
+ $text = preg_replace_callback("/\[vimeo\](https?:\/\/vimeo.com\/[0-9]+).*?\[\/vimeo\]/ism", $try_oembed_callback, $text);
+ }
+
+ $text = preg_replace("/\[vimeo\]https?:\/\/player.vimeo.com\/video\/([0-9]+)(.*?)\[\/vimeo\]/ism", '[vimeo]$1[/vimeo]', $text);
+ $text = preg_replace("/\[vimeo\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/vimeo\]/ism", '[vimeo]$1[/vimeo]', $text);
+
+ if ($try_oembed) {
+ $text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", '', $text);
+ } else {
+ $text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism",
+ 'https://vimeo.com/$1 ', $text);
+ }
+
+ // oembed tag
+ $text = OEmbed::BBCode2HTML($text);
+
+ // Avoid triple linefeeds through oembed
+ $text = str_replace(" ", " ", $text);
+
+ // If we found an event earlier, strip out all the event code and replace with a reformatted version.
+ // Replace the event-start section with the entire formatted event. The other bbcode is stripped.
+ // Summary (e.g. title) is required, earlier revisions only required description (in addition to
+ // start which is always required). Allow desc with a missing summary for compatibility.
+
+ if ((!empty($ev['desc']) || !empty($ev['summary'])) && !empty($ev['start'])) {
+ $sub = Event::getHTML($ev, $simple_html);
+
+ $text = preg_replace("/\[event\-summary\](.*?)\[\/event\-summary\]/ism", '', $text);
+ $text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/ism", '', $text);
+ $text = preg_replace("/\[event\-start\](.*?)\[\/event\-start\]/ism", $sub, $text);
+ $text = preg_replace("/\[event\-finish\](.*?)\[\/event\-finish\]/ism", '', $text);
+ $text = preg_replace("/\[event\-location\](.*?)\[\/event\-location\]/ism", '', $text);
+ $text = preg_replace("/\[event\-adjust\](.*?)\[\/event\-adjust\]/ism", '', $text);
+ $text = preg_replace("/\[event\-id\](.*?)\[\/event\-id\]/ism", '', $text);
+ }
+
+ // Replace non graphical smilies for external posts
+ if ($simple_html) {
+ $text = Smilies::replace($text);
+ }
+
// if the HTML is used to generate plain text, then don't do this search, but replace all URL of that kind to text
if (!$for_plaintext) {
$text = preg_replace(Strings::autoLinkRegEx(), '[url]$1[/url]', $text);
@@ -1385,7 +1689,7 @@ class BBCode extends BaseObject
// convert links start with System::baseUrl() as local link without the target="_blank" attribute
$escapedBaseUrl = preg_quote(System::baseUrl(), '/');
$text = preg_replace("/\[url\](".$escapedBaseUrl."[$URLSearchString]*)\[\/url\]/ism", '$1 ', $text);
- $text = preg_replace("/\[url\=(".$escapedBaseUrl."[$URLSearchString]*)\](.*?)\[\/url\]/ism", '$2 ', $text);
+ $text = preg_replace("/\[url\=(".$escapedBaseUrl."[$URLSearchString]*)\](.*?)\[\/url\]/ism", '$2 ', $text);
$text = preg_replace("/\[url\]([$URLSearchString]*)\[\/url\]/ism", '$1 ', $text);
$text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$2 ', $text);
@@ -1403,309 +1707,6 @@ class BBCode extends BaseObject
$text = preg_replace("/\[mail\]([$MAILSearchString]*)\[\/mail\]/", '$1 ', $text);
$text = preg_replace("/\[mail\=([$MAILSearchString]*)\](.*?)\[\/mail\]/", '$2 ', $text);
- // leave open the posibility of [map=something]
- // this is replaced in Item::prepareBody() which has knowledge of the item location
-
- if (strpos($text, '[/map]') !== false) {
- $text = preg_replace_callback(
- "/\[map\](.*?)\[\/map\]/ism",
- function ($match) use ($simple_html) {
- return str_replace($match[0], '' . Map::byLocation($match[1], $simple_html) . '
', $match[0]);
- },
- $text
- );
- }
- if (strpos($text, '[map=') !== false) {
- $text = preg_replace_callback(
- "/\[map=(.*?)\]/ism",
- function ($match) use ($simple_html) {
- return str_replace($match[0], '' . Map::byCoordinates(str_replace('/', ' ', $match[1]), $simple_html) . '
', $match[0]);
- },
- $text
- );
- }
- if (strpos($text, '[map]') !== false) {
- $text = preg_replace("/\[map\]/", '
', $text);
- }
-
- // Check for headers
- $text = preg_replace("(\[h1\](.*?)\[\/h1\])ism", '$1 ', $text);
- $text = preg_replace("(\[h2\](.*?)\[\/h2\])ism", '$1 ', $text);
- $text = preg_replace("(\[h3\](.*?)\[\/h3\])ism", '$1 ', $text);
- $text = preg_replace("(\[h4\](.*?)\[\/h4\])ism", '$1 ', $text);
- $text = preg_replace("(\[h5\](.*?)\[\/h5\])ism", '$1 ', $text);
- $text = preg_replace("(\[h6\](.*?)\[\/h6\])ism", '$1 ', $text);
-
- // Check for paragraph
- $text = preg_replace("(\[p\](.*?)\[\/p\])ism", '$1
', $text);
-
- // Check for bold text
- $text = preg_replace("(\[b\](.*?)\[\/b\])ism", '$1 ', $text);
-
- // Check for Italics text
- $text = preg_replace("(\[i\](.*?)\[\/i\])ism", '$1 ', $text);
-
- // Check for Underline text
- $text = preg_replace("(\[u\](.*?)\[\/u\])ism", '$1 ', $text);
-
- // Check for strike-through text
- $text = preg_replace("(\[s\](.*?)\[\/s\])ism", '$1 ', $text);
-
- // Check for over-line text
- $text = preg_replace("(\[o\](.*?)\[\/o\])ism", '$1 ', $text);
-
- // Check for colored text
- $text = preg_replace("(\[color=(.*?)\](.*?)\[\/color\])ism", "$2 ", $text);
-
- // Check for sized text
- // [size=50] --> font-size: 50px (with the unit).
- $text = preg_replace("(\[size=(\d*?)\](.*?)\[\/size\])ism", "$2 ", $text);
- $text = preg_replace("(\[size=(.*?)\](.*?)\[\/size\])ism", "$2 ", $text);
-
- // Check for centered text
- $text = preg_replace("(\[center\](.*?)\[\/center\])ism", "$1
", $text);
-
- // Check for list text
- $text = str_replace("[*]", "", $text);
-
- // Check for style sheet commands
- $text = preg_replace_callback(
- "(\[style=(.*?)\](.*?)\[\/style\])ism",
- function ($match) {
- return "" . $match[2] . " ";
- },
- $text
- );
-
- // Check for CSS classes
- $text = preg_replace_callback(
- "(\[class=(.*?)\](.*?)\[\/class\])ism",
- function ($match) {
- return "" . $match[2] . " ";
- },
- $text
- );
-
- // handle nested lists
- $endlessloop = 0;
-
- while ((((strpos($text, "[/list]") !== false) && (strpos($text, "[list") !== false)) ||
- ((strpos($text, "[/ol]") !== false) && (strpos($text, "[ol]") !== false)) ||
- ((strpos($text, "[/ul]") !== false) && (strpos($text, "[ul]") !== false)) ||
- ((strpos($text, "[/li]") !== false) && (strpos($text, "[li]") !== false))) && (++$endlessloop < 20)) {
- $text = preg_replace("/\[list\](.*?)\[\/list\]/ism", '', $text);
- $text = preg_replace("/\[list=\](.*?)\[\/list\]/ism", '', $text);
- $text = preg_replace("/\[list=1\](.*?)\[\/list\]/ism", '', $text);
- $text = preg_replace("/\[list=((?-i)i)\](.*?)\[\/list\]/ism", '', $text);
- $text = preg_replace("/\[list=((?-i)I)\](.*?)\[\/list\]/ism", '', $text);
- $text = preg_replace("/\[list=((?-i)a)\](.*?)\[\/list\]/ism", '', $text);
- $text = preg_replace("/\[list=((?-i)A)\](.*?)\[\/list\]/ism", '', $text);
- $text = preg_replace("/\[ul\](.*?)\[\/ul\]/ism", '', $text);
- $text = preg_replace("/\[ol\](.*?)\[\/ol\]/ism", '', $text);
- $text = preg_replace("/\[li\](.*?)\[\/li\]/ism", ' $1 ', $text);
- }
-
- $text = preg_replace("/\[th\](.*?)\[\/th\]/sm", '$1 ', $text);
- $text = preg_replace("/\[td\](.*?)\[\/td\]/sm", '$1 ', $text);
- $text = preg_replace("/\[tr\](.*?)\[\/tr\]/sm", '$1 ', $text);
- $text = preg_replace("/\[table\](.*?)\[\/table\]/sm", '', $text);
-
- $text = preg_replace("/\[table border=1\](.*?)\[\/table\]/sm", '', $text);
- $text = preg_replace("/\[table border=0\](.*?)\[\/table\]/sm", '', $text);
-
- $text = str_replace('[hr]', ' ', $text);
-
- // This is actually executed in Item::prepareBody()
-
- $text = str_replace('[nosmile]', '', $text);
-
- // Check for font change text
- $text = preg_replace("/\[font=(.*?)\](.*?)\[\/font\]/sm", "$2 ", $text);
-
- // Declare the format for [spoiler] layout
- $SpoilerLayout = '$1 ';
-
- // Check for [spoiler] text
- // handle nested quotes
- $endlessloop = 0;
- while ((strpos($text, "[/spoiler]") !== false) && (strpos($text, "[spoiler]") !== false) && (++$endlessloop < 20)) {
- $text = preg_replace("/\[spoiler\](.*?)\[\/spoiler\]/ism", "$SpoilerLayout", $text);
- }
-
- // Check for [spoiler=Author] text
-
- $t_wrote = L10n::t('$1 wrote:');
-
- // handle nested quotes
- $endlessloop = 0;
- while ((strpos($text, "[/spoiler]")!== false) && (strpos($text, "[spoiler=") !== false) && (++$endlessloop < 20)) {
- $text = preg_replace("/\[spoiler=[\"\']*(.*?)[\"\']*\](.*?)\[\/spoiler\]/ism",
- "" . $t_wrote . " $2 ",
- $text);
- }
-
- // Declare the format for [quote] layout
- $QuoteLayout = '$1 ';
-
- // Check for [quote] text
- // handle nested quotes
- $endlessloop = 0;
- while ((strpos($text, "[/quote]") !== false) && (strpos($text, "[quote]") !== false) && (++$endlessloop < 20)) {
- $text = preg_replace("/\[quote\](.*?)\[\/quote\]/ism", "$QuoteLayout", $text);
- }
-
- // Check for [quote=Author] text
-
- $t_wrote = L10n::t('$1 wrote:');
-
- // handle nested quotes
- $endlessloop = 0;
- while ((strpos($text, "[/quote]")!== false) && (strpos($text, "[quote=") !== false) && (++$endlessloop < 20)) {
- $text = preg_replace("/\[quote=[\"\']*(.*?)[\"\']*\](.*?)\[\/quote\]/ism",
- "" . $t_wrote . "
$2 ",
- $text);
- }
-
-
- // [img=widthxheight]image source[/img]
- $text = preg_replace_callback(
- "/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism",
- function ($matches) use ($simple_html) {
- if (strpos($matches[3], "data:image/") === 0) {
- return $matches[0];
- }
-
- $matches[3] = self::proxyUrl($matches[3], $simple_html);
- return "[img=" . $matches[1] . "x" . $matches[2] . "]" . $matches[3] . "[/img]";
- },
- $text
- );
-
- $text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", ' ', $text);
- $text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*)\](.*?)\[\/zmg\]/ism", ' ', $text);
-
- $text = preg_replace_callback("/\[img\=([$URLSearchString]*)\](.*?)\[\/img\]/ism",
- function ($matches) use ($simple_html) {
- $matches[1] = self::proxyUrl($matches[1], $simple_html);
- $matches[2] = htmlspecialchars($matches[2], ENT_COMPAT);
- return ' ';
- },
- $text);
-
- // Images
- // [img]pathtoimage[/img]
- $text = preg_replace_callback(
- "/\[img\](.*?)\[\/img\]/ism",
- function ($matches) use ($simple_html) {
- if (strpos($matches[1], "data:image/") === 0) {
- return $matches[0];
- }
-
- $matches[1] = self::proxyUrl($matches[1], $simple_html);
- return "[img]" . $matches[1] . "[/img]";
- },
- $text
- );
-
- $text = preg_replace("/\[img\](.*?)\[\/img\]/ism", ' ', $text);
- $text = preg_replace("/\[zmg\](.*?)\[\/zmg\]/ism", ' ', $text);
-
- // Shared content
- $text = self::convertShare(
- $text,
- function (array $attributes, array $author_contact, $content, $is_quote_share) use ($simple_html) {
- return self::convertShareCallback($attributes, $author_contact, $content, $is_quote_share, $simple_html);
- }
- );
-
- $text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism", ' ', $text);
- $text = preg_replace("/\[crypt(.*?)\](.*?)\[\/crypt\]/ism", ' ', $text);
- //$Text = preg_replace("/\[crypt=(.*?)\](.*?)\[\/crypt\]/ism", ' ', $Text);
-
- // Try to Oembed
- if ($try_oembed) {
- $text = preg_replace("/\[video\](.*?\.(ogg|ogv|oga|ogm|webm|mp4).*?)\[\/video\]/ism", '$1 ', $text);
- $text = preg_replace("/\[audio\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mp3).*?)\[\/audio\]/ism", '$1 ', $text);
-
- $text = preg_replace_callback("/\[video\](.*?)\[\/video\]/ism", $try_oembed_callback, $text);
- $text = preg_replace_callback("/\[audio\](.*?)\[\/audio\]/ism", $try_oembed_callback, $text);
- } else {
- $text = preg_replace("/\[video\](.*?)\[\/video\]/ism",
- '$1 ', $text);
- $text = preg_replace("/\[audio\](.*?)\[\/audio\]/ism",
- '$1 ', $text);
- }
-
- // html5 video and audio
-
-
- if ($try_oembed) {
- $text = preg_replace("/\[iframe\](.*?)\[\/iframe\]/ism", '', $text);
- } else {
- $text = preg_replace("/\[iframe\](.*?)\[\/iframe\]/ism", '$1 ', $text);
- }
-
- // Youtube extensions
- if ($try_oembed) {
- $text = preg_replace_callback("/\[youtube\](https?:\/\/www.youtube.com\/watch\?v\=.*?)\[\/youtube\]/ism", $try_oembed_callback, $text);
- $text = preg_replace_callback("/\[youtube\](www.youtube.com\/watch\?v\=.*?)\[\/youtube\]/ism", $try_oembed_callback, $text);
- $text = preg_replace_callback("/\[youtube\](https?:\/\/youtu.be\/.*?)\[\/youtube\]/ism", $try_oembed_callback, $text);
- }
-
- $text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text);
- $text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/embed\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text);
- $text = preg_replace("/\[youtube\]https?:\/\/youtu.be\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text);
-
- if ($try_oembed) {
- $text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", 'VIDEO ', $text);
- } else {
- $text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism",
- 'https://www.youtube.com/watch?v=$1 ', $text);
- }
-
- if ($try_oembed) {
- $text = preg_replace_callback("/\[vimeo\](https?:\/\/player.vimeo.com\/video\/[0-9]+).*?\[\/vimeo\]/ism", $try_oembed_callback, $text);
- $text = preg_replace_callback("/\[vimeo\](https?:\/\/vimeo.com\/[0-9]+).*?\[\/vimeo\]/ism", $try_oembed_callback, $text);
- }
-
- $text = preg_replace("/\[vimeo\]https?:\/\/player.vimeo.com\/video\/([0-9]+)(.*?)\[\/vimeo\]/ism", '[vimeo]$1[/vimeo]', $text);
- $text = preg_replace("/\[vimeo\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/vimeo\]/ism", '[vimeo]$1[/vimeo]', $text);
-
- if ($try_oembed) {
- $text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", '', $text);
- } else {
- $text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism",
- 'https://vimeo.com/$1 ', $text);
- }
-
- // oembed tag
- $text = OEmbed::BBCode2HTML($text);
-
- // Avoid triple linefeeds through oembed
- $text = str_replace(" ", " ", $text);
-
- // If we found an event earlier, strip out all the event code and replace with a reformatted version.
- // Replace the event-start section with the entire formatted event. The other bbcode is stripped.
- // Summary (e.g. title) is required, earlier revisions only required description (in addition to
- // start which is always required). Allow desc with a missing summary for compatibility.
-
- if ((!empty($ev['desc']) || !empty($ev['summary'])) && !empty($ev['start'])) {
- $sub = Event::getHTML($ev, $simple_html);
-
- $text = preg_replace("/\[event\-summary\](.*?)\[\/event\-summary\]/ism", '', $text);
- $text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/ism", '', $text);
- $text = preg_replace("/\[event\-start\](.*?)\[\/event\-start\]/ism", $sub, $text);
- $text = preg_replace("/\[event\-finish\](.*?)\[\/event\-finish\]/ism", '', $text);
- $text = preg_replace("/\[event\-location\](.*?)\[\/event\-location\]/ism", '', $text);
- $text = preg_replace("/\[event\-adjust\](.*?)\[\/event\-adjust\]/ism", '', $text);
- $text = preg_replace("/\[event\-id\](.*?)\[\/event\-id\]/ism", '', $text);
- }
-
- // Replace non graphical smilies for external posts
- if ($simple_html) {
- $text = Smilies::replace($text);
- }
-
// Unhide all [noparse] contained bbtags unspacefying them
// and triming the [noparse] tag.
diff --git a/tests/src/Content/Text/BBCodeTest.php b/tests/src/Content/Text/BBCodeTest.php
index 864a3794d..f74aebaab 100644
--- a/tests/src/Content/Text/BBCodeTest.php
+++ b/tests/src/Content/Text/BBCodeTest.php
@@ -134,4 +134,47 @@ class BBCodeTest extends MockedTest
$this->assertNotEquals($assert, $output);
}
}
+
+ public function dataBBCodes()
+ {
+ return [
+ 'bug-7271-condensed-space' => [
+ 'expectedHtml' => '',
+ 'text' => '[ol][*] http://example.com/[/ol]',
+ ],
+ 'bug-7271-condensed-nospace' => [
+ 'expectedHtml' => '',
+ 'text' => '[ol][*]http://example.com/[/ol]',
+ ],
+ 'bug-7271-indented-space' => [
+ 'expectedHtml' => '',
+ 'text' => '[ul]
+[*] http://example.com/
+[/ul]',
+ ],
+ 'bug-7271-indented-nospace' => [
+ 'expectedHtml' => '',
+ 'text' => '[ul]
+[*]http://example.com/
+[/ul]',
+ ],
+ ];
+ }
+
+ /**
+ * Test convert bbcodes to HTML
+ * @dataProvider dataBBCodes
+ *
+ * @param string $expectedHtml Expected HTML output
+ * @param string $text BBCode text
+ * @param int $simpleHtml BBCode::convert method $simple_html parameter value, optional.
+ * @param bool $forPlaintext BBCode::convert method $for_plaintext parameter value, optional.
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+ */
+ public function testConvert($expectedHtml, $text, $simpleHtml = 0, $forPlaintext = false)
+ {
+ $actual = BBCode::convert($text, false, $simpleHtml, $forPlaintext);
+
+ $this->assertEquals($expectedHtml, $actual);
+ }
}