X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FContent%2FText%2FBBCode.php;h=a8b5ec2025546e7ffa0e694597d2f38524ccd8b1;hb=5e2cbce9b6efce2baaed69b6aad1537a51bdae9d;hp=35f4979d11fe7ae943310e0d73b15488356ec857;hpb=c598bf7d8f5075526fadcfd329f6dd448533dfad;p=friendica.git diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index 35f4979d11..a8b5ec2025 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -1,5 +1,4 @@ Message type ("link", "video", "photo") - * 'text' -> Text before the shared message - * 'after' -> Text after the shared message - * 'image' -> Preview image of the message - * 'url' -> Url to the attached message - * 'title' -> Title of the attachment - * 'description' -> Description of the attachment + * 'type' -> Message type ("link", "video", "photo") + * 'text' -> Text before the shared message + * 'after' -> Text after the shared message + * 'image' -> Preview image of the message + * 'url' -> Url to the attached message + * 'title' -> Title of the attachment + * 'description' -> Description of the attachment + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ private static function getOldAttachmentData($body) { @@ -89,7 +90,7 @@ class BBCode extends BaseObject $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]; } @@ -108,13 +109,14 @@ class BBCode extends BaseObject * * @param string $body Message body * @return array - * 'type' -> Message type ("link", "video", "photo") - * 'text' -> Text before the shared message - * 'after' -> Text after the shared message - * 'image' -> Preview image of the message - * 'url' -> Url to the attached message - * 'title' -> Title of the attachment - * 'description' -> Description of the attachment + * 'type' -> Message type ("link", "video", "photo") + * 'text' -> Text before the shared message + * 'after' -> Text after the shared message + * 'image' -> Preview image of the message + * 'url' -> Url to the attached message + * 'title' -> Title of the attachment + * 'description' -> Description of the attachment + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ public static function getAttachmentData($body) { @@ -130,12 +132,12 @@ class BBCode extends BaseObject $type = ""; preg_match("/type='(.*?)'/ism", $attributes, $matches); - if (x($matches, 1)) { + if (!empty($matches[1])) { $type = strtolower($matches[1]); } preg_match('/type="(.*?)"/ism', $attributes, $matches); - if (x($matches, 1)) { + if (!empty($matches[1])) { $type = strtolower($matches[1]); } @@ -153,12 +155,12 @@ class BBCode extends BaseObject $url = ""; preg_match("/url='(.*?)'/ism", $attributes, $matches); - if (x($matches, 1)) { + if (!empty($matches[1])) { $url = $matches[1]; } preg_match('/url="(.*?)"/ism', $attributes, $matches); - if (x($matches, 1)) { + if (!empty($matches[1])) { $url = $matches[1]; } @@ -168,12 +170,12 @@ class BBCode extends BaseObject $title = ""; preg_match("/title='(.*?)'/ism", $attributes, $matches); - if (x($matches, 1)) { + if (!empty($matches[1])) { $title = $matches[1]; } preg_match('/title="(.*?)"/ism', $attributes, $matches); - if (x($matches, 1)) { + if (!empty($matches[1])) { $title = $matches[1]; } @@ -186,12 +188,12 @@ class BBCode extends BaseObject $image = ""; preg_match("/image='(.*?)'/ism", $attributes, $matches); - if (x($matches, 1)) { + if (!empty($matches[1])) { $image = $matches[1]; } preg_match('/image="(.*?)"/ism', $attributes, $matches); - if (x($matches, 1)) { + if (!empty($matches[1])) { $image = $matches[1]; } @@ -201,12 +203,12 @@ class BBCode extends BaseObject $preview = ""; preg_match("/preview='(.*?)'/ism", $attributes, $matches); - if (x($matches, 1)) { + if (!empty($matches[1])) { $preview = $matches[1]; } preg_match('/preview="(.*?)"/ism', $attributes, $matches); - if (x($matches, 1)) { + if (!empty($matches[1])) { $preview = $matches[1]; } @@ -234,7 +236,7 @@ class BBCode extends BaseObject */ $has_title = !empty($item['title']); - $plink = (!empty($item['plink']) ? $item['plink'] : ''); + $plink = defaults($item, 'plink', ''); $post = self::getAttachmentData($body); // if nothing is found, it maybe having an image. @@ -345,13 +347,14 @@ class BBCode extends BaseObject /** * @brief Converts a BBCode text into plaintext * + * @param $text * @param bool $keep_urls Whether to keep URLs in the resulting plaintext * * @return string */ public static function toPlaintext($text, $keep_urls = true) { - $naked_text = preg_replace('/\[(.+?)\]/','', $text); + $naked_text = preg_replace('/\[(.+?)\]\s*/','', $text); if (!$keep_urls) { $naked_text = preg_replace('#https?\://[^\s<]+[^\s\.\)]#i', '', $naked_text); } @@ -363,7 +366,7 @@ class BBCode extends BaseObject { // Only send proxied pictures to API and for internal display if (in_array($simplehtml, [false, 2])) { - return proxy_url($image); + return ProxyUtils::proxifyUrl($image); } else { return $image; } @@ -383,7 +386,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)) { @@ -418,7 +421,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]' @@ -427,7 +430,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); } } } @@ -446,16 +449,17 @@ class BBCode extends BaseObject * @brief Truncates imported message body string length to max_import_size * @param string $body * @return string + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ 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 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 = ''; @@ -475,7 +479,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; } @@ -489,7 +493,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; } @@ -512,11 +516,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; } @@ -532,24 +536,27 @@ class BBCode extends BaseObject * Note: Can produce a [bookmark] tag in the returned string * * @brief Processes [attachment] tags - * @param string $return + * @param string $return * @param bool|int $simplehtml - * @param bool $tryoembed + * @param bool $tryoembed * @return string + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ 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"] = ""; } @@ -567,28 +574,32 @@ class BBCode extends BaseObject 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)); } @@ -598,7 +609,7 @@ class BBCode extends BaseObject } } - 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) @@ -608,10 +619,10 @@ class BBCode extends BaseObject 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"]; @@ -620,20 +631,20 @@ class BBCode extends BaseObject $data["title"] = $data["url"]; } - if (($data["text"] == "") && ($data["title"] != "") && ($data["url"] == "")) { + 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 (($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]"; } @@ -771,10 +782,10 @@ class BBCode extends BaseObject /** * Performs a preg_replace within the boundaries of all named BBCode tags in a text * - * @param type $pattern Preg pattern string - * @param type $replace Preg replace string - * @param type $name BBCode tag name - * @param type $text Text to search + * @param string $pattern Preg pattern string + * @param string $replace Preg replace string + * @param string $name BBCode tag name + * @param string $text Text to search * @return string */ public static function pregReplaceInTag($pattern, $replace, $name, $text) @@ -857,190 +868,141 @@ 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 .= "
' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' ' . $mention . ':
' . "\n" . '«' . $content . '»'; break; case 2: - $text = $preshare . html_entity_decode("♲ ", ENT_QUOTES, 'UTF-8') . ' ' . $userid_compact . ":' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ':
' . "\n" . $content; break; case 3: // Diaspora - $headline = '' . html_entity_decode("♲ ", ENT_QUOTES, 'UTF-8') . $userid . ':' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . $mention . ':
' . "\n"; - if (stripos(normalise_link($link), 'http://twitter.com/') === 0) { - $text .= '' . trim($share[3]) . "
' . trim($content) . '' . "\n"; - if ($link != "") { - $text .= '
' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8'); + $headline .= L10n::t('%2$s %3$s', $attributes['link'], $mention, $attributes['posted']); + $headline .= ':
' . "\n"; - $text = trim($share[1]); - - if ($text != "") { - $text .= "' . trim($share[3]) . "
' . trim($content) . '' . "\n"; break; case 5: - $text = $preshare . html_entity_decode("♲ ", ENT_QUOTES, 'UTF-8') . ' ' . $userid_compact . ":
' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ':
' . "\n" . $content; break; case 7: // statusnet/GNU Social - $text = $preshare . html_entity_decode("♲ ", ENT_QUOTES, 'UTF-8') . " @" . $userid_compact . ": " . $share[3]; + $text = ($is_quote_share? '' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' @' . $author_contact['addr'] . ': ' . $content . '
' . "\n"; break; - case 8: // twitter - $text = $preshare . "RT @" . $userid_compact . ": " . $share[3]; - break; - case 9: // Google+/Facebook - $text = $preshare . html_entity_decode("♲ ", ENT_QUOTES, 'UTF-8') . ' ' . $userid_compact . ":' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ':
' . "\n"; + $text .= '' . $content . '
' . "\n"; - if ($link != "") { - $text .= "' . $attributes['link'] . '
'; } 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(Strings::normaliseLink($attributes['link']), 'http://twitter.com/') === 0 && OEmbed::isAllowedURL($attributes['link'])) { try { - $oembed = OEmbed::getHTML($link, $preshare); + $text = ($is_quote_share? '' . 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?
@@ -1265,19 +1229,11 @@ 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);
}
- // 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 ([^<]*)
(?! for Diaspora inline code blocks
- if ($simple_html === 3) {
- $return = '' . $match[1] . '
';
- }
- return $return;
- }
- , $text);
-
// Unhide all [noparse] contained bbtags unspacefying them
// and triming the [noparse] tag.
@@ -1764,9 +1729,21 @@ class BBCode extends BaseObject
$text = self::interpolateSavedImagesIntoItemBody($text, $saved_image);
}
+ // Restore code blocks
+ $text = preg_replace_callback('/#codeblock-([0-9]+)#/iU',
+ function ($matches) use ($codeblocks) {
+ $return = $matches[0];
+ if (isset($codeblocks[intval($matches[1])])) {
+ $return = $codeblocks[$matches[1]];
+ }
+ return $return;
+ },
+ $text
+ );
+
// 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 ativated item cache or at export.
+ // For performance reasons do it only with activated item cache or at export.
if (!$try_oembed || (get_itemcachepath() != "")) {
$doc = new DOMDocument();
$doc->preserveWhiteSpace = false;
@@ -1792,7 +1769,7 @@ class BBCode extends BaseObject
//$Text = str_replace('
', ' ', $Text);
//$Text = str_replace('
convert($text);
+ $text = HTML::toMarkdown($text);
// unmask the special chars back to HTML
$text = str_replace(['&\_lt\_;', '&\_gt\_;', '&\_amp\_;'], ['<', '>', '&'], $text);
- $a->save_timestamp($stamp1, "parser");
+ $a->saveTimestamp($stamp1, "parser");
// Libertree has a problem with escaped hashtags.
$text = str_replace(['\#'], ['#'], $text);
@@ -1962,26 +1927,88 @@ class BBCode extends BaseObject
if ($for_diaspora) {
$url_search_string = "^\[\]";
$text = preg_replace_callback(
- "/([@]\[(.*?)\])\(([$url_search_string]*?)\)/ism",
+ "/([@!])\[(.*?)\]\(([$url_search_string]*?)\)/ism",
['self', 'bbCodeMention2DiasporaCallback'],
$text
);
}
- // Restore code blocks
- $text = preg_replace_callback('/#codeblock-([0-9]+)#/iU',
- function ($matches) use ($codeblocks) {
- $return = '';
- if (isset($codeblocks[intval($matches[1])])) {
- $return = $codeblocks[$matches[1]];
- }
- return $return;
- },
- $text
- );
-
- Addon::callHooks('bb2diaspora', $text);
+ Hook::callAll('bb2diaspora', $text);
return $text;
}
+
+ /**
+ * @brief Pull out all #hashtags and @person tags from $string.
+ *
+ * We also get @person@domain.com - which would make
+ * the regex quite complicated as tags can also
+ * end a sentence. So we'll run through our results
+ * and strip the period from any tags which end with one.
+ * Returns array of tags found, or empty array.
+ *
+ * @param string $string Post content
+ *
+ * @return array List of tag and person names
+ */
+ public static function getTags($string)
+ {
+ $ret = [];
+
+ // Convert hashtag links to hashtags
+ $string = preg_replace('/#\[url\=([^\[\]]*)\](.*?)\[\/url\]/ism', '#$2', $string);
+
+ // ignore anything in a code block
+ $string = preg_replace('/\[code.*?\].*?\[\/code\]/sm', '', $string);
+
+ // Force line feeds at bbtags
+ $string = str_replace(['[', ']'], ["\n[", "]\n"], $string);
+
+ // ignore anything in a bbtag
+ $string = preg_replace('/\[(.*?)\]/sm', '', $string);
+
+ // Match full names against @tags including the space between first and last
+ // We will look these up afterward to see if they are full names or not recognisable.
+
+ if (preg_match_all('/(@[^ \x0D\x0A,:?]+ [^ \x0D\x0A@,:?]+)([ \x0D\x0A@,:?]|$)/', $string, $matches)) {
+ foreach ($matches[1] as $match) {
+ if (strstr($match, ']')) {
+ // we might be inside a bbcode color tag - leave it alone
+ continue;
+ }
+
+ if (substr($match, -1, 1) === '.') {
+ $ret[] = substr($match, 0, -1);
+ } else {
+ $ret[] = $match;
+ }
+ }
+ }
+
+ // Otherwise pull out single word tags. These can be @nickname, @first_last
+ // and #hash tags.
+
+ if (preg_match_all('/([!#@][^\^ \x0D\x0A,;:?]+)([ \x0D\x0A,;:?]|$)/', $string, $matches)) {
+ foreach ($matches[1] as $match) {
+ if (strstr($match, ']')) {
+ // we might be inside a bbcode color tag - leave it alone
+ continue;
+ }
+ if (substr($match, -1, 1) === '.') {
+ $match = substr($match,0,-1);
+ }
+ // ignore strictly numeric tags like #1
+ if ((strpos($match, '#') === 0) && ctype_digit(substr($match, 1))) {
+ continue;
+ }
+ // try not to catch url fragments
+ if (strpos($string, $match) && preg_match('/[a-zA-z0-9\/]/', substr($string, strpos($string, $match) - 1, 1))) {
+ continue;
+ }
+ $ret[] = $match;
+ }
+ }
+
+ return $ret;
+ }
}