X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FContent%2FText%2FBBCode.php;h=8187521582ff253a665b7acd45031d7c3fd54c66;hb=07cea24430420cb0ac2b1d8f870d7292002c7faf;hp=a60e17c90eeb787e76349349546d00e38f44210d;hpb=cc1160a243a45c19954dfca878037e09da5903c0;p=friendica.git diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index a60e17c90e..8187521582 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -24,6 +24,7 @@ use Friendica\Model\Event; use Friendica\Model\Photo; use Friendica\Network\Probe; use Friendica\Object\Image; +use Friendica\Protocol\Activity; use Friendica\Util\Map; use Friendica\Util\Network; use Friendica\Util\ParseUrl; @@ -38,7 +39,7 @@ class BBCode extends BaseObject * * @param string $body Message body * @return array - * 'type' -> Message type ("link", "video", "photo") + * 'type' -> Message type ('link', 'video', 'photo') * 'text' -> Text before the shared message * 'after' -> Text after the shared message * 'image' -> Preview image of the message @@ -56,19 +57,19 @@ class BBCode extends BaseObject if (preg_match_all("(\[class=(.*?)\](.*?)\[\/class\])ism", $body, $attached, PREG_SET_ORDER)) { foreach ($attached as $data) { - if (!in_array($data[1], ["type-link", "type-video", "type-photo"])) { + if (!in_array($data[1], ['type-link', 'type-video', 'type-photo'])) { continue; } - $post["type"] = substr($data[1], 5); + $post['type'] = substr($data[1], 5); $pos = strpos($body, $data[0]); if ($pos > 0) { - $post["text"] = trim(substr($body, 0, $pos)); - $post["after"] = trim(substr($body, $pos + strlen($data[0]))); + $post['text'] = trim(substr($body, 0, $pos)); + $post['after'] = trim(substr($body, $pos + strlen($data[0]))); } else { - $post["text"] = trim(str_replace($data[0], "", $body)); - $post["after"] = ''; + $post['text'] = trim(str_replace($data[0], '', $body)); + $post['after'] = ''; } $attacheddata = $data[2]; @@ -79,25 +80,25 @@ class BBCode extends BaseObject if ($picturedata) { if (($picturedata[0] >= 500) && ($picturedata[0] >= $picturedata[1])) { - $post["image"] = $matches[1]; + $post['image'] = $matches[1]; } else { - $post["preview"] = $matches[1]; + $post['preview'] = $matches[1]; } } } if (preg_match("/\[bookmark\=(.*?)\](.*?)\[\/bookmark\]/ism", $attacheddata, $matches)) { - $post["url"] = $matches[1]; - $post["title"] = $matches[2]; + $post['url'] = $matches[1]; + $post['title'] = $matches[2]; } - if (!empty($post["url"]) && (in_array($post["type"], ["link", "video"])) + if (!empty($post['url']) && (in_array($post['type'], ['link', 'video'])) && preg_match("/\[url\=(.*?)\](.*?)\[\/url\]/ism", $attacheddata, $matches)) { - $post["url"] = $matches[1]; + $post['url'] = $matches[1]; } // Search for description if (preg_match("/\[quote\](.*?)\[\/quote\]/ism", $attacheddata, $matches)) { - $post["description"] = $matches[1]; + $post['description'] = $matches[1]; } } } @@ -109,7 +110,7 @@ class BBCode extends BaseObject * * @param string $body Message body * @return array - * 'type' -> Message type ("link", "video", "photo") + * 'type' -> Message type ('link', 'video', 'photo') * 'text' -> Text before the shared message * 'after' -> Text after the shared message * 'image' -> Preview image of the message @@ -136,9 +137,9 @@ class BBCode extends BaseObject $attributes = $match[2]; - $data["text"] = trim($match[1]); + $data['text'] = trim($match[1]); - $type = ""; + $type = ''; preg_match("/type='(.*?)'/ism", $attributes, $matches); if (!empty($matches[1])) { $type = strtolower($matches[1]); @@ -149,19 +150,19 @@ class BBCode extends BaseObject $type = strtolower($matches[1]); } - if ($type == "") { + if ($type == '') { return []; } - if (!in_array($type, ["link", "audio", "photo", "video"])) { + if (!in_array($type, ['link', 'audio', 'photo', 'video'])) { return []; } - if ($type != "") { - $data["type"] = $type; + if ($type != '') { + $data['type'] = $type; } - $url = ""; + $url = ''; preg_match("/url='(.*?)'/ism", $attributes, $matches); if (!empty($matches[1])) { $url = $matches[1]; @@ -172,11 +173,11 @@ class BBCode extends BaseObject $url = $matches[1]; } - if ($url != "") { - $data["url"] = html_entity_decode($url, ENT_QUOTES, 'UTF-8'); + if ($url != '') { + $data['url'] = html_entity_decode($url, ENT_QUOTES, 'UTF-8'); } - $title = ""; + $title = ''; preg_match("/title='(.*?)'/ism", $attributes, $matches); if (!empty($matches[1])) { $title = $matches[1]; @@ -187,14 +188,14 @@ class BBCode extends BaseObject $title = $matches[1]; } - if ($title != "") { + if ($title != '') { $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; + $title = str_replace(['[', ']'], ['[', ']'], $title); + $data['title'] = $title; } - $image = ""; + $image = ''; preg_match("/image='(.*?)'/ism", $attributes, $matches); if (!empty($matches[1])) { $image = $matches[1]; @@ -205,11 +206,11 @@ class BBCode extends BaseObject $image = $matches[1]; } - if ($image != "") { - $data["image"] = html_entity_decode($image, ENT_QUOTES, 'UTF-8'); + if ($image != '') { + $data['image'] = html_entity_decode($image, ENT_QUOTES, 'UTF-8'); } - $preview = ""; + $preview = ''; preg_match("/preview='(.*?)'/ism", $attributes, $matches); if (!empty($matches[1])) { $preview = $matches[1]; @@ -220,13 +221,13 @@ class BBCode extends BaseObject $preview = $matches[1]; } - if ($preview != "") { - $data["preview"] = html_entity_decode($preview, ENT_QUOTES, 'UTF-8'); + if ($preview != '') { + $data['preview'] = html_entity_decode($preview, ENT_QUOTES, 'UTF-8'); } - $data["description"] = trim($match[3]); + $data['description'] = trim($match[3]); - $data["after"] = trim($match[4]); + $data['after'] = trim($match[4]); return $data; } @@ -244,7 +245,7 @@ class BBCode extends BaseObject */ $has_title = !empty($item['title']); - $plink = defaults($item, 'plink', ''); + $plink = $item['plink'] ?? ''; $post = self::getAttachmentData($body); // Get all linked images with alternative image description @@ -268,15 +269,15 @@ class BBCode extends BaseObject } // if nothing is found, it maybe having an image. - if (!isset($post["type"])) { + if (!isset($post['type'])) { // Simplify image codes $body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body); $body = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", '[img]$1[/img]', $body); - $post["text"] = $body; + $post['text'] = $body; if (preg_match_all("(\[url=(.*?)\]\s*\[img\](.*?)\[\/img\]\s*\[\/url\])ism", $body, $pictures, PREG_SET_ORDER)) { if ((count($pictures) == 1) && !$has_title) { - if (!empty($item['object-type']) && ($item['object-type'] == ACTIVITY_OBJ_IMAGE)) { + if (!empty($item['object-type']) && ($item['object-type'] == Activity::OBJ_IMAGE)) { // Replace the preview picture with the real picture $url = str_replace('-1.', '-0.', $pictures[0][2]); $data = ['url' => $url, 'type' => 'photo']; @@ -288,75 +289,75 @@ class BBCode extends BaseObject // Workaround: // Sometimes photo posts to the own album are not detected at the start. // So we seem to cannot use the cache for these cases. That's strange. - if (($data["type"] != "photo") && strstr($pictures[0][1], "/photos/")) { + if (($data['type'] != 'photo') && strstr($pictures[0][1], "/photos/")) { $data = ParseUrl::getSiteinfo($pictures[0][1], true); } - if ($data["type"] == "photo") { - $post["type"] = "photo"; - if (isset($data["images"][0])) { - $post["image"] = $data["images"][0]["src"]; - $post["url"] = $data["url"]; + if ($data['type'] == 'photo') { + $post['type'] = 'photo'; + if (isset($data['images'][0])) { + $post['image'] = $data['images'][0]['src']; + $post['url'] = $data['url']; } else { - $post["image"] = $data["url"]; + $post['image'] = $data['url']; } - $post["preview"] = $pictures[0][2]; - $post["text"] = trim(str_replace($pictures[0][0], "", $body)); + $post['preview'] = $pictures[0][2]; + $post['text'] = trim(str_replace($pictures[0][0], '', $body)); } else { $imgdata = Image::getInfoFromURL($pictures[0][1]); - if ($imgdata && substr($imgdata["mime"], 0, 6) == "image/") { - $post["type"] = "photo"; - $post["image"] = $pictures[0][1]; - $post["preview"] = $pictures[0][2]; - $post["text"] = trim(str_replace($pictures[0][0], "", $body)); + if ($imgdata && substr($imgdata['mime'], 0, 6) == 'image/') { + $post['type'] = 'photo'; + $post['image'] = $pictures[0][1]; + $post['preview'] = $pictures[0][2]; + $post['text'] = trim(str_replace($pictures[0][0], '', $body)); } } } elseif (count($pictures) > 0) { - $post["type"] = "link"; - $post["url"] = $plink; - $post["image"] = $pictures[0][2]; - $post["text"] = $body; + $post['type'] = 'link'; + $post['url'] = $plink; + $post['image'] = $pictures[0][2]; + $post['text'] = $body; foreach ($pictures as $picture) { - $post["text"] = trim(str_replace($picture[0], "", $post["text"])); + $post['text'] = trim(str_replace($picture[0], '', $post['text'])); } } } elseif (preg_match_all("(\[img\](.*?)\[\/img\])ism", $body, $pictures, PREG_SET_ORDER)) { if ((count($pictures) == 1) && !$has_title) { - $post["type"] = "photo"; - $post["image"] = $pictures[0][1]; - $post["text"] = str_replace($pictures[0][0], "", $body); + $post['type'] = 'photo'; + $post['image'] = $pictures[0][1]; + $post['text'] = str_replace($pictures[0][0], '', $body); } elseif (count($pictures) > 0) { - $post["type"] = "link"; - $post["url"] = $plink; - $post["image"] = $pictures[0][1]; - $post["text"] = $body; + $post['type'] = 'link'; + $post['url'] = $plink; + $post['image'] = $pictures[0][1]; + $post['text'] = $body; foreach ($pictures as $picture) { - $post["text"] = trim(str_replace($picture[0], "", $post["text"])); + $post['text'] = trim(str_replace($picture[0], '', $post['text'])); } } } // Test for the external links - preg_match_all("(\[url\](.*?)\[\/url\])ism", $post["text"], $links1, PREG_SET_ORDER); - preg_match_all("(\[url\=(.*?)\].*?\[\/url\])ism", $post["text"], $links2, PREG_SET_ORDER); + preg_match_all("(\[url\](.*?)\[\/url\])ism", $post['text'], $links1, PREG_SET_ORDER); + preg_match_all("(\[url\=(.*?)\].*?\[\/url\])ism", $post['text'], $links2, PREG_SET_ORDER); $links = array_merge($links1, $links2); // If there is only a single one, then use it. // This should cover link posts via API. - if ((count($links) == 1) && !isset($post["preview"]) && !$has_title) { - $post["type"] = "link"; - $post["url"] = $links[0][1]; + if ((count($links) == 1) && !isset($post['preview']) && !$has_title) { + $post['type'] = 'link'; + $post['url'] = $links[0][1]; } // Now count the number of external media links - preg_match_all("(\[vimeo\](.*?)\[\/vimeo\])ism", $post["text"], $links1, PREG_SET_ORDER); - preg_match_all("(\[youtube\\](.*?)\[\/youtube\\])ism", $post["text"], $links2, PREG_SET_ORDER); - preg_match_all("(\[video\\](.*?)\[\/video\\])ism", $post["text"], $links3, PREG_SET_ORDER); - preg_match_all("(\[audio\\](.*?)\[\/audio\\])ism", $post["text"], $links4, PREG_SET_ORDER); + preg_match_all("(\[vimeo\](.*?)\[\/vimeo\])ism", $post['text'], $links1, PREG_SET_ORDER); + preg_match_all("(\[youtube\\](.*?)\[\/youtube\\])ism", $post['text'], $links2, PREG_SET_ORDER); + preg_match_all("(\[video\\](.*?)\[\/video\\])ism", $post['text'], $links3, PREG_SET_ORDER); + preg_match_all("(\[audio\\](.*?)\[\/audio\\])ism", $post['text'], $links4, PREG_SET_ORDER); // Add them to the other external links $links = array_merge($links, $links1, $links2, $links3, $links4); @@ -364,19 +365,19 @@ class BBCode extends BaseObject // Are there more than one? if (count($links) > 1) { // The post will be the type "text", which means a blog post - unset($post["type"]); - $post["url"] = $plink; + unset($post['type']); + $post['url'] = $plink; } - if (!isset($post["type"])) { - $post["type"] = "text"; - $post["text"] = trim($body); + if (!isset($post['type'])) { + $post['type'] = "text"; + $post['text'] = trim($body); } - } elseif (isset($post["url"]) && ($post["type"] == "video")) { - $data = ParseUrl::getSiteinfoCached($post["url"], true); + } elseif (isset($post['url']) && ($post['type'] == 'video')) { + $data = ParseUrl::getSiteinfoCached($post['url'], true); - if (isset($data["images"][0])) { - $post["image"] = $data["images"][0]["src"]; + if (isset($data['images'][0])) { + $post['image'] = $data['images'][0]['src']; } } @@ -581,27 +582,27 @@ class BBCode extends BaseObject private static function convertAttachment($return, $simplehtml = false, $tryoembed = true) { $data = self::getAttachmentData($return); - if (empty($data) || empty($data["url"])) { + 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"]); + if (isset($data['title'])) { + $data['title'] = strip_tags($data['title']); + $data['title'] = str_replace(['http://', 'https://'], '', $data['title']); } else { - $data["title"] = null; + $data['title'] = null; } - 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"] = ""; + 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'] = ''; } $return = ''; if (in_array($simplehtml, [7, 9])) { - $return = self::convertUrlForOStatus($data["url"]); + $return = self::convertUrlForActivityPub($data['url']); } elseif (($simplehtml != 4) && ($simplehtml != 0)) { - $return = sprintf('%s
', $data["url"], $data["title"]); + $return = sprintf('%s
', $data['url'], $data['title']); } else { try { if ($tryoembed && OEmbed::isAllowedURL($data['url'])) { @@ -610,28 +611,28 @@ class BBCode extends BaseObject throw new Exception('OEmbed is disabled for this attachment.'); } } catch (Exception $e) { - $data["title"] = defaults($data, 'title', $data['url']); + $data['title'] = ($data['title'] ?? '') ?: $data['url']; if ($simplehtml != 4) { - $return = sprintf('
', $data["type"]); + $return = sprintf('
', $data['type']); } if (!empty($data['title']) && !empty($data['url'])) { - if (!empty($data["image"]) && empty($data["text"]) && ($data["type"] == "photo")) { - $return .= sprintf('', $data["url"], self::proxyUrl($data["image"], $simplehtml), $data["title"]); + if (!empty($data['image']) && empty($data['text']) && ($data['type'] == 'photo')) { + $return .= sprintf('', $data['url'], self::proxyUrl($data['image'], $simplehtml), $data['title']); } else { - if (!empty($data["image"])) { - $return .= sprintf('
', $data["url"], self::proxyUrl($data["image"], $simplehtml), $data["title"]); - } elseif (!empty($data["preview"])) { - $return .= sprintf('
', $data["url"], self::proxyUrl($data["preview"], $simplehtml), $data["title"]); + if (!empty($data['image'])) { + $return .= sprintf('
', $data['url'], self::proxyUrl($data['image'], $simplehtml), $data['title']); + } elseif (!empty($data['preview'])) { + $return .= sprintf('
', $data['url'], self::proxyUrl($data['preview'], $simplehtml), $data['title']); } $return .= sprintf('

%s

', $data['url'], $data['title']); } } - if (!empty($data["description"]) && $data["description"] != $data["title"]) { + if (!empty($data['description']) && $data['description'] != $data['title']) { // Sanitize the HTML by converting it to BBCode - $bbcode = HTML::toBBCode($data["description"]); + $bbcode = HTML::toBBCode($data['description']); $return .= sprintf('
%s
', trim(self::convert($bbcode))); } @@ -645,7 +646,7 @@ class BBCode extends BaseObject } } - return trim(defaults($data, 'text', '') . ' ' . $return . ' ' . defaults($data, 'after', '')); + return trim(($data['text'] ?? '') . ' ' . $return . ' ' . ($data['after'] ?? '')); } public static function removeShareInformation($Text, $plaintext = false, $nolink = false) @@ -655,36 +656,36 @@ class BBCode extends BaseObject if (!$data) { return $Text; } elseif ($nolink) { - return $data["text"] . defaults($data, 'after', ''); + return $data['text'] . ($data['after'] ?? ''); } - $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"]; - } elseif (($text != "") && strstr($title, $text)) { - $data["text"] = $data["title"]; - $data["title"] = $data["url"]; + $title = htmlentities($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']; + } elseif (($text != '') && strstr($title, $text)) { + $data['text'] = $data['title']; + $data['title'] = $data['url']; } - if (empty($data["text"]) && !empty($data["title"]) && empty($data["url"])) { - return $data["title"] . $data["after"]; + if (empty($data['text']) && !empty($data['title']) && empty($data['url'])) { + 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"])) { - return $data["text"] . $data["after"]; + if (!empty($data['url']) && strpos($data['text'], $data['url'])) { + return $data['text'] . $data['after']; } - $text = $data["text"]; + $text = $data['text']; - if (!empty($data["url"]) && !empty($data["title"])) { - $text .= "\n[url=" . $data["url"] . "]" . $data["title"] . "[/url]"; - } elseif (!empty($data["url"])) { - $text .= "\n[url]" . $data["url"] . "[/url]"; + if (!empty($data['url']) && !empty($data['title'])) { + $text .= "\n[url=" . $data['url'] . ']' . $data['title'] . '[/url]'; + } elseif (!empty($data['url'])) { + $text .= "\n[url]" . $data['url'] . '[/url]'; } - return $text . "\n" . $data["after"]; + return $text . "\n" . $data['after']; } /** @@ -694,7 +695,7 @@ class BBCode extends BaseObject * @param array $match Array with the matching values * @return string reformatted link including HTML codes */ - private static function convertUrlForOStatusCallback($match) + private static function convertUrlForActivityPubCallback($match) { $url = $match[1]; @@ -707,15 +708,26 @@ class BBCode extends BaseObject return $match[0]; } - return self::convertUrlForOStatus($url); + return self::convertUrlForActivityPub($url); } /** - * @brief Converts [url] BBCodes in a format that looks fine on OStatus systems. + * @brief Converts [url] BBCodes in a format that looks fine on ActivityPub systems. * @param string $url URL that is about to be reformatted * @return string reformatted link including HTML codes */ - private static function convertUrlForOStatus($url) + private static function convertUrlForActivityPub($url) + { + $html = '%s'; + return sprintf($html, $url, self::getStyledURL($url)); + } + + /** + * Converts an URL in a nicer format (without the scheme and possibly shortened) + * @param string $url URL that is about to be reformatted + * @return string reformatted link + */ + private static function getStyledURL($url) { $parts = parse_url($url); $scheme = $parts['scheme'] . '://'; @@ -725,9 +737,7 @@ class BBCode extends BaseObject $styled_url = substr($styled_url, 0, 30) . "…"; } - $html = '%s'; - - return sprintf($html, $url, $styled_url); + return $styled_url; } /* @@ -932,7 +942,7 @@ class BBCode extends BaseObject $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'); + $attributes[$field] = html_entity_decode($matches[2] ?? '', ENT_QUOTES, 'UTF-8'); } // We only call this so that a previously unknown contact can be added. @@ -951,11 +961,11 @@ class BBCode extends BaseObject Contact::getIdForURL($attributes['profile'], 0, true, $default); $author_contact = Contact::getDetailsByURL($attributes['profile']); - $author_contact['addr'] = defaults($author_contact, 'addr' , Protocol::getAddrFromProfileUrl($attributes['profile'])); + $author_contact['addr'] = ($author_contact['addr'] ?? '') ?: Protocol::getAddrFromProfileUrl($attributes['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']); + $attributes['author'] = ($author_contact['name'] ?? '') ?: $attributes['author']; + $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); @@ -1056,7 +1066,8 @@ class BBCode extends BaseObject private static function removePictureLinksCallback($match) { - $text = Cache::get($match[1]); + $cache_key = 'remove:' . $match[1]; + $text = Cache::get($cache_key); if (is_null($text)) { $a = self::getApp(); @@ -1072,10 +1083,10 @@ class BBCode extends BaseObject $a->getProfiler()->saveTimestamp($stamp1, "network", System::callstack()); - if (substr($curl_info["content_type"], 0, 6) == "image/") { - $text = "[url=" . $match[1] . "]" . $match[1] . "[/url]"; + if (substr($curl_info['content_type'], 0, 6) == 'image/') { + $text = "[url=" . $match[1] . ']' . $match[1] . "[/url]"; } else { - $text = "[url=" . $match[2] . "]" . $match[2] . "[/url]"; + $text = "[url=" . $match[2] . ']' . $match[2] . "[/url]"; // if its not a picture then look if its a page that contains a picture link $body = Network::fetchUrl($match[1]); @@ -1093,12 +1104,12 @@ class BBCode extends BaseObject } } - if (strtolower($attr["name"]) == "twitter:image") { - $text = "[url=" . $attr["content"] . "]" . $attr["content"] . "[/url]"; + if (strtolower($attr['name']) == 'twitter:image') { + $text = '[url=' . $attr['content'] . ']' . $attr['content'] . '[/url]'; } } } - Cache::set($match[1], $text); + Cache::set($cache_key, $text); } return $text; @@ -1106,7 +1117,7 @@ class BBCode extends BaseObject private static function expandLinksCallback($match) { - if (($match[3] == "") || ($match[2] == $match[3]) || stristr($match[2], $match[3])) { + if (($match[3] == '') || ($match[2] == $match[3]) || stristr($match[2], $match[3])) { return ($match[1] . "[url]" . $match[2] . "[/url]"); } else { return ($match[1] . $match[3] . " [url]" . $match[2] . "[/url]"); @@ -1115,58 +1126,72 @@ class BBCode extends BaseObject private static function cleanPictureLinksCallback($match) { - $text = Cache::get($match[1]); + $a = self::getApp(); - if (is_null($text)) { - $a = self::getApp(); + // When the picture link is the own photo path then we can avoid fetching the link + $own_photo_url = preg_quote(Strings::normaliseLink($a->getBaseURL()) . '/photos/'); + if (preg_match('|' . $own_photo_url . '.*?/image/|', Strings::normaliseLink($match[1]))) { + if (!empty($match[3])) { + $text = '[img=' . str_replace('-1.', '-0.', $match[2]) . ']' . $match[3] . '[/img]'; + } else { + $text = '[img]' . str_replace('-1.', '-0.', $match[2]) . '[/img]'; + } + return $text; + } - $stamp1 = microtime(true); + $cache_key = 'clean:' . $match[1]; + $text = Cache::get($cache_key); + if (!is_null($text)) { + return $text; + } - $ch = @curl_init($match[1]); - @curl_setopt($ch, CURLOPT_NOBODY, true); - @curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - @curl_setopt($ch, CURLOPT_USERAGENT, $a->getUserAgent()); - @curl_exec($ch); - $curl_info = @curl_getinfo($ch); + // Only fetch the header, not the content + $stamp1 = microtime(true); - $a->getProfiler()->saveTimestamp($stamp1, "network", System::callstack()); + $ch = @curl_init($match[1]); + @curl_setopt($ch, CURLOPT_NOBODY, true); + @curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + @curl_setopt($ch, CURLOPT_USERAGENT, $a->getUserAgent()); + @curl_exec($ch); + $curl_info = @curl_getinfo($ch); + + $a->getProfiler()->saveTimestamp($stamp1, "network", System::callstack()); - // if its a link to a picture then embed this picture - if (substr($curl_info["content_type"], 0, 6) == "image/") { - $text = "[img]" . $match[1] . "[/img]"; + // if its a link to a picture then embed this picture + if (substr($curl_info['content_type'], 0, 6) == 'image/') { + $text = '[img]' . $match[1] . '[/img]'; + } else { + if (!empty($match[3])) { + $text = '[img=' . $match[2] . ']' . $match[3] . '[/img]'; } else { - if (!empty($match[3])) { - $text = "[img=" . $match[2] . "]" . $match[3] . "[/img]"; - } else { - $text = "[img]" . $match[2] . "[/img]"; - } + $text = '[img]' . $match[2] . '[/img]'; + } - // if its not a picture then look if its a page that contains a picture link - $body = Network::fetchUrl($match[1]); + // if its not a picture then look if its a page that contains a picture link + $body = Network::fetchUrl($match[1]); - $doc = new DOMDocument(); - @$doc->loadHTML($body); - $xpath = new DOMXPath($doc); - $list = $xpath->query("//meta[@name]"); - foreach ($list as $node) { - $attr = []; - if ($node->attributes->length) { - foreach ($node->attributes as $attribute) { - $attr[$attribute->name] = $attribute->value; - } + $doc = new DOMDocument(); + @$doc->loadHTML($body); + $xpath = new DOMXPath($doc); + $list = $xpath->query("//meta[@name]"); + foreach ($list as $node) { + $attr = []; + if ($node->attributes->length) { + foreach ($node->attributes as $attribute) { + $attr[$attribute->name] = $attribute->value; } + } - if (strtolower($attr["name"]) == "twitter:image") { - if (!empty($match[3])) { - $text = "[img=" . $attr["content"] . "]" . $match[3] . "[/img]"; - } else { - $text = "[img]" . $attr["content"] . "[/img]"; - } + if (strtolower($attr['name']) == "twitter:image") { + if (!empty($match[3])) { + $text = "[img=" . $attr['content'] . "]" . $match[3] . "[/img]"; + } else { + $text = "[img]" . $attr['content'] . "[/img]"; } } } - Cache::set($match[1], $text); } + Cache::set($cache_key, $text); return $text; } @@ -1217,7 +1242,7 @@ class BBCode extends BaseObject $try_oembed_callback = function ($match) { $url = $match[1]; - $title = defaults($match, 2, null); + $title = $match[2] ?? null; try { $return = OEmbed::getHTML($url, $title); @@ -1318,7 +1343,7 @@ class BBCode extends BaseObject $text = str_replace($search, $replace, $text); // removing multiplicated newlines - if (Config::get("system", "remove_multiplicated_lines")) { + if (Config::get('system', 'remove_multiplicated_lines')) { $search = ["\n\n\n", "\n ", " \n", "[/quote]\n\n", "\n[/quote]", "[/li]\n", "\n[li]", "\n[ul]", "[/ul]\n", "\n\n[share ", "[/attachment]\n", "\n[h1]", "[/h1]\n", "\n[h2]", "[/h2]\n", "\n[h3]", "[/h3]\n", "\n[h4]", "[/h4]\n", "\n[h5]", "[/h5]\n", "\n[h6]", "[/h6]\n"]; $replace = ["\n\n", "\n", "\n", "[/quote]\n", "[/quote]", "[/li]", "[li]", "[ul]", "[/ul]", "\n[share ", "[/attachment]", @@ -1389,8 +1414,14 @@ class BBCode extends BaseObject // Check for sized text // [size=50] --> font-size: 50px (with the unit). - $text = preg_replace("(\[size=(\d*?)\](.*?)\[\/size\])ism", "$2", $text); - $text = preg_replace("(\[size=(.*?)\](.*?)\[\/size\])ism", "$2", $text); + if ($simple_html != 3) { + $text = preg_replace("(\[size=(\d*?)\](.*?)\[\/size\])ism", "$2", $text); + $text = preg_replace("(\[size=(.*?)\](.*?)\[\/size\])ism", "$2", $text); + } else { + // Issue 2199: Diaspora doesn't interpret the construct above, nor the or element + $text = preg_replace("(\[size=(.*?)\](.*?)\[\/size\])ism", "$2", $text); + } + // Check for centered text $text = preg_replace("(\[center\](.*?)\[\/center\])ism", "
$1
", $text); @@ -1445,6 +1476,11 @@ class BBCode extends BaseObject $text = str_replace('[hr]', '
', $text); + if (!$for_plaintext) { + // Autolinker for isolated URLs + $text = preg_replace(Strings::autoLinkRegEx(), '[url]$1[/url]', $text); + } + // This is actually executed in Item::prepareBody() $nosmile = strpos($text, '[nosmile]') !== false; @@ -1454,24 +1490,22 @@ class BBCode extends BaseObject $text = preg_replace("/\[font=(.*?)\](.*?)\[\/font\]/sm", "$2", $text); // Declare the format for [spoiler] layout - $SpoilerLayout = '
$1
'; + $SpoilerLayout = '
' . L10n::t('Click to open/close') . '$1
'; // Check for [spoiler] text // handle nested quotes $endlessloop = 0; while ((strpos($text, "[/spoiler]") !== false) && (strpos($text, "[spoiler]") !== false) && (++$endlessloop < 20)) { - $text = preg_replace("/\[spoiler\](.*?)\[\/spoiler\]/ism", "$SpoilerLayout", $text); + $text = preg_replace("/\[spoiler\](.*?)\[\/spoiler\]/ism", $SpoilerLayout, $text); } - // Check for [spoiler=Author] text - - $t_wrote = L10n::t('$1 wrote:'); + // Check for [spoiler=Title] text // handle nested quotes $endlessloop = 0; while ((strpos($text, "[/spoiler]")!== false) && (strpos($text, "[spoiler=") !== false) && (++$endlessloop < 20)) { $text = preg_replace("/\[spoiler=[\"\']*(.*?)[\"\']*\](.*?)\[\/spoiler\]/ism", - "
" . $t_wrote . "
$2
", + '
$1$2
', $text); } @@ -1629,12 +1663,10 @@ class BBCode extends BaseObject $text = Smilies::replace($text); } - // if the HTML is used to generate plain text, then don't do this search, but replace all URL of that kind to text if (!$for_plaintext) { - $text = preg_replace(Strings::autoLinkRegEx(), '[url]$1[/url]', $text); if (in_array($simple_html, [7, 9])) { - $text = preg_replace_callback("/\[url\](.*?)\[\/url\]/ism", 'self::convertUrlForOStatusCallback', $text); - $text = preg_replace_callback("/\[url\=(.*?)\](.*?)\[\/url\]/ism", 'self::convertUrlForOStatusCallback', $text); + $text = preg_replace_callback("/\[url\](.*?)\[\/url\]/ism", 'self::convertUrlForActivityPubCallback', $text); + $text = preg_replace_callback("/\[url\=(.*?)\](.*?)\[\/url\]/ism", 'self::convertUrlForActivityPubCallback', $text); } } else { $text = preg_replace("(\[url\](.*?)\[\/url\])ism", " $1 ", $text); @@ -1810,7 +1842,7 @@ class BBCode extends BaseObject // Clean up the HTML by loading and saving the HTML with the DOM. // Bad structured html can break a whole page. // For performance reasons do it only with activated item cache or at export. - if (!$try_oembed || (get_itemcachepath() != "")) { + if (!$try_oembed || (get_itemcachepath() != '')) { $doc = new DOMDocument(); $doc->preserveWhiteSpace = false; @@ -1818,10 +1850,10 @@ class BBCode extends BaseObject $doctype = ''; $encoding = ''; - @$doc->loadHTML($encoding.$doctype."".$text.""); + @$doc->loadHTML($encoding . $doctype . '' . $text . ''); $doc->encoding = 'UTF-8'; $text = $doc->saveHTML(); - $text = str_replace(["", "", $doctype, $encoding], ["", "", "", ""], $text); + $text = str_replace(['', '', $doctype, $encoding], ['', '', '', ''], $text); $text = str_replace('
', '', $text); @@ -1861,9 +1893,9 @@ class BBCode extends BaseObject * @param string $addon The addon for which the abstract is meant for * @return string The abstract */ - public static function getAbstract($text, $addon = "") + public static function getAbstract($text, $addon = '') { - $abstract = ""; + $abstract = ''; $abstracts = []; $addon = strtolower($addon); @@ -1877,7 +1909,7 @@ class BBCode extends BaseObject $abstract = $abstracts[$addon]; } - if ($abstract == "" && preg_match("/\[abstract\](.*?)\[\/abstract\]/ism", $text, $result)) { + if ($abstract == '' && preg_match("/\[abstract\](.*?)\[\/abstract\]/ism", $text, $result)) { $abstract = $result[1]; } @@ -1953,7 +1985,7 @@ class BBCode extends BaseObject // Add all tags that maybe were removed if (preg_match_all("/#\[url\=([$url_search_string]*)\](.*?)\[\/url\]/ism", $original_text, $tags)) { - $tagline = ""; + $tagline = ''; foreach ($tags[2] as $tag) { $tag = html_entity_decode($tag, ENT_QUOTES, 'UTF-8'); if (!strpos(html_entity_decode($text, ENT_QUOTES, 'UTF-8'), '#' . $tag)) { @@ -1971,7 +2003,7 @@ class BBCode extends BaseObject // If a link is followed by a quote then there should be a newline before it // Maybe we should make this newline at every time before a quote. - $text = str_replace(["
"], ["
"], $text); + $text = str_replace(['
'], ['
'], $text); $stamp1 = microtime(true);