X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FContent%2FText%2FBBCode.php;h=c3453bcf727bda8baf6f51517838e4403e7d43a6;hb=406b46b63531bb45d73eda3badc7ba657c1ab8c0;hp=6de12167e521988fe2ca4982d741f1f4426189f9;hpb=e1a72b8f5ab3bf8024f6588279416f187f845ba5;p=friendica.git diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index 6de12167e5..c3453bcf72 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -2,33 +2,31 @@ /** * @file src/Content/Text/BBCode.php */ + namespace Friendica\Content\Text; use DOMDocument; -use DomXPath; +use DOMXPath; use Exception; +use Friendica\BaseObject; use Friendica\Content\OEmbed; use Friendica\Content\Smilies; -use Friendica\Content\Text\Plaintext; use Friendica\Core\Addon; use Friendica\Core\Cache; use Friendica\Core\Config; use Friendica\Core\L10n; use Friendica\Core\Protocol; -use Friendica\Core\PConfig; use Friendica\Core\System; use Friendica\Model\Contact; +use Friendica\Model\Event; +use Friendica\Network\Probe; use Friendica\Object\Image; use Friendica\Util\Map; use Friendica\Util\Network; use Friendica\Util\ParseUrl; +use Friendica\Util\Proxy as ProxyUtils; -require_once "include/event.php"; -require_once "include/html2plain.php"; -require_once "include/html2bbcode.php"; -require_once "mod/proxy.php"; - -class BBCode +class BBCode extends BaseObject { /** * @brief Fetches attachment data that were generated the old way @@ -74,10 +72,12 @@ class BBCode $picturedata = Image::getInfoFromURL($matches[1]); - if (($picturedata[0] >= 500) && ($picturedata[0] >= $picturedata[1])) { - $post["image"] = $matches[1]; - } else { - $post["preview"] = $matches[1]; + if ($picturedata) { + if (($picturedata[0] >= 500) && ($picturedata[0] >= $picturedata[1])) { + $post["image"] = $matches[1]; + } else { + $post["preview"] = $matches[1]; + } } } @@ -85,7 +85,7 @@ class BBCode $post["url"] = $matches[1]; $post["title"] = $matches[2]; } - if (($post["url"] == "") && (in_array($post["type"], ["link", "video"])) + if (!empty($post["url"]) && (in_array($post["type"], ["link", "video"])) && preg_match("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", $attacheddata, $matches)) { $post["url"] = $matches[1]; } @@ -174,7 +174,7 @@ class BBCode } if ($title != "") { - $title = BBCode::convert(html_entity_decode($title, ENT_QUOTES, 'UTF-8'), false, true); + $title = self::convert(html_entity_decode($title, ENT_QUOTES, 'UTF-8'), false, true); $title = html_entity_decode($title, ENT_QUOTES, 'UTF-8'); $title = str_replace(["[", "]"], ["[", "]"], $title); $data["title"] = $title; @@ -239,6 +239,9 @@ class BBCode $body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $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 ((count($pictures) == 1) && !$has_title) { // Checking, if the link goes to a picture @@ -264,7 +267,7 @@ class BBCode $post["text"] = str_replace($pictures[0][0], "", $body); } else { $imgdata = Image::getInfoFromURL($pictures[0][1]); - if (substr($imgdata["mime"], 0, 6) == "image/") { + if ($imgdata && substr($imgdata["mime"], 0, 6) == "image/") { $post["type"] = "photo"; $post["image"] = $pictures[0][1]; $post["preview"] = $pictures[0][2]; @@ -336,159 +339,30 @@ class BBCode } /** - * @brief Convert a message into plaintext for connectors to other networks + * @brief Converts a BBCode text into plaintext * - * @param array $b The message array that is about to be posted - * @param int $limit The maximum number of characters when posting to that network - * @param bool $includedlinks Has an attached link to be included into the message? - * @param int $htmlmode This triggers the behaviour of the bbcode conversion - * @param string $target_network Name of the network where the post should go to. + * @param bool $keep_urls Whether to keep URLs in the resulting plaintext * - * @return string The converted message + * @return string */ - public static function toPlaintext($b, $limit = 0, $includedlinks = false, $htmlmode = 2, $target_network = "") + public static function toPlaintext($text, $keep_urls = true) { - // Remove the hash tags - $URLSearchString = "^\[\]"; - $body = preg_replace("/([#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $b["body"]); - - // Add an URL element if the text contains a raw link - $body = preg_replace("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url]$2[/url]', $body); - - // Remove the abstract - $body = self::stripAbstract($body); - - // At first look at data that is attached via "type-..." stuff - // This will hopefully replaced with a dedicated bbcode later - //$post = self::getAttachedData($b["body"]); - $post = self::getAttachedData($body, $b); - - if (($b["title"] != "") && ($post["text"] != "")) { - $post["text"] = trim($b["title"]."\n\n".$post["text"]); - } elseif ($b["title"] != "") { - $post["text"] = trim($b["title"]); + $naked_text = preg_replace('/\[(.+?)\]\s*/','', $text); + if (!$keep_urls) { + $naked_text = preg_replace('#https?\://[^\s<]+[^\s\.\)]#i', '', $naked_text); } - $abstract = ""; - - // Fetch the abstract from the given target network - if ($target_network != "") { - $default_abstract = self::getAbstract($b["body"]); - $abstract = self::getAbstract($b["body"], $target_network); - - // If we post to a network with no limit we only fetch - // an abstract exactly for this network - if (($limit == 0) && ($abstract == $default_abstract)) { - $abstract = ""; - } - } else {// Try to guess the correct target network - switch ($htmlmode) { - case 8: - $abstract = self::getAbstract($b["body"], NETWORK_TWITTER); - break; - case 7: - $abstract = self::getAbstract($b["body"], NETWORK_STATUSNET); - break; - case 6: - $abstract = self::getAbstract($b["body"], NETWORK_APPNET); - break; - default: // We don't know the exact target. - // We fetch an abstract since there is a posting limit. - if ($limit > 0) { - $abstract = self::getAbstract($b["body"]); - } - } - } - - if ($abstract != "") { - $post["text"] = $abstract; - - if ($post["type"] == "text") { - $post["type"] = "link"; - $post["url"] = $b["plink"]; - } - } - - $html = BBCode::convert($post["text"].$post["after"], false, $htmlmode); - $msg = html2plain($html, 0, true); - $msg = trim(html_entity_decode($msg, ENT_QUOTES, 'UTF-8')); - - $link = ""; - if ($includedlinks) { - if ($post["type"] == "link") { - $link = $post["url"]; - } elseif ($post["type"] == "text") { - $link = $post["url"]; - } elseif ($post["type"] == "video") { - $link = $post["url"]; - } elseif ($post["type"] == "photo") { - $link = $post["image"]; - } - - if (($msg == "") && isset($post["title"])) { - $msg = trim($post["title"]); - } - - if (($msg == "") && isset($post["description"])) { - $msg = trim($post["description"]); - } - - // If the link is already contained in the post, then it neeedn't to be added again - // But: if the link is beyond the limit, then it has to be added. - if (($link != "") && strstr($msg, $link)) { - $pos = strpos($msg, $link); - - // Will the text be shortened in the link? - // Or is the link the last item in the post? - if (($limit > 0) && ($pos < $limit) && (($pos + 23 > $limit) || ($pos + strlen($link) == strlen($msg)))) { - $msg = trim(str_replace($link, "", $msg)); - } elseif (($limit == 0) || ($pos < $limit)) { - // The limit has to be increased since it will be shortened - but not now - // Only do it with Twitter (htmlmode = 8) - if (($limit > 0) && (strlen($link) > 23) && ($htmlmode == 8)) { - $limit = $limit - 23 + strlen($link); - } - - $link = ""; - - if ($post["type"] == "text") { - unset($post["url"]); - } - } - } - } - - if ($limit > 0) { - // Reduce multiple spaces - // When posted to a network with limited space, we try to gain space where possible - while (strpos($msg, " ") !== false) { - $msg = str_replace(" ", " ", $msg); - } - - // Twitter is using its own limiter, so we always assume that shortened links will have this length - if (iconv_strlen($link, "UTF-8") > 0) { - $limit = $limit - 23; - } + return $naked_text; + } - if (iconv_strlen($msg, "UTF-8") > $limit) { - if (($post["type"] == "text") && isset($post["url"])) { - $post["url"] = $b["plink"]; - } elseif (!isset($post["url"])) { - $limit = $limit - 23; - $post["url"] = $b["plink"]; - // Which purpose has this line? It is now uncommented, but left as a reminder - //} elseif (strpos($b["body"], "[share") !== false) { - // $post["url"] = $b["plink"]; - } elseif (PConfig::get($b["uid"], "system", "no_intelligent_shortening")) { - $post["url"] = $b["plink"]; - } - $msg = Plaintext::shorten($msg, $limit); - } + private static function proxyUrl($image, $simplehtml = false) + { + // Only send proxied pictures to API and for internal display + if (in_array($simplehtml, [false, 2])) { + return ProxyUtils::proxifyUrl($image); + } else { + return $image; } - - $post["text"] = trim($msg); - - return($post); } public static function scaleExternalImages($srctext, $include_link = true, $scale_replace = false) @@ -571,7 +445,7 @@ class BBCode */ public static function limitBodySize($body) { - $maxlen = get_max_import_size(); + $maxlen = Config::get('config', 'max_import_size', 0); // If the length of the body, including the embedded images, is smaller // than the maximum, then don't waste time looking for the images @@ -662,16 +536,18 @@ class BBCode private static function convertAttachment($return, $simplehtml = false, $tryoembed = true) { $data = self::getAttachmentData($return); - if (!$data) { + if (empty($data) || empty($data["url"])) { return $return; } if (isset($data["title"])) { $data["title"] = strip_tags($data["title"]); $data["title"] = str_replace(["http://", "https://"], "", $data["title"]); + } else { + $data["title"] = null; } - if (((strpos($data["text"], "[img=") !== false) || (strpos($data["text"], "[img]") !== false) || Config::get('system', 'always_show_preview')) && ($data["image"] != "")) { + if (((strpos($data["text"], "[img=") !== false) || (strpos($data["text"], "[img]") !== false) || Config::get('system', 'always_show_preview')) && !empty($data["image"])) { $data["preview"] = $data["image"]; $data["image"] = ""; } @@ -689,28 +565,32 @@ class BBCode throw new Exception('OEmbed is disabled for this attachment.'); } } catch (Exception $e) { + $data["title"] = defaults($data, 'title', $data['url']); + if ($simplehtml != 4) { $return = sprintf('
%s', trim(self::convert($bbcode))); } - if ($data["type"] == "link") { + + if (!empty($data['url'])) { $return .= sprintf('%s', $data['url'], parse_url($data['url'], PHP_URL_HOST)); } @@ -720,7 +600,7 @@ class BBCode } } - return trim($data["text"] . ' ' . $return . ' ' . $data["after"]); + return trim(defaults($data, 'text', '') . ' ' . $return . ' ' . defaults($data, 'after', '')); } public static function removeShareInformation($Text, $plaintext = false, $nolink = false) @@ -730,10 +610,10 @@ class BBCode if (!$data) { return $Text; } elseif ($nolink) { - return $data["text"] . $data["after"]; + return $data["text"] . defaults($data, 'after', ''); } - $title = htmlentities($data["title"], ENT_QUOTES, 'UTF-8', false); + $title = htmlentities(defaults($data, 'title', ''), ENT_QUOTES, 'UTF-8', false); $text = htmlentities($data["text"], ENT_QUOTES, 'UTF-8', false); if ($plaintext || (($title != "") && strstr($text, $title))) { $data["title"] = $data["url"]; @@ -747,42 +627,21 @@ class BBCode } // If the link already is included in the post, don't add it again - if (($data["url"] != "") && strpos($data["text"], $data["url"])) { + if (!empty($data["url"]) && strpos($data["text"], $data["url"])) { return $data["text"] . $data["after"]; } $text = $data["text"]; - if (($data["url"] != "") && ($data["title"] != "")) { + if (!empty($data["url"]) && !empty($data["title"])) { $text .= "\n[url=" . $data["url"] . "]" . $data["title"] . "[/url]"; - } elseif (($data["url"] != "")) { + } elseif (!empty($data["url"])) { $text .= "\n[url]" . $data["url"] . "[/url]"; } return $text . "\n" . $data["after"]; } - private static function cleanCss($input) - { - $cleaned = ""; - - $input = strtolower($input); - - for ($i = 0; $i < strlen($input); $i++) { - $char = substr($input, $i, 1); - - if (($char >= "a") && ($char <= "z")) { - $cleaned .= $char; - } - - if (!(strpos(" #;:0123456789-_.%", $char) === false)) { - $cleaned .= $char; - } - } - - return $cleaned; - } - /** * Converts [url] BBCodes in a format that looks fine on Mastodon. (callback function) * @@ -826,48 +685,6 @@ class BBCode return sprintf($html, $url, $styled_url); } - /** - * @brief Shortens [url] BBCodes in a format that looks less ugly than the full address. (callback function) - * @param array $match Array with the matching values - * @return string reformatted link including HTML codes - */ - private static function shortenVisibleUrlCallback($match) - { - $url = $match[1]; - - if (isset($match[2]) && ($match[1] != $match[2])) { - return $match[0]; - } - - $parts = parse_url($url); - if (!isset($parts['scheme'])) { - return $match[0]; - } - - return self::shortenVisibleUrl($url); - } - - /** - * @brief Shortens [url] BBCodes in a format that looks less ugly than the full address. - * @param string $url URL that is about to be reformatted - * @return string reformatted link including HTML codes - */ - private static function shortenVisibleUrl($url) - { - $parts = parse_url($url); - $scheme = $parts['scheme'] . '://'; - $styled_url = str_replace($scheme, '', $url); - -// Currently deactivated, due to preview problems inside of Diaspora -// if (strlen($styled_url) > 30) { -// $styled_url = substr($styled_url, 0, 30) . "â¦"; -// } - - $html = '%s'; - - return sprintf($html, $url, $styled_url); - } - /* * [noparse][i]italic[/i][/noparse] turns into * [noparse][ i ]italic[ /i ][/noparse], @@ -1034,7 +851,7 @@ class BBCode // it loops over the array starting from the first element and going sequentially // to the last element $newbody = str_replace('[$#saved_image' . $cnt . '#$]', - '
' . trim($matches[2], "\n\r") . '
';
+ }
+ return $return;
+ },
+ $text
+ );
+
// Hide all [noparse] contained bbtags by spacefying them
// POSSIBLE BUG --> Will the 'preg' functions crash if there's an embedded image?
@@ -1434,7 +1253,7 @@ class BBCode
// After we're finished processing the bbcode we'll
// replace all of the event code with a reformatted version.
- $ev = bbtoevent($text);
+ $ev = Event::fromBBCode($text);
// Replace any html brackets with HTML Entities to prevent executing HTML or script
// Don't use strip_tags here because it breaks [url] search by replacing & with amp
@@ -1454,11 +1273,6 @@ class BBCode
$text = preg_replace("/\[share(.*?)avatar\s?=\s?'.*?'\s?(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism", "\n[share$1$2]$3[/share]", $text);
}
- // Check for [code] text here, before the linefeeds are messed with.
- // The highlighter will unescape and re-escape the content.
- if (strpos($text, '[code=') !== false) {
- $text = preg_replace_callback("/\[code=(.*?)\](.*?)\[\/code\]/ism", 'self::textHighlightCallback', $text);
- }
// Convert new line chars to html ' . Map::byLocation($match[1]) . '
', $match[0]); + function ($match) use ($simple_html) { + return str_replace($match[0], '' . Map::byLocation($match[1], $simple_html) . '
', $match[0]); }, $text ); @@ -1607,14 +1425,14 @@ class BBCode if (strpos($text, '[map=') !== false) { $text = preg_replace_callback( "/\[map=(.*?)\]/ism", - function ($match) { - return str_replace($match[0], '' . Map::byCoordinates(str_replace('/', ' ', $match[1])) . '
', $match[0]); + function ($match) use ($simple_html) { + return str_replace($match[0], '' . Map::byCoordinates(str_replace('/', ' ', $match[1]), $simple_html) . '
', $match[0]); }, $text ); } if (strpos($text, '[map]') !== false) { - $text = preg_replace("/\[map\]/", '', $text); + $text = preg_replace("/\[map\]/", '', $text); } // Check for headers @@ -1638,7 +1456,7 @@ class BBCode $text = preg_replace("(\[u\](.*?)\[\/u\])ism", '$1', $text); // Check for strike-through text - $text = preg_replace("(\[s\](.*?)\[\/s\])ism", '"], [""], $text); + + $stamp1 = microtime(true); + + // Now convert HTML to Markdown + $text = HTML::toMarkdown($text); + + // unmask the special chars back to HTML + $text = str_replace(['&\_lt\_;', '&\_gt\_;', '&\_amp\_;'], ['<', '>', '&'], $text); + + $a->save_timestamp($stamp1, "parser"); + + // Libertree has a problem with escaped hashtags. + $text = str_replace(['\#'], ['#'], $text); + + // Remove any leading or trailing whitespace, as this will mess up + // the Diaspora signature verification and cause the item to disappear + $text = trim($text); + + if ($for_diaspora) { + $url_search_string = "^\[\]"; + $text = preg_replace_callback( + "/([@]\[(.*?)\])\(([$url_search_string]*?)\)/ism", + ['self', 'bbCodeMention2DiasporaCallback'], + $text + ); + } + + Addon::callHooks('bb2diaspora', $text); + + return $text; + } }