]> git.mxchange.org Git - friendica.git/blobdiff - src/Content/Text/BBCode.php
Merge pull request #6054 from nupplaphil/lock_logger
[friendica.git] / src / Content / Text / BBCode.php
index c3453bcf727bda8baf6f51517838e4403e7d43a6..22ce4ea3aeb112c14e5b313e609190ca30c16e86 100644 (file)
@@ -15,6 +15,7 @@ use Friendica\Core\Addon;
 use Friendica\Core\Cache;
 use Friendica\Core\Config;
 use Friendica\Core\L10n;
+use Friendica\Core\Logger;
 use Friendica\Core\Protocol;
 use Friendica\Core\System;
 use Friendica\Model\Contact;
@@ -379,7 +380,7 @@ class BBCode extends BaseObject
                $c = preg_match_all('/\[img.*?\](.*?)\[\/img\]/ism', $s, $matches, PREG_SET_ORDER);
                if ($c) {
                        foreach ($matches as $mtch) {
-                               logger('scale_external_image: ' . $mtch[1]);
+                               Logger::log('scale_external_image: ' . $mtch[1]);
 
                                $hostname = str_replace('www.', '', substr(System::baseUrl(), strpos(System::baseUrl(), '://') + 3));
                                if (stristr($mtch[1], $hostname)) {
@@ -414,7 +415,7 @@ class BBCode extends BaseObject
                                                        $Image->scaleDown(640);
                                                        $new_width = $Image->getWidth();
                                                        $new_height = $Image->getHeight();
-                                                       logger('scale_external_images: ' . $orig_width . '->' . $new_width . 'w ' . $orig_height . '->' . $new_height . 'h' . ' match: ' . $mtch[0], LOGGER_DEBUG);
+                                                       Logger::log('scale_external_images: ' . $orig_width . '->' . $new_width . 'w ' . $orig_height . '->' . $new_height . 'h' . ' match: ' . $mtch[0], Logger::DEBUG);
                                                        $s = str_replace(
                                                                $mtch[0],
                                                                '[img=' . $new_width . 'x' . $new_height. ']' . $scaled . '[/img]'
@@ -423,7 +424,7 @@ class BBCode extends BaseObject
                                                                        : ''),
                                                                $s
                                                        );
-                                                       logger('scale_external_images: new string: ' . $s, LOGGER_DEBUG);
+                                                       Logger::log('scale_external_images: new string: ' . $s, Logger::DEBUG);
                                                }
                                        }
                                }
@@ -451,7 +452,7 @@ class BBCode extends BaseObject
                // than the maximum, then don't waste time looking for the images
                if ($maxlen && (strlen($body) > $maxlen)) {
 
-                       logger('the total body length exceeds the limit', LOGGER_DEBUG);
+                       Logger::log('the total body length exceeds the limit', Logger::DEBUG);
 
                        $orig_body = $body;
                        $new_body = '';
@@ -471,7 +472,7 @@ class BBCode extends BaseObject
 
                                        if (($textlen + $img_start) > $maxlen) {
                                                if ($textlen < $maxlen) {
-                                                       logger('the limit happens before an embedded image', LOGGER_DEBUG);
+                                                       Logger::log('the limit happens before an embedded image', Logger::DEBUG);
                                                        $new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen);
                                                        $textlen = $maxlen;
                                                }
@@ -485,7 +486,7 @@ class BBCode extends BaseObject
 
                                        if (($textlen + $img_end) > $maxlen) {
                                                if ($textlen < $maxlen) {
-                                                       logger('the limit happens before the end of a non-embedded image', LOGGER_DEBUG);
+                                                       Logger::log('the limit happens before the end of a non-embedded image', Logger::DEBUG);
                                                        $new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen);
                                                        $textlen = $maxlen;
                                                }
@@ -508,11 +509,11 @@ class BBCode extends BaseObject
 
                        if (($textlen + strlen($orig_body)) > $maxlen) {
                                if ($textlen < $maxlen) {
-                                       logger('the limit happens after the end of the last image', LOGGER_DEBUG);
+                                       Logger::log('the limit happens after the end of the last image', Logger::DEBUG);
                                        $new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen);
                                }
                        } else {
-                               logger('the text size with embedded images extracted did not violate the limit', LOGGER_DEBUG);
+                               Logger::log('the text size with embedded images extracted did not violate the limit', Logger::DEBUG);
                                $new_body = $new_body . $orig_body;
                        }
 
@@ -859,187 +860,140 @@ class BBCode extends BaseObject
        }
 
        /**
-        * Processes [share] tags
+        * This function converts a [share] block to text according to a provided callback function whose signature is:
         *
-        * Note: Can produce a [bookmark] tag in the output
+        * function(array $attributes, array $author_contact, string $content, boolean $is_quote_share): string
         *
-        * @brief Processes [share] tags
-        * @param array    $share      preg_match_callback result array
-        * @param bool|int $simplehtml
-        * @return string
+        * Where:
+        * - $attributes is an array of attributes of the [share] block itself. Missing keys will be completed by the contact
+        * data lookup
+        * - $author_contact is a contact record array
+        * - $content is the inner content of the [share] block
+        * - $is_quote_share indicates whether there's any content before the [share] block
+        * - Return value is the string that should replace the [share] block in the provided text
+        *
+        * This function is intended to be used by addon connector to format a share block like the target network is expecting it.
+        *
+        * @param  string   $text     A BBCode string
+        * @param  callable $callback
+        * @return string The BBCode string with all [share] blocks replaced
         */
-       private static function convertShare($share, $simplehtml)
+       public static function convertShare($text, callable $callback)
        {
-               $attributes = $share[2];
-
-               $author = "";
-               preg_match("/author='(.*?)'/ism", $attributes, $matches);
-               if (x($matches, 1)) {
-                       $author = html_entity_decode($matches[1], ENT_QUOTES, 'UTF-8');
-               }
-
-               preg_match('/author="(.*?)"/ism', $attributes, $matches);
-               if (x($matches, 1)) {
-                       $author = $matches[1];
-               }
-
-               $profile = "";
-               preg_match("/profile='(.*?)'/ism", $attributes, $matches);
-               if (x($matches, 1)) {
-                       $profile = $matches[1];
-               }
-
-               preg_match('/profile="(.*?)"/ism', $attributes, $matches);
-               if (x($matches, 1)) {
-                       $profile = $matches[1];
-               }
-
-               $avatar = "";
-               preg_match("/avatar='(.*?)'/ism", $attributes, $matches);
-               if (x($matches, 1)) {
-                       $avatar = $matches[1];
-               }
-
-               preg_match('/avatar="(.*?)"/ism', $attributes, $matches);
-               if (x($matches, 1)) {
-                       $avatar = $matches[1];
-               }
-
-               $link = "";
-               preg_match("/link='(.*?)'/ism", $attributes, $matches);
-               if (x($matches, 1)) {
-                       $link = $matches[1];
-               }
-
-               preg_match('/link="(.*?)"/ism', $attributes, $matches);
-               if (x($matches, 1)) {
-                       $link = $matches[1];
-               }
-
-               $posted = "";
-
-               preg_match("/posted='(.*?)'/ism", $attributes, $matches);
-               if (x($matches, 1)) {
-                       $posted = $matches[1];
-               }
+               $return = preg_replace_callback(
+                       "/(.*?)\[share(.*?)\](.*?)\[\/share\]/ism",
+                       function ($match) use ($callback) {
+                               $attribute_string = $match[2];
+
+                               $attributes = [];
+                               foreach(['author', 'profile', 'avatar', 'link', 'posted'] as $field) {
+                                       preg_match("/$field=(['\"])(.+?)\\1/ism", $attribute_string, $matches);
+                                       $attributes[$field] = html_entity_decode(defaults($matches, 2, ''), ENT_QUOTES, 'UTF-8');
+                               }
 
-               preg_match('/posted="(.*?)"/ism', $attributes, $matches);
-               if (x($matches, 1)) {
-                       $posted = $matches[1];
-               }
+                               // 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);
 
-               // 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($profile, 0, true);
+                               $author_contact = Contact::getDetailsByURL($attributes['profile']);
+                               $author_contact['addr'] = defaults($author_contact, 'addr' , Protocol::getAddrFromProfileUrl($attributes['profile']));
 
-               $data = Contact::getDetailsByURL($profile);
+                               $attributes['author']   = defaults($author_contact, 'name' , $attributes['author']);
+                               $attributes['avatar']   = defaults($author_contact, 'micro', $attributes['avatar']);
+                               $attributes['profile']  = defaults($author_contact, 'url'  , $attributes['profile']);
 
-               if (x($data, "name") && x($data, "addr")) {
-                       $userid_compact = $data["name"] . " (" . $data["addr"] . ")";
-               } else {
-                       $userid_compact = Protocol::getAddrFromProfileUrl($profile, $author);
-               }
-
-               if (x($data, "addr")) {
-                       $userid = $data["addr"];
-               } else {
-                       $userid = Protocol::formatMention($profile, $author);
-               }
+                               if ($attributes['avatar']) {
+                                       $attributes['avatar'] = ProxyUtils::proxifyUrl($attributes['avatar'], false, ProxyUtils::SIZE_THUMB);
+                               }
 
-               if (x($data, "name")) {
-                       $author = $data["name"];
-               }
+                               return $match[1] . $callback($attributes, $author_contact, $match[3], trim($match[1]) != '');
+                       },
+                       $text
+               );
 
-               if (x($data, "micro")) {
-                       $avatar = $data["micro"];
-               }
+               return $return;
+       }
 
-               $preshare = trim($share[1]);
-               if ($preshare != "") {
-                       $preshare .= "<br />";
-               }
+       /**
+        * Default [share] tag conversion callback
+        *
+        * Note: Can produce a [bookmark] tag in the output
+        *
+        * @see BBCode::convertShare()
+        * @param array   $attributes     [share] block attribute values
+        * @param array   $author_contact Contact row of the shared author
+        * @param string  $content        Inner content of the [share] block
+        * @param boolean $is_quote_share Whether there is content before the [share] block
+        * @param integer $simplehtml     Mysterious integer value depending on the target network/formatting style
+        * @return string
+        */
+       private static function convertShareCallback(array $attributes, array $author_contact, $content, $is_quote_share, $simplehtml)
+       {
+               $mention = Protocol::formatMention($attributes['profile'], $attributes['author']);
 
                switch ($simplehtml) {
                        case 1:
-                               $text = $preshare . html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8') . ' <a href="' . $profile . '">' . $userid . "</a>: <br />»" . $share[3] . "«";
+                               $text = ($is_quote_share? '<br />' : '') . '<p>' . html_entity_decode('&#x2672; ', ENT_QUOTES, 'UTF-8') . ' <a href="' . $attributes['profile'] . '">' . $mention . '</a>: </p>' . "\n" . '«' . $content . '»';
                                break;
                        case 2:
-                               $text = $preshare . html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8') . ' ' . $userid_compact . ": <br />" . $share[3];
+                               $text = ($is_quote_share? '<br />' : '') . '<p>' . html_entity_decode('&#x2672; ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ': </p>' . "\n" . $content;
                                break;
                        case 3: // Diaspora
-                               $headline = '<b>' . html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8') . $userid . ':</b><br />';
-
-                               $text = trim($share[1]);
-
-                               if ($text != "") {
-                                       $text .= "<hr />";
-                               }
+                               $headline = '<p><b>' . html_entity_decode('&#x2672; ', ENT_QUOTES, 'UTF-8') . $mention . ':</b></p>' . "\n";
 
-                               if (stripos(normalise_link($link), 'http://twitter.com/') === 0) {
-                                       $text .= '<br /><a href="' . $link . '">' . $link . '</a>';
+                               if (stripos(normalise_link($attributes['link']), 'http://twitter.com/') === 0) {
+                                       $text = ($is_quote_share? '<hr />' : '') . '<p><a href="' . $attributes['link'] . '">' . $attributes['link'] . '</a></p>' . "\n";
                                } else {
-                                       $text .= $headline . '<blockquote>' . trim($share[3]) . "</blockquote><br />";
+                                       $text = ($is_quote_share? '<hr />' : '') . $headline . '<blockquote>' . trim($content) . '</blockquote>' . "\n";
 
-                                       if ($link != "") {
-                                               $text .= '<br /><a href="' . $link . '">[l]</a>';
+                                       if ($attributes['link'] != '') {
+                                               $text .= '<p><a href="' . $attributes['link'] . '">[l]</a></p>' . "\n";
                                        }
                                }
 
                                break;
                        case 4:
-                               $headline = '<br /><b>' . html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8');
-                               $headline .= L10n::t('<a href="%1$s" target="_blank">%2$s</a> %3$s', $link, $userid, $posted);
-                               $headline .= ":</b><br />";
+                               $headline = '<p><b>' . html_entity_decode('&#x2672; ', ENT_QUOTES, 'UTF-8');
+                               $headline .= L10n::t('<a href="%1$s" target="_blank">%2$s</a> %3$s', $attributes['link'], $mention, $attributes['posted']);
+                               $headline .= ':</b></p>' . "\n";
 
-                               $text = trim($share[1]);
-
-                               if ($text != "") {
-                                       $text .= "<hr />";
-                               }
-
-                               $text .= $headline . '<blockquote class="shared_content">' . trim($share[3]) . "</blockquote><br />";
+                               $text = ($is_quote_share? '<hr />' : '') . $headline . '<blockquote class="shared_content">' . trim($content) . '</blockquote>' . "\n";
 
                                break;
                        case 5:
-                               $text = $preshare . html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8') . ' ' . $userid_compact . ": <br />" . $share[3];
+                               $text = ($is_quote_share? '<br />' : '') . '<p>' . html_entity_decode('&#x2672; ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ': </p>' . "\n" . $content;
                                break;
                        case 7: // statusnet/GNU Social
-                               $text = $preshare . html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8') . " @" . $userid_compact . ": " . $share[3];
-                               break;
-                       case 8: // twitter
-                               $text = $preshare . "RT @" . $userid_compact . ": " . $share[3];
+                               $text = ($is_quote_share? '<br />' : '') . '<p>' . html_entity_decode('&#x2672; ', ENT_QUOTES, 'UTF-8') . ' @' . $author_contact['addr'] . ': ' . $content . '</p>' . "\n";
                                break;
                        case 9: // Google+
-                               $text = $preshare . html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8') . ' ' . $userid_compact . ": <br />" . $share[3];
+                               $text = ($is_quote_share? '<br />' : '') . '<p>' . html_entity_decode('&#x2672; ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ': </p>' . "\n";
+                               $text .= '<p>' . $content . '</p>' . "\n";
 
-                               if ($link != "") {
-                                       $text .= "<br /><br />" . $link;
+                               if ($attributes['link'] != '') {
+                                       $text .= '<p>' . $attributes['link'] . '</p>';
                                }
                                break;
                        default:
                                // Transforms quoted tweets in rich attachments to avoid nested tweets
-                               if (stripos(normalise_link($link), 'http://twitter.com/') === 0 && OEmbed::isAllowedURL($link)) {
+                               if (stripos(normalise_link($attributes['link']), 'http://twitter.com/') === 0 && OEmbed::isAllowedURL($attributes['link'])) {
                                        try {
-                                               $oembed = OEmbed::getHTML($link, $preshare);
+                                               $text = ($is_quote_share? '<br />' : '') . OEmbed::getHTML($attributes['link']);
                                        } catch (Exception $e) {
-                                               $oembed = sprintf('[bookmark=%s]%s[/bookmark]', $link, $preshare);
+                                               $text = ($is_quote_share? '<br />' : '') . sprintf('[bookmark=%s]%s[/bookmark]', $attributes['link'], $content);
                                        }
-
-                                       $text = $preshare . $oembed;
                                } else {
-                                       $text = trim($share[1]) . "\n";
-
-                                       $avatar = ProxyUtils::proxifyUrl($avatar, false, ProxyUtils::SIZE_THUMB);
+                                       $text = ($is_quote_share? "\n" : '');
 
                                        $tpl = get_markup_template('shared_content.tpl');
                                        $text .= replace_macros($tpl, [
-                                               '$profile' => $profile,
-                                               '$avatar' => $avatar,
-                                               '$author' => $author,
-                                               '$link' => $link,
-                                               '$posted' => $posted,
-                                               '$content' => trim($share[3])
+                                               '$profile' => $attributes['profile'],
+                                               '$avatar'  => $attributes['avatar'],
+                                               '$author'  => $attributes['author'],
+                                               '$link'    => $attributes['link'],
+                                               '$posted'  => $attributes['posted'],
+                                               '$content' => trim($content)
                                        ]);
                                }
                                break;
@@ -1060,11 +1014,11 @@ class BBCode extends BaseObject
                        $ch = @curl_init($match[1]);
                        @curl_setopt($ch, CURLOPT_NOBODY, true);
                        @curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-                       @curl_setopt($ch, CURLOPT_USERAGENT, $a->get_useragent());
+                       @curl_setopt($ch, CURLOPT_USERAGENT, $a->getUserAgent());
                        @curl_exec($ch);
                        $curl_info = @curl_getinfo($ch);
 
-                       $a->save_timestamp($stamp1, "network");
+                       $a->saveTimestamp($stamp1, "network");
 
                        if (substr($curl_info["content_type"], 0, 6) == "image/") {
                                $text = "[url=" . $match[1] . "]" . $match[1] . "[/url]";
@@ -1119,11 +1073,11 @@ class BBCode extends BaseObject
                        $ch = @curl_init($match[1]);
                        @curl_setopt($ch, CURLOPT_NOBODY, true);
                        @curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-                       @curl_setopt($ch, CURLOPT_USERAGENT, $a->get_useragent());
+                       @curl_setopt($ch, CURLOPT_USERAGENT, $a->getUserAgent());
                        @curl_exec($ch);
                        $curl_info = @curl_getinfo($ch);
 
-                       $a->save_timestamp($stamp1, "network");
+                       $a->saveTimestamp($stamp1, "network");
 
                        // if its a link to a picture then embed this picture
                        if (substr($curl_info["content_type"], 0, 6) == "image/") {
@@ -1265,9 +1219,6 @@ class BBCode extends BaseObject
                $text = preg_replace("/\s?\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism", "[share$1]$2[/share]", $text);
                $text = preg_replace("/\s?\[quote(.*?)\]\s?(.*?)\s?\[\/quote\]\s?/ism", "[quote$1]$2[/quote]", $text);
 
-               $text = preg_replace("/\n\[code\]/ism", "[code]", $text);
-               $text = preg_replace("/\[\/code\]\n/ism", "[/code]", $text);
-
                // when the content is meant exporting to other systems then remove the avatar picture since this doesn't really look good on these systems
                if (!$try_oembed) {
                        $text = preg_replace("/\[share(.*?)avatar\s?=\s?'.*?'\s?(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism", "\n[share$1$2]$3[/share]", $text);
@@ -1369,7 +1320,7 @@ class BBCode extends BaseObject
 
                // Handle Diaspora posts
                $text = preg_replace_callback(
-                       "&\[url=/posts/([^\[\]]*)\](.*)\[\/url\]&Usi",
+                       "&\[url=/?posts/([^\[\]]*)\](.*)\[\/url\]&Usi",
                        function ($match) {
                                return "[url=" . System::baseUrl() . "/display/" . $match[1] . "]" . $match[2] . "[/url]";
                        }, $text
@@ -1624,10 +1575,12 @@ class BBCode extends BaseObject
                $text = preg_replace("/\[zmg\](.*?)\[\/zmg\]/ism", '<img src="$1" alt="' . L10n::t('Image/photo') . '" />', $text);
 
                // Shared content
-               $text = preg_replace_callback("/(.*?)\[share(.*?)\](.*?)\[\/share\]/ism",
-                       function ($match) use ($simple_html) {
-                               return self::convertShare($match, $simple_html);
-                       }, $text);
+               $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", '<br/><img src="' .System::baseUrl() . '/images/lock_icon.gif" alt="' . L10n::t('Encrypted content') . '" title="' . L10n::t('Encrypted content') . '" /><br />', $text);
                $text = preg_replace("/\[crypt(.*?)\](.*?)\[\/crypt\]/ism", '<br/><img src="' .System::baseUrl() . '/images/lock_icon.gif" alt="' . L10n::t('Encrypted content') . '" title="' . '$1' . ' ' . L10n::t('Encrypted content') . '" /><br />', $text);
@@ -1717,18 +1670,6 @@ class BBCode extends BaseObject
                        $text = Smilies::replace($text, false, true);
                }
 
-               // Replace inline code blocks
-               $text = preg_replace_callback("|(?!<br[^>]*>)<code>([^<]*)</code>(?!<br[^>]*>)|ism",
-                       function ($match) use ($simple_html) {
-                               $return = '<key>' . $match[1] . '</key>';
-                               // Use <code> for Diaspora inline code blocks
-                               if ($simple_html === 3) {
-                                       $return = '<code>' . $match[1] . '</code>';
-                               }
-                               return $return;
-                       }
-               , $text);
-
                // Unhide all [noparse] contained bbtags unspacefying them
                // and triming the [noparse] tag.
 
@@ -1946,7 +1887,7 @@ class BBCode extends BaseObject
                // unmask the special chars back to HTML
                $text = str_replace(['&\_lt\_;', '&\_gt\_;', '&\_amp\_;'], ['&lt;', '&gt;', '&amp;'], $text);
 
-               $a->save_timestamp($stamp1, "parser");
+               $a->saveTimestamp($stamp1, "parser");
 
                // Libertree has a problem with escaped hashtags.
                $text = str_replace(['\#'], ['#'], $text);