X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FContent%2FText%2FBBCode.php;h=5a2b966dd57c2ce6501522409e111e84d9c263ed;hb=7fb9e1c7c8f5f4887e44aadf6115b68c6cc66d03;hp=44a6189d9d5533bc0a916e75ab7fba5eb57d9d2d;hpb=bb5f738619dd29264253a1e51f37b5c3c253e2be;p=friendica.git diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index 44a6189d9d..5a2b966dd5 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -39,6 +39,7 @@ use Friendica\Model\Event; use Friendica\Model\Photo; use Friendica\Model\Post; use Friendica\Model\Tag; +use Friendica\Network\HTTPClientOptions; use Friendica\Object\Image; use Friendica\Protocol\Activity; use Friendica\Util\Images; @@ -51,7 +52,7 @@ use Friendica\Util\XML; class BBCode { // Update this value to the current date whenever changes are made to BBCode::convert - const VERSION = '2021-07-13'; + const VERSION = '2021-07-28'; const INTERNAL = 0; const EXTERNAL = 1; @@ -152,6 +153,7 @@ class BBCode */ public static function getAttachmentData($body) { + DI::profiler()->startRecording('rendering'); $data = [ 'type' => '', 'text' => '', @@ -167,6 +169,7 @@ class BBCode ]; if (!preg_match("/(.*)\[attachment(.*?)\](.*?)\[\/attachment\](.*)/ism", $body, $match)) { + DI::profiler()->stopRecording(); return self::getOldAttachmentData($body); } @@ -211,6 +214,7 @@ class BBCode } if (!in_array($data['type'], ['link', 'audio', 'photo', 'video'])) { + DI::profiler()->stopRecording(); return []; } @@ -232,6 +236,7 @@ class BBCode } } + DI::profiler()->stopRecording(); return $data; } @@ -247,6 +252,7 @@ class BBCode - (thumbnail) */ + DI::profiler()->startRecording('rendering'); $has_title = !empty($item['title']); $plink = $item['plink'] ?? ''; $post = self::getAttachmentData($body); @@ -398,6 +404,7 @@ class BBCode } } + DI::profiler()->stopRecording(); return $post; } @@ -434,6 +441,7 @@ class BBCode */ public static function toPlaintext($text, $keep_urls = true) { + DI::profiler()->startRecording('rendering'); // Remove pictures in advance to avoid unneeded proxy calls $text = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", ' $2 ', $text); $text = preg_replace("/\[img.*?\[\/img\]/ism", ' ', $text); @@ -443,6 +451,7 @@ class BBCode $naked_text = HTML::toPlaintext(self::convert($text, false, 0, true), 0, !$keep_urls); + DI::profiler()->stopRecording(); return $naked_text; } @@ -468,6 +477,7 @@ class BBCode */ public static function scaleExternalImages(string $srctext) { + DI::profiler()->startRecording('rendering'); $s = $srctext; // Simplify image links @@ -484,7 +494,7 @@ class BBCode continue; } - $curlResult = DI::httpRequest()->get($mtch[1]); + $curlResult = DI::httpClient()->get($mtch[1]); if (!$curlResult->isSuccess()) { continue; } @@ -517,6 +527,7 @@ class BBCode } } + DI::profiler()->stopRecording(); return $s; } @@ -532,6 +543,7 @@ class BBCode */ public static function limitBodySize($body) { + DI::profiler()->startRecording('rendering'); $maxlen = DI::config()->get('config', 'max_import_size', 0); // If the length of the body, including the embedded images, is smaller @@ -603,8 +615,10 @@ class BBCode $new_body = $new_body . $orig_body; } + DI::profiler()->stopRecording(); return $new_body; } else { + DI::profiler()->stopRecording(); return $body; } } @@ -624,13 +638,13 @@ class BBCode */ public static function convertAttachment($text, $simplehtml = self::INTERNAL, $tryoembed = true, array $data = [], $uriid = 0) { + DI::profiler()->startRecording('rendering'); $data = $data ?: self::getAttachmentData($text); if (empty($data) || empty($data['url'])) { + DI::profiler()->stopRecording(); return $text; } - $stamp1 = microtime(true); - if (isset($data['title'])) { $data['title'] = strip_tags($data['title']); $data['title'] = str_replace(['http://', 'https://'], '', $data['title']); @@ -688,17 +702,20 @@ class BBCode } } - DI::profiler()->saveTimestamp($stamp1, 'rendering'); + DI::profiler()->stopRecording(); return trim(($data['text'] ?? '') . ' ' . $return . ' ' . ($data['after'] ?? '')); } public static function removeShareInformation($Text, $plaintext = false, $nolink = false) { + DI::profiler()->startRecording('rendering'); $data = self::getAttachmentData($Text); if (!$data) { + DI::profiler()->stopRecording(); return $Text; } elseif ($nolink) { + DI::profiler()->stopRecording(); return $data['text'] . ($data['after'] ?? ''); } @@ -712,11 +729,13 @@ class BBCode } if (empty($data['text']) && !empty($data['title']) && empty($data['url'])) { + DI::profiler()->stopRecording(); return $data['title'] . $data['after']; } // If the link already is included in the post, don't add it again if (!empty($data['url']) && strpos($data['text'], $data['url'])) { + DI::profiler()->stopRecording(); return $data['text'] . $data['after']; } @@ -728,6 +747,7 @@ class BBCode $text .= "\n[url]" . $data['url'] . '[/url]'; } + DI::profiler()->stopRecording(); return $text . "\n" . $data['after']; } @@ -821,6 +841,7 @@ class BBCode */ public static function getTagPosition($text, $name, $occurrences = 0) { + DI::profiler()->startRecording('rendering'); if ($occurrences < 0) { $occurrences = 0; } @@ -833,6 +854,7 @@ class BBCode } if ($start_open === false) { + DI::profiler()->stopRecording(); return false; } @@ -840,6 +862,7 @@ class BBCode $start_close = strpos($text, ']', $start_open); if ($start_close === false) { + DI::profiler()->stopRecording(); return false; } @@ -848,6 +871,7 @@ class BBCode $end_open = strpos($text, '[/' . $name . ']', $start_close); if ($end_open === false) { + DI::profiler()->stopRecording(); return false; } @@ -866,6 +890,7 @@ class BBCode $res['start']['equal'] = $start_equal + 1; } + DI::profiler()->stopRecording(); return $res; } @@ -880,6 +905,7 @@ class BBCode */ public static function pregReplaceInTag($pattern, $replace, $name, $text) { + DI::profiler()->startRecording('rendering'); $occurrences = 0; $pos = self::getTagPosition($text, $name, $occurrences); while ($pos !== false && $occurrences++ < 1000) { @@ -896,6 +922,7 @@ class BBCode $pos = self::getTagPosition($text, $name, $occurrences); } + DI::profiler()->stopRecording(); return $text; } @@ -964,12 +991,14 @@ class BBCode */ public static function fetchShareAttributes($text) { + DI::profiler()->startRecording('rendering'); // See Issue https://github.com/friendica/friendica/issues/10454 // Hashtags in usernames are expanded to links. This here is a quick fix. $text = preg_replace('/([@!#])\[url\=.*?\](.*?)\[\/url\]/ism', '$1$2', $text); $attributes = []; if (!preg_match("/(.*?)\[share(.*?)\](.*)\[\/share\]/ism", $text, $matches)) { + DI::profiler()->stopRecording(); return $attributes; } @@ -978,6 +1007,7 @@ class BBCode preg_match("/$field=(['\"])(.+?)\\1/ism", $attribute_string, $matches); $attributes[$field] = html_entity_decode($matches[2] ?? '', ENT_QUOTES, 'UTF-8'); } + DI::profiler()->stopRecording(); return $attributes; } @@ -1002,6 +1032,7 @@ class BBCode */ public static function convertShare($text, callable $callback, int $uriid = 0) { + DI::profiler()->startRecording('rendering'); $return = preg_replace_callback( "/(.*?)\[share(.*?)\](.*)\[\/share\]/ism", function ($match) use ($callback, $uriid) { @@ -1033,6 +1064,44 @@ class BBCode $text ); + DI::profiler()->stopRecording(); + return $return; + } + + /** + * Convert complex IMG and ZMG elements + * + * @param [type] $text + * @param integer $simplehtml + * @param integer $uriid + * @return string + */ + private static function convertImages(string $text, int $simplehtml, int $uriid = 0):string + { + DI::profiler()->startRecording('rendering'); + $return = preg_replace_callback( + "/\[[zi]mg(.*?)\]([^\[\]]*)\[\/[zi]mg\]/ism", + function ($match) use ($simplehtml, $uriid) { + $attribute_string = $match[1]; + $attributes = []; + foreach (['alt', 'width', 'height'] as $field) { + preg_match("/$field=(['\"])(.+?)\\1/ism", $attribute_string, $matches); + $attributes[$field] = html_entity_decode($matches[2] ?? '', ENT_QUOTES, 'UTF-8'); + } + + $img_str = ' $value) { + if (!empty($value)) { + $img_str .= ' ' . $key . '="' . htmlspecialchars($value, ENT_COMPAT) . '"'; + } + } + return $img_str . '>'; + }, + $text + ); + + DI::profiler()->stopRecording(); return $return; } @@ -1052,6 +1121,7 @@ class BBCode */ private static function convertShareCallback(array $attributes, array $author_contact, $content, $is_quote_share, $simplehtml) { + DI::profiler()->startRecording('rendering'); $mention = Protocol::formatMention($attributes['profile'], $attributes['author']); switch ($simplehtml) { @@ -1124,9 +1194,9 @@ class BBCode $text = DI::cache()->get($cache_key); if (is_null($text)) { - $curlResult = DI::httpRequest()->head($match[1], ['timeout' => DI::config()->get('system', 'xrd_timeout')]); + $curlResult = DI::httpClient()->head($match[1], [HTTPClientOptions::TIMEOUT => DI::config()->get('system', 'xrd_timeout')]); if ($curlResult->isSuccess()) { - $mimetype = $curlResult->getHeader('Content-Type'); + $mimetype = $curlResult->getHeader('Content-Type')[0] ?? ''; } else { $mimetype = ''; } @@ -1137,7 +1207,7 @@ class BBCode $text = "[url=" . $match[2] . ']' . $match[2] . "[/url]"; // if its not a picture then look if its a page that contains a picture link - $body = DI::httpRequest()->fetch($match[1]); + $body = DI::httpClient()->fetch($match[1]); if (empty($body)) { DI::cache()->set($cache_key, $text); return $text; @@ -1195,9 +1265,9 @@ class BBCode return $text; } - $curlResult = DI::httpRequest()->head($match[1], ['timeout' => DI::config()->get('system', 'xrd_timeout')]); + $curlResult = DI::httpClient()->head($match[1], [HTTPClientOptions::TIMEOUT => DI::config()->get('system', 'xrd_timeout')]); if ($curlResult->isSuccess()) { - $mimetype = $curlResult->getHeader('Content-Type'); + $mimetype = $curlResult->getHeader('Content-Type')[0] ?? ''; } else { $mimetype = ''; } @@ -1213,7 +1283,7 @@ class BBCode } // if its not a picture then look if its a page that contains a picture link - $body = DI::httpRequest()->fetch($match[1]); + $body = DI::httpClient()->fetch($match[1]); if (empty($body)) { DI::cache()->set($cache_key, $text); return $text; @@ -1247,22 +1317,62 @@ class BBCode public static function cleanPictureLinks($text) { + DI::profiler()->startRecording('rendering'); $return = preg_replace_callback("&\[url=([^\[\]]*)\]\[img=(.*)\](.*)\[\/img\]\[\/url\]&Usi", 'self::cleanPictureLinksCallback', $text); $return = preg_replace_callback("&\[url=([^\[\]]*)\]\[img\](.*)\[\/img\]\[\/url\]&Usi", 'self::cleanPictureLinksCallback', $return); + DI::profiler()->stopRecording(); return $return; } public static function removeLinks(string $bbcode) { + DI::profiler()->startRecording('rendering'); $bbcode = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", ' $1 ', $bbcode); $bbcode = preg_replace("/\[img.*?\[\/img\]/ism", ' ', $bbcode); $bbcode = preg_replace('/[@!#]\[url\=.*?\].*?\[\/url\]/ism', '', $bbcode); $bbcode = preg_replace("/\[url=[^\[\]]*\](.*)\[\/url\]/Usi", ' $1 ', $bbcode); $bbcode = preg_replace('/[@!#]?\[url.*?\[\/url\]/ism', '', $bbcode); + DI::profiler()->stopRecording(); return $bbcode; } + /** + * Replace names in mentions with nicknames + * + * @param string $body + * @return string Body with replaced mentions + */ + public static function setMentionsToNicknames(string $body):string + { + DI::profiler()->startRecording('rendering'); + $regexp = "/([@!])\[url\=([^\[\]]*)\].*?\[\/url\]/ism"; + $body = preg_replace_callback($regexp, ['self', 'mentionCallback'], $body); + DI::profiler()->stopRecording(); + return $body; + } + + /** + * Callback function to replace a Friendica style mention in a mention with the nickname + * + * @param array $match Matching values for the callback + * @return string Replaced mention + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + */ + private static function mentionCallback($match) + { + if (empty($match[2])) { + return ''; + } + + $data = Contact::getByURL($match[2], false, ['url', 'nick']); + if (empty($data['nick'])) { + return $match[0]; + } + + return $match[1] . '[url=' . $data['url'] . ']' . $data['nick'] . '[/url]'; + } + /** * Converts a BBCode message for a given URI-ID to a HTML message * @@ -1327,6 +1437,8 @@ class BBCode return ''; } + DI::profiler()->startRecording('rendering'); + Hook::callAll('bbcode', $text); $a = DI::app(); @@ -1655,6 +1767,8 @@ class BBCode $text = preg_replace("/\[img\](.*?)\[\/img\]/ism", '' . DI::l10n()->t('Image/photo') . '', $text); $text = preg_replace("/\[zmg\](.*?)\[\/zmg\]/ism", '' . DI::l10n()->t('Image/photo') . '', $text); + + $text = self::convertImages($text, $simple_html, $uriid); $text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism", '
' . DI::l10n()->t('Encrypted content') . '
', $text); $text = preg_replace("/\[crypt(.*?)\](.*?)\[\/crypt\]/ism", '
' . DI::l10n()->t('Encrypted content') . '
', $text); @@ -1696,7 +1810,7 @@ class BBCode $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", '', $text); + $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); @@ -1711,7 +1825,7 @@ class BBCode $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); + $text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", '', $text); } else { $text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", 'https://vimeo.com/$1', $text); @@ -1946,6 +2060,7 @@ class BBCode ); $text = HTML::purify($text, $allowedIframeDomains); + DI::profiler()->stopRecording(); return trim($text); } @@ -1958,9 +2073,11 @@ class BBCode */ public static function stripAbstract($text) { + DI::profiler()->startRecording('rendering'); $text = preg_replace("/[\s|\n]*\[abstract\].*?\[\/abstract\][\s|\n]*/ism", '', $text); $text = preg_replace("/[\s|\n]*\[abstract=.*?\].*?\[\/abstract][\s|\n]*/ism", '', $text); + DI::profiler()->stopRecording(); return $text; } @@ -1973,6 +2090,7 @@ class BBCode */ public static function getAbstract($text, $addon = '') { + DI::profiler()->startRecording('rendering'); $abstract = ''; $abstracts = []; $addon = strtolower($addon); @@ -1991,6 +2109,7 @@ class BBCode $abstract = $result[1]; } + DI::profiler()->stopRecording(); return $abstract; } @@ -2029,6 +2148,7 @@ class BBCode */ public static function toMarkdown($text, $for_diaspora = true) { + DI::profiler()->startRecording('rendering'); $original_text = $text; // Since Diaspora is creating a summary for links, this function removes them before posting @@ -2073,13 +2193,9 @@ class BBCode // Maybe we should make this newline at every time before a quote. $text = str_replace(['
'], ['
'], $text); - $stamp1 = microtime(true); - // Now convert HTML to Markdown $text = HTML::toMarkdown($text); - DI::profiler()->saveTimestamp($stamp1, "parser"); - // Libertree has a problem with escaped hashtags. $text = str_replace(['\#'], ['#'], $text); @@ -2098,6 +2214,7 @@ class BBCode Hook::callAll('bb2diaspora', $text); + DI::profiler()->stopRecording(); return $text; } @@ -2116,6 +2233,7 @@ class BBCode */ public static function getTags($string) { + DI::profiler()->startRecording('rendering'); $ret = []; self::performWithEscapedTags($string, ['noparse', 'pre', 'code', 'img'], function ($string) use (&$ret) { @@ -2166,6 +2284,7 @@ class BBCode } }); + DI::profiler()->stopRecording(); return array_unique($ret); } @@ -2225,6 +2344,7 @@ class BBCode */ public static function setMentions($body, $profile_uid = 0, $network = '') { + DI::profiler()->startRecording('rendering'); self::performWithEscapedTags($body, ['noparse', 'pre', 'code', 'img'], function ($body) use ($profile_uid, $network) { $tags = self::getTags($body); @@ -2256,6 +2376,7 @@ class BBCode return $body; }); + DI::profiler()->stopRecording(); return $body; } @@ -2271,6 +2392,7 @@ class BBCode */ public static function getShareOpeningTag(string $author, string $profile, string $avatar, string $link, string $posted, string $guid = null) { + DI::profiler()->startRecording('rendering'); $header = "[share author='" . str_replace(["'", "[", "]"], ["'", "[", "]"], $author) . "' profile='" . str_replace(["'", "[", "]"], ["'", "[", "]"], $profile) . "' avatar='" . str_replace(["'", "[", "]"], ["'", "[", "]"], $avatar) . @@ -2283,6 +2405,7 @@ class BBCode $header .= "']"; + DI::profiler()->stopRecording(); return $header; } @@ -2304,6 +2427,7 @@ class BBCode */ public static function embedURL(string $url, bool $tryAttachment = true, string $title = null, string $description = null, string $tags = null): string { + DI::profiler()->startRecording('rendering'); DI::logger()->info($url); // If there is already some content information submitted we don't @@ -2325,6 +2449,7 @@ class BBCode DI::logger()->info('(unparsed): returns: ' . $result); + DI::profiler()->stopRecording(); return $result; } @@ -2343,6 +2468,7 @@ class BBCode break; } + DI::profiler()->stopRecording(); return $bbcode; } @@ -2350,10 +2476,13 @@ class BBCode // Bypass attachment if parse url for a comment if (!$tryAttachment) { + DI::profiler()->stopRecording(); return "\n" . '[url=' . $url . ']' . $siteinfo['title'] . '[/url]'; } // Format it as BBCode attachment - return "\n" . PageInfo::getFooterFromData($siteinfo); + $bbcode = "\n" . PageInfo::getFooterFromData($siteinfo); + DI::profiler()->stopRecording(); + return $bbcode; } }