]> git.mxchange.org Git - friendica.git/blobdiff - src/Content/Text/BBCode.php
Avoid proxyfying images that are removed or replaced later
[friendica.git] / src / Content / Text / BBCode.php
index 48fda6296c268d245f10240f094b0b7cf0fa1433..b1244d0ac3cd44255a15379bdf8b486bc388ad7b 100644 (file)
@@ -50,9 +50,10 @@ use Friendica\Util\XML;
 class BBCode
 {
        // Update this value to the current date whenever changes are made to BBCode::convert
-       const VERSION = '2021-04-24';
+       const VERSION = '2021-05-21';
 
        const INTERNAL = 0;
+       const EXTERNAL = 1;
        const API = 2;
        const DIASPORA = 3;
        const CONNECTORS = 4;
@@ -432,6 +433,10 @@ class BBCode
         */
        public static function toPlaintext($text, $keep_urls = true)
        {
+               // Remove pictures in advance to avoid unneeded proxy calls
+               $text = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", ' $2 ', $text);
+               $text = preg_replace("/\[img.*?\[\/img\]/ism", ' ', $text);
+
                $naked_text = HTML::toPlaintext(self::convert($text, false, 0, true), 0, !$keep_urls);
 
                return $naked_text;
@@ -952,6 +957,10 @@ class BBCode
         */
        public static function fetchShareAttributes($text)
        {
+               // 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)) {
                        return $attributes;
@@ -996,7 +1005,7 @@ class BBCode
                                        $attributes[$field] = html_entity_decode($matches[2] ?? '', ENT_QUOTES, 'UTF-8');
                                }
 
-                               $author_contact = Contact::getByURL($attributes['profile'], false, ['url', 'addr', 'name', 'micro']);
+                               $author_contact = Contact::getByURL($attributes['profile'], false, ['id', 'url', 'addr', 'name', 'micro']);
                                $author_contact['url'] = ($author_contact['url'] ?? $attributes['profile']);
                                $author_contact['addr'] = ($author_contact['addr'] ?? '') ?: Protocol::getAddrFromProfileUrl($attributes['profile']);
 
@@ -1004,8 +1013,10 @@ class BBCode
                                $attributes['avatar']   = ($author_contact['micro'] ?? '') ?: $attributes['avatar'];
                                $attributes['profile']  = ($author_contact['url']   ?? '') ?: $attributes['profile'];
 
-                               if ($attributes['avatar']) {
-                                       $attributes['avatar'] = ProxyUtils::proxifyUrl($attributes['avatar'], false, ProxyUtils::SIZE_THUMB);
+                               if (!empty($author_contact['id'])) {
+                                       $attributes['avatar'] = Contact::getAvatarUrlForId($author_contact['id'], ProxyUtils::SIZE_THUMB);
+                               } elseif ($attributes['avatar']) {
+                                       $attributes['avatar'] = ProxyUtils::proxifyUrl($attributes['avatar'], ProxyUtils::SIZE_THUMB);
                                }
 
                                $content = preg_replace(Strings::autoLinkRegEx(), '<a href="$1">$1</a>', $match[3]);
@@ -1038,7 +1049,9 @@ class BBCode
 
                switch ($simplehtml) {
                        case self::API:
-                               $text = ($is_quote_share? '<br>' : '') . '<p>' . html_entity_decode('&#x2672; ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ': </p>' . "\n" . $content;
+                               $text = ($is_quote_share? '<br>' : '') .
+                               '<p><b><a href="' . $attributes['link'] . '">' . html_entity_decode('&#x2672; ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . "</a>:</b> </p>\n" .
+                               '<blockquote class="shared_content">' . $content . '</blockquote>';
                                break;
                        case self::DIASPORA:
                                if (stripos(Strings::normaliseLink($attributes['link']), 'http://twitter.com/') === 0) {
@@ -1085,7 +1098,7 @@ class BBCode
                                        '$avatar'       => $attributes['avatar'],
                                        '$author'       => $attributes['author'],
                                        '$link'         => $attributes['link'],
-                                       '$link_title'   => DI::l10n()->t('link to source'),
+                                       '$link_title'   => DI::l10n()->t('Link to source'),
                                        '$posted'       => $attributes['posted'],
                                        '$guid'         => $attributes['guid'],
                                        '$network_name' => ContactSelector::networkToName($network, $attributes['profile']),
@@ -1104,20 +1117,14 @@ class BBCode
                $text = DI::cache()->get($cache_key);
 
                if (is_null($text)) {
-                       $a = DI::app();
-
-                       $stamp1 = microtime(true);
-
-                       $ch = @curl_init($match[1]);
-                       @curl_setopt($ch, CURLOPT_NOBODY, true);
-                       @curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-                       @curl_setopt($ch, CURLOPT_USERAGENT, DI::httpRequest()->getUserAgent());
-                       @curl_exec($ch);
-                       $curl_info = @curl_getinfo($ch);
-
-                       DI::profiler()->saveTimestamp($stamp1, "network");
+                       $curlResult = DI::httpRequest()->head($match[1], ['timeout' => DI::config()->get('system', 'xrd_timeout')]);
+                       if ($curlResult->isSuccess()) {
+                               $mimetype = $curlResult->getHeader('Content-Type');
+                       } else {
+                               $mimetype = '';
+                       }
 
-                       if (substr($curl_info['content_type'], 0, 6) == 'image/') {
+                       if (substr($mimetype, 0, 6) == 'image/') {
                                $text = "[url=" . $match[1] . ']' . $match[1] . "[/url]";
                        } else {
                                $text = "[url=" . $match[2] . ']' . $match[2] . "[/url]";
@@ -1181,20 +1188,15 @@ class BBCode
                        return $text;
                }
 
-               // Only fetch the header, not the content
-               $stamp1 = microtime(true);
-
-               $ch = @curl_init($match[1]);
-               @curl_setopt($ch, CURLOPT_NOBODY, true);
-               @curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-               @curl_setopt($ch, CURLOPT_USERAGENT, DI::httpRequest()->getUserAgent());
-               @curl_exec($ch);
-               $curl_info = @curl_getinfo($ch);
-
-               DI::profiler()->saveTimestamp($stamp1, "network");
+               $curlResult = DI::httpRequest()->head($match[1], ['timeout' => DI::config()->get('system', 'xrd_timeout')]);
+               if ($curlResult->isSuccess()) {
+                       $mimetype = $curlResult->getHeader('Content-Type');
+               } else {
+                       $mimetype = '';
+               }
 
                // if its a link to a picture then embed this picture
-               if (substr($curl_info['content_type'], 0, 6) == 'image/') {
+               if (substr($mimetype, 0, 6) == 'image/') {
                        $text = '[img]' . $match[1] . '[/img]';
                } else {
                        if (!empty($match[3])) {
@@ -1397,7 +1399,7 @@ class BBCode
                                // Handle attached links or videos
                                if ($simple_html == self::ACTIVITYPUB) {
                                        $text = self::removeAttachment($text);
-                               } elseif (!in_array($simple_html, [self::INTERNAL, self::CONNECTORS])) {
+                               } elseif (!in_array($simple_html, [self::INTERNAL, self::EXTERNAL, self::CONNECTORS])) {
                                        $text = self::removeAttachment($text, true);
                                } else {
                                        $text = self::convertAttachment($text, $simple_html, $try_oembed);
@@ -1407,9 +1409,9 @@ class BBCode
                                $text = str_replace('[nosmile]', '', $text);
 
                                // Replace non graphical smilies for external posts
-                               if (!$nosmile && !$for_plaintext) {
-                                       $text = self::performWithEscapedTags($text, ['img'], function ($text) {
-                                               return Smilies::replace($text);
+                               if (!$nosmile) {
+                                       $text = self::performWithEscapedTags($text, ['img'], function ($text) use ($simple_html, $for_plaintext) {
+                                               return Smilies::replace($text, ($simple_html != self::INTERNAL) || $for_plaintext);
                                        });
                                }
 
@@ -1731,7 +1733,7 @@ class BBCode
                                                $text);
                                } elseif (!$simple_html) {
                                        $text = preg_replace("/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism",
-                                               '$1<a href="$2" class="userinfo mention" title="$3">$3</a>',
+                                               '<bdi>$1<a href="$2" class="userinfo mention" title="$3">$3</a></bdi>',
                                                $text);
                                }
 
@@ -1903,7 +1905,7 @@ class BBCode
 
                $text = HTML::purify($text, $allowedIframeDomains);
 
-               return $text;
+               return trim($text);
        }
 
        /**
@@ -2125,6 +2127,32 @@ class BBCode
                return array_unique($ret);
        }
 
+       /**
+        * Expand tags to URLs
+        *
+        * @param string $body 
+        * @return string body with expanded tags 
+        */
+       public static function expandTags(string $body)
+       {
+               return preg_replace_callback("/([!#@])([^\^ \x0D\x0A,;:?\']*[^\^ \x0D\x0A,;:?!\'.])/",
+                       function ($match) {
+                               switch ($match[1]) {
+                                       case '!':
+                                       case '@':
+                                               $contact = Contact::getByURL($match[2]);
+                                               if (!empty($contact)) {
+                                                       return $match[1] . '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]';
+                                               } else {
+                                                       return $match[1] . $match[2];
+                                               }
+                                               break;
+                                       case '#':
+                                               return $match[1] . '[url=' . 'https://' . DI::baseUrl() . '/search?tag=' . $match[2] . ']' . $match[2] . '[/url]';
+                               }
+                       }, $body);
+       }
+
        /**
         * Perform a custom function on a text after having escaped blocks enclosed in the provided tag list.
         *
@@ -2178,9 +2206,7 @@ class BBCode
                                        }
                                }
 
-                               $success = Item::replaceTag($body, $inform, $profile_uid, $tag, $network);
-
-                               if ($success['replaced']) {
+                               if (($success = Item::replaceTag($body, $inform, $profile_uid, $tag, $network)) && $success['replaced']) {
                                        $tagged[] = $tag;
                                }
                        }