X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FContent%2FText%2FBBCode.php;h=12497d66516ebbf44b6f127906b7c97959a6c97c;hb=a947bd0889cfb2eb58692f92ab19a875019d3b79;hp=85466b50f695c7439f7e499267739006f6d4560f;hpb=c4bfc6e86e3eba8d8bf89526344bc649ad91bd66;p=friendica.git diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index 85466b50f6..12497d6651 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -21,6 +21,7 @@ use Friendica\Core\Renderer; use Friendica\Core\System; use Friendica\Model\Contact; use Friendica\Model\Event; +use Friendica\Model\Photo; use Friendica\Network\Probe; use Friendica\Object\Image; use Friendica\Util\Map; @@ -72,9 +73,7 @@ class BBCode extends BaseObject $attacheddata = $data[2]; - $URLSearchString = "^\[\]"; - - if (preg_match("/\[img\]([$URLSearchString]*)\[\/img\]/ism", $attacheddata, $matches)) { + if (preg_match("/\[img\](.*?)\[\/img\]/ism", $attacheddata, $matches)) { $picturedata = Image::getInfoFromURL($matches[1]); @@ -87,12 +86,12 @@ class BBCode extends BaseObject } } - if (preg_match("/\[bookmark\=([$URLSearchString]*)\](.*?)\[\/bookmark\]/ism", $attacheddata, $matches)) { + if (preg_match("/\[bookmark\=(.*?)\](.*?)\[\/bookmark\]/ism", $attacheddata, $matches)) { $post["url"] = $matches[1]; $post["title"] = $matches[2]; } if (!empty($post["url"]) && (in_array($post["type"], ["link", "video"])) - && preg_match("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", $attacheddata, $matches)) { + && preg_match("/\[url\=(.*?)\](.*?)\[\/url\]/ism", $attacheddata, $matches)) { $post["url"] = $matches[1]; } @@ -240,19 +239,43 @@ class BBCode extends BaseObject $plink = defaults($item, 'plink', ''); $post = self::getAttachmentData($body); + // Get all linked images with alternative image description + if (preg_match_all("/\[img=([^\[\]]*)\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures, PREG_SET_ORDER)) { + foreach ($pictures as $picture) { + if (Photo::isLocal($picture[1])) { + $post['images'][] = ['url' => str_replace('-1.', '-0.', $picture[1]), 'description' => $picture[2]]; + } + } + if (!empty($post['images']) && !empty($post['images'][0]['description'])) { + $post['image_description'] = $post['images'][0]['description']; + } + } + + if (preg_match_all("/\[img\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures, PREG_SET_ORDER)) { + foreach ($pictures as $picture) { + if (Photo::isLocal($picture[1])) { + $post['images'][] = ['url' => str_replace('-1.', '-0.', $picture[1]), 'description' => '']; + } + } + } + // if nothing is found, it maybe having an image. if (!isset($post["type"])) { // Simplify image codes $body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body); + $body = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", '[img]$1[/img]', $body); + $post["text"] = $body; - $URLSearchString = "^\[\]"; - - $body = preg_replace("/\[img\=([$URLSearchString]*)\](.*?)\[\/img\]/ism", '[img]$1[/img]', $body); - - if (preg_match_all("(\[url=([$URLSearchString]*)\]\s*\[img\]([$URLSearchString]*)\[\/img\]\s*\[\/url\])ism", $body, $pictures, PREG_SET_ORDER)) { + if (preg_match_all("(\[url=(.*?)\]\s*\[img\](.*?)\[\/img\]\s*\[\/url\])ism", $body, $pictures, PREG_SET_ORDER)) { if ((count($pictures) == 1) && !$has_title) { - // Checking, if the link goes to a picture - $data = ParseUrl::getSiteinfoCached($pictures[0][1], true); + if (!empty($item['object-type']) && ($item['object-type'] == ACTIVITY_OBJ_IMAGE)) { + // Replace the preview picture with the real picture + $url = str_replace('-1.', '-0.', $pictures[0][2]); + $data = ['url' => $url, 'type' => 'photo']; + } else { + // Checking, if the link goes to a picture + $data = ParseUrl::getSiteinfoCached($pictures[0][1], true); + } // Workaround: // Sometimes photo posts to the own album are not detected at the start. @@ -271,14 +294,14 @@ class BBCode extends BaseObject } $post["preview"] = $pictures[0][2]; - $post["text"] = str_replace($pictures[0][0], "", $body); + $post["text"] = trim(str_replace($pictures[0][0], "", $body)); } else { $imgdata = Image::getInfoFromURL($pictures[0][1]); if ($imgdata && substr($imgdata["mime"], 0, 6) == "image/") { $post["type"] = "photo"; $post["image"] = $pictures[0][1]; $post["preview"] = $pictures[0][2]; - $post["text"] = str_replace($pictures[0][0], "", $body); + $post["text"] = trim(str_replace($pictures[0][0], "", $body)); } } } elseif (count($pictures) > 0) { @@ -286,8 +309,12 @@ class BBCode extends BaseObject $post["url"] = $plink; $post["image"] = $pictures[0][2]; $post["text"] = $body; + + foreach ($pictures as $picture) { + $post["text"] = trim(str_replace($picture[0], "", $post["text"])); + } } - } elseif (preg_match_all("(\[img\]([$URLSearchString]*)\[\/img\])ism", $body, $pictures, PREG_SET_ORDER)) { + } elseif (preg_match_all("(\[img\](.*?)\[\/img\])ism", $body, $pictures, PREG_SET_ORDER)) { if ((count($pictures) == 1) && !$has_title) { $post["type"] = "photo"; $post["image"] = $pictures[0][1]; @@ -297,12 +324,16 @@ class BBCode extends BaseObject $post["url"] = $plink; $post["image"] = $pictures[0][1]; $post["text"] = $body; + + foreach ($pictures as $picture) { + $post["text"] = trim(str_replace($picture[0], "", $post["text"])); + } } } // Test for the external links - preg_match_all("(\[url\]([$URLSearchString]*)\[\/url\])ism", $body, $links1, PREG_SET_ORDER); - preg_match_all("(\[url\=([$URLSearchString]*)\].*?\[\/url\])ism", $body, $links2, PREG_SET_ORDER); + preg_match_all("(\[url\](.*?)\[\/url\])ism", $post["text"], $links1, PREG_SET_ORDER); + preg_match_all("(\[url\=(.*?)\].*?\[\/url\])ism", $post["text"], $links2, PREG_SET_ORDER); $links = array_merge($links1, $links2); @@ -310,15 +341,14 @@ class BBCode extends BaseObject // This should cover link posts via API. if ((count($links) == 1) && !isset($post["preview"]) && !$has_title) { $post["type"] = "link"; - $post["text"] = trim($body); $post["url"] = $links[0][1]; } // Now count the number of external media links - preg_match_all("(\[vimeo\](.*?)\[\/vimeo\])ism", $body, $links1, PREG_SET_ORDER); - preg_match_all("(\[youtube\\](.*?)\[\/youtube\\])ism", $body, $links2, PREG_SET_ORDER); - preg_match_all("(\[video\\](.*?)\[\/video\\])ism", $body, $links3, PREG_SET_ORDER); - preg_match_all("(\[audio\\](.*?)\[\/audio\\])ism", $body, $links4, PREG_SET_ORDER); + preg_match_all("(\[vimeo\](.*?)\[\/vimeo\])ism", $post["text"], $links1, PREG_SET_ORDER); + preg_match_all("(\[youtube\\](.*?)\[\/youtube\\])ism", $post["text"], $links2, PREG_SET_ORDER); + preg_match_all("(\[video\\](.*?)\[\/video\\])ism", $post["text"], $links3, PREG_SET_ORDER); + preg_match_all("(\[audio\\](.*?)\[\/audio\\])ism", $post["text"], $links4, PREG_SET_ORDER); // Add them to the other external links $links = array_merge($links, $links1, $links2, $links3, $links4); @@ -355,10 +385,7 @@ class BBCode extends BaseObject */ public static function toPlaintext($text, $keep_urls = true) { - $naked_text = preg_replace('/\[(.+?)\]\s*/','', $text); - if (!$keep_urls) { - $naked_text = preg_replace('#https?\://[^\s<]+[^\s\.\)]#i', '', $naked_text); - } + $naked_text = HTML::toPlaintext(BBCode::convert($text, false, 0, true), 0, !$keep_urls); return $naked_text; } @@ -563,7 +590,7 @@ class BBCode extends BaseObject } $return = ''; - if ($simplehtml == 7) { + if (in_array($simplehtml, [7, 9])) { $return = self::convertUrlForOStatus($data["url"]); } elseif (($simplehtml != 4) && ($simplehtml != 0)) { $return = sprintf('%s
', $data["url"], $data["title"]); @@ -903,7 +930,17 @@ class BBCode extends BaseObject // We only call this so that a previously unknown contact can be added. // This is important for the function "Model\Contact::getDetailsByURL()". // This function then can fetch an entry from the contact table. - Contact::getIdForURL($attributes['profile'], 0, true); + $default['url'] = $attributes['profile']; + + if (!empty($attributes['author'])) { + $default['name'] = $attributes['author']; + } + + if (!empty($attributes['avatar'])) { + $default['photo'] = $attributes['avatar']; + } + + Contact::getIdForURL($attributes['profile'], 0, true, $default); $author_contact = Contact::getDetailsByURL($attributes['profile']); $author_contact['addr'] = defaults($author_contact, 'addr' , Protocol::getAddrFromProfileUrl($attributes['profile'])); @@ -979,16 +1016,9 @@ class BBCode extends BaseObject $text = ($is_quote_share? '
' : '') . '

' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ':

' . "\n" . $content; break; case 7: // statusnet/GNU Social + case 9: // ActivityPub $text = ($is_quote_share? '
' : '') . '

' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' @' . $author_contact['addr'] . ': ' . $content . '

' . "\n"; break; - case 9: // Google+ - $text = ($is_quote_share? '
' : '') . '

' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ':

' . "\n"; - $text .= '

' . $content . '

' . "\n"; - - if ($attributes['link'] != '') { - $text .= '

' . $attributes['link'] . '

'; - } - break; default: // Transforms quoted tweets in rich attachments to avoid nested tweets if (stripos(Strings::normaliseLink($attributes['link']), 'http://twitter.com/') === 0 && OEmbed::isAllowedURL($attributes['link'])) { @@ -1097,7 +1127,11 @@ class BBCode extends BaseObject if (substr($curl_info["content_type"], 0, 6) == "image/") { $text = "[img]" . $match[1] . "[/img]"; } else { - $text = "[img]" . $match[2] . "[/img]"; + if (!empty($match[3])) { + $text = "[img=" . $match[2] . "]" . $match[3] . "[/img]"; + } else { + $text = "[img]" . $match[2] . "[/img]"; + } // if its not a picture then look if its a page that contains a picture link $body = Network::fetchUrl($match[1]); @@ -1115,7 +1149,11 @@ class BBCode extends BaseObject } if (strtolower($attr["name"]) == "twitter:image") { - $text = "[img]" . $attr["content"] . "[/img]"; + if (!empty($match[3])) { + $text = "[img=" . $attr["content"] . "]" . $match[3] . "[/img]"; + } else { + $text = "[img]" . $attr["content"] . "[/img]"; + } } } } @@ -1127,7 +1165,8 @@ class BBCode extends BaseObject public static function cleanPictureLinks($text) { - $return = preg_replace_callback("&\[url=([^\[\]]*)\]\[img\](.*)\[\/img\]\[\/url\]&Usi", 'self::cleanPictureLinksCallback', $text); + $return = preg_replace_callback("&\[url=([^\[\]]*)\]\[img=(.*)\](.*)\[\/img\]\[\/url\]&Usi", 'self::cleanPictureLinksCallback', $text); + $return = preg_replace_callback("&\[url=([^\[\]]*)\]\[img\](.*)\[\/img\]\[\/url\]&Usi", 'self::cleanPictureLinksCallback', $return); return $return; } @@ -1140,13 +1179,14 @@ class BBCode extends BaseObject * Simple HTML values meaning: * - 0: Friendica display * - 1: Unused - * - 2: Used for Google+, Windows Phone push, Friendica API + * - 2: Used for Windows Phone push, Friendica API * - 3: Used before converting to Markdown in bb2diaspora.php * - 4: Used for WordPress, Libertree (before Markdown), pump.io and tumblr * - 5: Unused * - 6: Unused * - 7: Used for dfrn, OStatus * - 8: Used for WP backlink text setting + * - 9: ActivityPub * * @param string $text * @param bool $try_oembed @@ -1180,17 +1220,18 @@ class BBCode extends BaseObject return $return; }; - // Extracting multi-line code blocks before the whitespace processing + // Extracting code blocks before the whitespace processing and the autolinker $codeblocks = []; $text = preg_replace_callback("#\[code(?:=([^\]]*))?\](.*?)\[\/code\]#ism", function ($matches) use (&$codeblocks) { - $return = $matches[0]; + $return = '#codeblock-' . count($codeblocks) . '#'; if (strpos($matches[2], "\n") !== false) { - $return = '#codeblock-' . count($codeblocks) . '#'; - - $codeblocks[] = '
' . trim($matches[2], "\n\r") . '
'; + $codeblocks[] = '
' . trim($matches[2], "\n\r") . '
'; + } else { + $codeblocks[] = '' . $matches[2] . ''; } + return $return; }, $text @@ -1249,6 +1290,25 @@ class BBCode extends BaseObject $text = trim($text); $text = str_replace("\r\n", "\n", $text); + // Remove linefeeds inside of the table elements. See issue #6799 + $search = ["\n[th]", "[th]\n", " [th]", "\n[/th]", "[/th]\n", "[/th] ", + "\n[td]", "[td]\n", " [td]", "\n[/td]", "[/td]\n", "[/td] ", + "\n[tr]", "[tr]\n", " [tr]", "[tr] ", "\n[/tr]", "[/tr]\n", " [/tr]", "[/tr] ", + "[table]\n", "[table] ", " [table]", "\n[/table]", " [/table]", "[/table] "]; + $replace = ["[th]", "[th]", "[th]", "[/th]", "[/th]", "[/th]", + "[td]", "[td]", "[td]", "[/td]", "[/td]", "[/td]", + "[tr]", "[tr]", "[tr]", "[tr]", "[/tr]", "[/tr]", "[/tr]", "[/tr]", + "[table]", "[table]", "[table]", "[/table]", "[/table]", "[/table]"]; + do { + $oldtext = $text; + $text = str_replace($search, $replace, $text); + } while ($oldtext != $text); + + // Replace these here only once + $search = ["\n[table]", "[/table]\n"]; + $replace = ["[table]", "[/table]"]; + $text = str_replace($search, $replace, $text); + // removing multiplicated newlines if (Config::get("system", "remove_multiplicated_lines")) { $search = ["\n\n\n", "\n ", " \n", "[/quote]\n\n", "\n[/quote]", "[/li]\n", "\n[li]", "\n[ul]", "[/ul]\n", "\n\n[share ", "[/attachment]\n", @@ -1261,154 +1321,11 @@ class BBCode extends BaseObject } while ($oldtext != $text); } - // Set up the parameters for a URL search string - $URLSearchString = "^\[\]"; - // Set up the parameters for a MAIL search string - $MAILSearchString = $URLSearchString; - - // 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) { - // Autolink feature (thanks to https://daringfireball.net/2010/07/improved_regex_for_matching_urls) - $autolink_regex = '@(?xi) -(?]+ # Run of non-space, non-()<> - | # or - \(([^\s()<>]+|(\([^\s()<>]+\)))*\) # balanced parens, up to 2 levels - )+ - (?: # End with: - \(([^\s()<>]+|(\([^\s()<>]+\)))*\) # balanced parens, up to 2 levels - | # or - [^\s`!()\[\]{};:\'".,<>?«»“”‘’] # not a space or one of these punct chars - ) -)@'; - $text = preg_replace($autolink_regex, '[url]$1[/url]', $text); - if ($simple_html == 7) { - $text = preg_replace_callback("/\[url\]([$URLSearchString]*)\[\/url\]/ism", 'self::convertUrlForOStatusCallback', $text); - $text = preg_replace_callback("/\[url\=([$URLSearchString]*)\]([$URLSearchString]*)\[\/url\]/ism", 'self::convertUrlForOStatusCallback', $text); - } - } else { - $text = preg_replace("(\[url\]([$URLSearchString]*)\[\/url\])ism", " $1 ", $text); - $text = preg_replace_callback("&\[url=([^\[\]]*)\]\[img\](.*)\[\/img\]\[\/url\]&Usi", 'self::removePictureLinksCallback', $text); - } - - // Handle attached links or videos $text = self::convertAttachment($text, $simple_html, $try_oembed); - $text = str_replace(["\r","\n"], ['
', '
'], $text); - - // Remove all hashtag addresses - if ((!$try_oembed || $simple_html) && !in_array($simple_html, [3, 7])) { - $text = preg_replace("/([#@!])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $text); - } elseif ($simple_html == 3) { - // The ! is converted to @ since Diaspora only understands the @ - $text = preg_replace("/([@!])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", - '@$3', - $text); - } elseif ($simple_html == 7) { - $text = preg_replace("/([@!])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", - '$1$3', - $text); - } elseif (!$simple_html) { - $text = preg_replace("/([@!])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", - '$1$3', - $text); - } - - // Bookmarks in red - will be converted to bookmarks in friendica - $text = preg_replace("/#\^\[url\]([$URLSearchString]*)\[\/url\]/ism", '[bookmark=$1]$1[/bookmark]', $text); - $text = preg_replace("/#\^\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '[bookmark=$1]$2[/bookmark]', $text); - $text = preg_replace("/#\[url\=[$URLSearchString]*\]\^\[\/url\]\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/i", - "[bookmark=$1]$2[/bookmark]", $text); - - if (in_array($simple_html, [2, 6, 7, 8, 9])) { - $text = preg_replace_callback("/([^#@!])\[url\=([^\]]*)\](.*?)\[\/url\]/ism", "self::expandLinksCallback", $text); - //$Text = preg_replace("/[^#@!]\[url\=([^\]]*)\](.*?)\[\/url\]/ism", ' $2 [url]$1[/url]', $Text); - $text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", ' $2 [url]$1[/url]',$text); - } - - if ($simple_html == 5) { - $text = preg_replace("/[^#@!]\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '[url]$1[/url]', $text); - } - - // Perform URL Search - if ($try_oembed) { - $text = preg_replace_callback("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", $try_oembed_callback, $text); - } - - if ($simple_html == 5) { - $text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", '[url]$1[/url]', $text); - } else { - $text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", '[url=$1]$2[/url]', $text); - } - - // Handle Diaspora posts - $text = preg_replace_callback( - "&\[url=/?posts/([^\[\]]*)\](.*)\[\/url\]&Usi", - function ($match) { - return "[url=" . System::baseUrl() . "/display/" . $match[1] . "]" . $match[2] . "[/url]"; - }, $text - ); - - $text = preg_replace_callback( - "&\[url=/people\?q\=(.*)\](.*)\[\/url\]&Usi", - function ($match) { - return "[url=" . System::baseUrl() . "/search?search=%40" . $match[1] . "]" . $match[2] . "[/url]"; - }, $text - ); - - // Server independent link to posts and comments - // See issue: https://github.com/diaspora/diaspora_federation/issues/75 - $expression = "=diaspora://.*?/post/([0-9A-Za-z\-_@.:]{15,254}[0-9A-Za-z])=ism"; - $text = preg_replace($expression, System::baseUrl()."/display/$1", $text); - - /* Tag conversion - * Supports: - * - #[url=][/url] - * - [url=]#[/url] - */ - $text = preg_replace_callback("/(?:#\[url\=[$URLSearchString]*\]|\[url\=[$URLSearchString]*\]#)(.*?)\[\/url\]/ism", function($matches) { - return '#' - . XML::escape($matches[1]) - . ''; - }, $text); - - // We need no target="_blank" for local links - // 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\]([$URLSearchString]*)\[\/url\]/ism", '$1', $text); - $text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$2', $text); - - // Red compatibility, though the link can't be authenticated on Friendica - $text = preg_replace("/\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '$2', $text); - - - // we may need to restrict this further if it picks up too many strays - // link acct:user@host to a webfinger profile redirector - - $text = preg_replace('/acct:([^@]+)@((?!\-)(?:[a-zA-Z\d\-]{0,62}[a-zA-Z\d]\.){1,126}(?!\d+)[a-zA-Z\d]{1,63})/', 'acct:$1@$2', $text); - - // Perform MAIL Search - $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", @@ -1418,6 +1335,7 @@ class BBCode extends BaseObject $text ); } + if (strpos($text, '[map=') !== false) { $text = preg_replace_callback( "/\[map=(.*?)\]/ism", @@ -1427,6 +1345,7 @@ class BBCode extends BaseObject $text ); } + if (strpos($text, '[map]') !== false) { $text = preg_replace("/\[map\]/", '

', $text); } @@ -1493,9 +1412,9 @@ class BBCode extends BaseObject $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)) { + ((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", '
    $1
', $text); $text = preg_replace("/\[list=\](.*?)\[\/list\]/ism", '
    $1
', $text); $text = preg_replace("/\[list=1\](.*?)\[\/list\]/ism", '
    $1
', $text); @@ -1520,17 +1439,12 @@ class BBCode extends BaseObject // This is actually executed in Item::prepareBody() + $nosmile = strpos($text, '[nosmile]') !== false; $text = str_replace('[nosmile]', '', $text); // Check for font change text $text = preg_replace("/\[font=(.*?)\](.*?)\[\/font\]/sm", "$2", $text); - // Declare the format for [code] layout - - $CodeLayout = '$1'; - // Check for [code] text - $text = preg_replace("/\[code\](.*?)\[\/code\]/ism", "$CodeLayout", $text); - // Declare the format for [spoiler] layout $SpoilerLayout = '
$1
'; @@ -1549,8 +1463,8 @@ class BBCode extends BaseObject $endlessloop = 0; while ((strpos($text, "[/spoiler]")!== false) && (strpos($text, "[spoiler=") !== false) && (++$endlessloop < 20)) { $text = preg_replace("/\[spoiler=[\"\']*(.*?)[\"\']*\](.*?)\[\/spoiler\]/ism", - "
" . $t_wrote . "
$2
", - $text); + "
" . $t_wrote . "
$2
", + $text); } // Declare the format for [quote] layout @@ -1571,8 +1485,8 @@ class BBCode extends BaseObject $endlessloop = 0; while ((strpos($text, "[/quote]")!== false) && (strpos($text, "[quote=") !== false) && (++$endlessloop < 20)) { $text = preg_replace("/\[quote=[\"\']*(.*?)[\"\']*\](.*?)\[\/quote\]/ism", - "

" . $t_wrote . "

$2
", - $text); + "

" . $t_wrote . "

$2
", + $text); } @@ -1593,7 +1507,7 @@ class BBCode extends BaseObject $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", + $text = preg_replace_callback("/\[img\=(.*?)\](.*?)\[\/img\]/ism", function ($matches) use ($simple_html) { $matches[1] = self::proxyUrl($matches[1], $simple_html); $matches[2] = htmlspecialchars($matches[2], ENT_COMPAT); @@ -1619,14 +1533,6 @@ class BBCode extends BaseObject $text = preg_replace("/\[img\](.*?)\[\/img\]/ism", '' . L10n::t('Image/photo') . '', $text); $text = preg_replace("/\[zmg\](.*?)\[\/zmg\]/ism", '' . L10n::t('Image/photo') . '', $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", '
' . L10n::t('Encrypted content') . '
', $text); $text = preg_replace("/\[crypt(.*?)\](.*?)\[\/crypt\]/ism", '
' . L10n::t('Encrypted content') . '
', $text); //$Text = preg_replace("/\[crypt=(.*?)\](.*?)\[\/crypt\]/ism", '
' . L10n::t('Encrypted content') . '
', $Text); @@ -1640,9 +1546,9 @@ class BBCode extends BaseObject $text = preg_replace_callback("/\[audio\](.*?)\[\/audio\]/ism", $try_oembed_callback, $text); } else { $text = preg_replace("/\[video\](.*?)\[\/video\]/ism", - '$1', $text); + '$1', $text); $text = preg_replace("/\[audio\](.*?)\[\/audio\]/ism", - '$1', $text); + '$1', $text); } // html5 video and audio @@ -1669,7 +1575,7 @@ class BBCode extends BaseObject $text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", '', $text); } else { $text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", - 'https://www.youtube.com/watch?v=$1', $text); + 'https://www.youtube.com/watch?v=$1', $text); } if ($try_oembed) { @@ -1684,7 +1590,7 @@ class BBCode extends BaseObject $text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", '', $text); } else { $text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", - 'https://vimeo.com/$1', $text); + 'https://vimeo.com/$1', $text); } // oembed tag @@ -1711,10 +1617,124 @@ class BBCode extends BaseObject } // Replace non graphical smilies for external posts - if ($simple_html) { + if (!$nosmile && !$for_plaintext) { $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); + if (in_array($simple_html, [7, 9])) { + $text = preg_replace_callback("/\[url\](.*?)\[\/url\]/ism", 'self::convertUrlForOStatusCallback', $text); + $text = preg_replace_callback("/\[url\=(.*?)\](.*?)\[\/url\]/ism", 'self::convertUrlForOStatusCallback', $text); + } + } else { + $text = preg_replace("(\[url\](.*?)\[\/url\])ism", " $1 ", $text); + $text = preg_replace_callback("&\[url=([^\[\]]*)\]\[img\](.*)\[\/img\]\[\/url\]&Usi", 'self::removePictureLinksCallback', $text); + } + + $text = str_replace(["\r","\n"], ['
', '
'], $text); + + // Remove all hashtag addresses + if ((!$try_oembed || $simple_html) && !in_array($simple_html, [3, 7, 9])) { + $text = preg_replace("/([#@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", '$1$3', $text); + } elseif ($simple_html == 3) { + // The ! is converted to @ since Diaspora only understands the @ + $text = preg_replace("/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", + '@$3', + $text); + } elseif (in_array($simple_html, [7, 9])) { + $text = preg_replace("/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", + '$1$3', + $text); + } elseif (!$simple_html) { + $text = preg_replace("/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", + '$1$3', + $text); + } + + // Bookmarks in red - will be converted to bookmarks in friendica + $text = preg_replace("/#\^\[url\](.*?)\[\/url\]/ism", '[bookmark=$1]$1[/bookmark]', $text); + $text = preg_replace("/#\^\[url\=(.*?)\](.*?)\[\/url\]/ism", '[bookmark=$1]$2[/bookmark]', $text); + $text = preg_replace("/#\[url\=.*?\]\^\[\/url\]\[url\=(.*?)\](.*?)\[\/url\]/i", + "[bookmark=$1]$2[/bookmark]", $text); + + if (in_array($simple_html, [2, 6, 7, 8])) { + $text = preg_replace_callback("/([^#@!])\[url\=([^\]]*)\](.*?)\[\/url\]/ism", "self::expandLinksCallback", $text); + //$Text = preg_replace("/[^#@!]\[url\=([^\]]*)\](.*?)\[\/url\]/ism", ' $2 [url]$1[/url]', $Text); + $text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", ' $2 [url]$1[/url]',$text); + } + + if ($simple_html == 5) { + $text = preg_replace("/[^#@!]\[url\=(.*?)\](.*?)\[\/url\]/ism", '[url]$1[/url]', $text); + } + + // Perform URL Search + if ($try_oembed) { + $text = preg_replace_callback("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", $try_oembed_callback, $text); + } + + if ($simple_html == 5) { + $text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", '[url]$1[/url]', $text); + } else { + $text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", '[url=$1]$2[/url]', $text); + } + + // Handle Diaspora posts + $text = preg_replace_callback( + "&\[url=/?posts/([^\[\]]*)\](.*)\[\/url\]&Usi", + function ($match) { + return "[url=" . System::baseUrl() . "/display/" . $match[1] . "]" . $match[2] . "[/url]"; + }, $text + ); + + $text = preg_replace_callback( + "&\[url=/people\?q\=(.*)\](.*)\[\/url\]&Usi", + function ($match) { + return "[url=" . System::baseUrl() . "/search?search=%40" . $match[1] . "]" . $match[2] . "[/url]"; + }, $text + ); + + // Server independent link to posts and comments + // See issue: https://github.com/diaspora/diaspora_federation/issues/75 + $expression = "=diaspora://.*?/post/([0-9A-Za-z\-_@.:]{15,254}[0-9A-Za-z])=ism"; + $text = preg_replace($expression, System::baseUrl()."/display/$1", $text); + + /* Tag conversion + * Supports: + * - #[url=][/url] + * - [url=]#[/url] + */ + $text = preg_replace_callback("/(?:#\[url\=.*?\]|\[url\=.*?\]#)(.*?)\[\/url\]/ism", function($matches) { + return '#' + . XML::escape($matches[1]) + . ''; + }, $text); + + // We need no target="_blank" for local links + // convert links start with System::baseUrl() as local link without the target="_blank" attribute + $escapedBaseUrl = preg_quote(System::baseUrl(), '/'); + $text = preg_replace("/\[url\](".$escapedBaseUrl.".*?)\[\/url\]/ism", '$1', $text); + $text = preg_replace("/\[url\=(".$escapedBaseUrl.".*?)\](.*?)\[\/url\]/ism", '$2', $text); + + $text = preg_replace("/\[url\](.*?)\[\/url\]/ism", '$1', $text); + $text = preg_replace("/\[url\=(.*?)\](.*?)\[\/url\]/ism", '$2', $text); + + // Red compatibility, though the link can't be authenticated on Friendica + $text = preg_replace("/\[zrl\=(.*?)\](.*?)\[\/zrl\]/ism", '$2', $text); + + + // we may need to restrict this further if it picks up too many strays + // link acct:user@host to a webfinger profile redirector + + $text = preg_replace('/acct:([^@]+)@((?!\-)(?:[a-zA-Z\d\-]{0,62}[a-zA-Z\d]\.){1,126}(?!\d+)[a-zA-Z\d]{1,63})/', 'acct:$1@$2', $text); + + // Perform MAIL Search + $text = preg_replace("/\[mail\](.*?)\[\/mail\]/", '$1', $text); + $text = preg_replace("/\[mail\=(.*?)\](.*?)\[\/mail\]/", '$2', $text); + // Unhide all [noparse] contained bbtags unspacefying them // and triming the [noparse] tag. @@ -1748,6 +1768,14 @@ class BBCode extends BaseObject $regex = '#<([^>]*?)(href)="(?!' . implode('|', $allowed_link_protocols) . ')(.*?)"(.*?)>#ism'; $text = preg_replace($regex, '<$1$2="javascript:void(0)"$4 data-original-href="$3" class="invalid-href" title="' . L10n::t('Invalid link protocol') . '">', $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); + } + ); + if ($saved_image) { $text = self::interpolateSavedImagesIntoItemBody($text, $saved_image); }