]> git.mxchange.org Git - friendica.git/blobdiff - src/Content/Text/BBCode.php
Merge pull request #10636 from nupplaphil/feat/httpclient_followup
[friendica.git] / src / Content / Text / BBCode.php
index 2f19a0101f69a4e78d2f48b85b71ae99c13346e6..5a2b966dd57c2ce6501522409e111e84d9c263ed 100644 (file)
@@ -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 = '<img src="' . 
+                               self::proxyUrl($match[2], $simplehtml, $uriid) . '"';
+                               foreach ($attributes as $key => $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,19 +1317,23 @@ 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;
        }
 
@@ -1271,8 +1345,11 @@ class BBCode
         */
        public static function setMentionsToNicknames(string $body):string
        {
+               DI::profiler()->startRecording('rendering');
                $regexp = "/([@!])\[url\=([^\[\]]*)\].*?\[\/url\]/ism";
-               return preg_replace_callback($regexp, ['self', 'mentionCallback'], $body);
+               $body = preg_replace_callback($regexp, ['self', 'mentionCallback'], $body);
+               DI::profiler()->stopRecording();
+               return $body;
        }
 
        /**
@@ -1360,6 +1437,8 @@ class BBCode
                        return '';
                }
 
+               DI::profiler()->startRecording('rendering');
+
                Hook::callAll('bbcode', $text);
 
                $a = DI::app();
@@ -1688,6 +1767,8 @@ class BBCode
 
                                $text = preg_replace("/\[img\](.*?)\[\/img\]/ism", '<img src="$1" alt="' . DI::l10n()->t('Image/photo') . '" />', $text);
                                $text = preg_replace("/\[zmg\](.*?)\[\/zmg\]/ism", '<img src="$1" alt="' . DI::l10n()->t('Image/photo') . '" />', $text);
+       
+                               $text = self::convertImages($text, $simple_html, $uriid);
 
                                $text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism", '<br><img src="' .DI::baseUrl() . '/images/lock_icon.gif" alt="' . DI::l10n()->t('Encrypted content') . '" title="' . DI::l10n()->t('Encrypted content') . '" /><br>', $text);
                                $text = preg_replace("/\[crypt(.*?)\](.*?)\[\/crypt\]/ism", '<br><img src="' .DI::baseUrl() . '/images/lock_icon.gif" alt="' . DI::l10n()->t('Encrypted content') . '" title="' . '$1' . ' ' . DI::l10n()->t('Encrypted content') . '" /><br>', $text);
@@ -1979,6 +2060,7 @@ class BBCode
                );
 
                $text = HTML::purify($text, $allowedIframeDomains);
+               DI::profiler()->stopRecording();
 
                return trim($text);
        }
@@ -1991,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;
        }
 
@@ -2006,6 +2090,7 @@ class BBCode
         */
        public static function getAbstract($text, $addon = '')
        {
+               DI::profiler()->startRecording('rendering');
                $abstract = '';
                $abstracts = [];
                $addon = strtolower($addon);
@@ -2024,6 +2109,7 @@ class BBCode
                        $abstract = $result[1];
                }
 
+               DI::profiler()->stopRecording();
                return $abstract;
        }
 
@@ -2062,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
@@ -2106,13 +2193,9 @@ class BBCode
                // Maybe we should make this newline at every time before a quote.
                $text = str_replace(['</a><blockquote>'], ['</a><br><blockquote>'], $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);
 
@@ -2131,6 +2214,7 @@ class BBCode
 
                Hook::callAll('bb2diaspora', $text);
 
+               DI::profiler()->stopRecording();
                return $text;
        }
 
@@ -2149,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) {
@@ -2199,6 +2284,7 @@ class BBCode
                        }
                });
 
+               DI::profiler()->stopRecording();
                return array_unique($ret);
        }
 
@@ -2258,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);
 
@@ -2289,6 +2376,7 @@ class BBCode
                        return $body;
                });
 
+               DI::profiler()->stopRecording();
                return $body;
        }
 
@@ -2304,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(["'", "[", "]"], ["&#x27;", "&#x5B;", "&#x5D;"], $author) .
                        "' profile='" . str_replace(["'", "[", "]"], ["&#x27;", "&#x5B;", "&#x5D;"], $profile) .
                        "' avatar='" . str_replace(["'", "[", "]"], ["&#x27;", "&#x5B;", "&#x5D;"], $avatar) .
@@ -2316,6 +2405,7 @@ class BBCode
 
                $header  .= "']";
 
+               DI::profiler()->stopRecording();
                return $header;
        }
 
@@ -2337,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
@@ -2358,6 +2449,7 @@ class BBCode
 
                        DI::logger()->info('(unparsed): returns: ' . $result);
 
+                       DI::profiler()->stopRecording();
                        return $result;
                }
 
@@ -2376,6 +2468,7 @@ class BBCode
                                        break;
                        }
 
+                       DI::profiler()->stopRecording();
                        return $bbcode;
                }
 
@@ -2383,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;
        }
 }