use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\Core\Protocol;
+use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Model\Contact;
use Friendica\Model\Event;
use Friendica\Util\Network;
use Friendica\Util\ParseUrl;
use Friendica\Util\Proxy as ProxyUtils;
+use Friendica\Util\Strings;
+use Friendica\Util\XML;
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]);
}
$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];
}
$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];
}
$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];
}
$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];
}
*/
$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.
case 3: // Diaspora
$headline = '<p><b>' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . $mention . ':</b></p>' . "\n";
- if (stripos(normalise_link($attributes['link']), 'http://twitter.com/') === 0) {
+ if (stripos(Strings::normaliseLink($attributes['link']), 'http://twitter.com/') === 0) {
$text = ($is_quote_share? '<hr />' : '') . '<p><a href="' . $attributes['link'] . '">' . $attributes['link'] . '</a></p>' . "\n";
} else {
$text = ($is_quote_share? '<hr />' : '') . $headline . '<blockquote>' . trim($content) . '</blockquote>' . "\n";
break;
default:
// Transforms quoted tweets in rich attachments to avoid nested tweets
- if (stripos(normalise_link($attributes['link']), 'http://twitter.com/') === 0 && OEmbed::isAllowedURL($attributes['link'])) {
+ if (stripos(Strings::normaliseLink($attributes['link']), 'http://twitter.com/') === 0 && OEmbed::isAllowedURL($attributes['link'])) {
try {
$text = ($is_quote_share? '<br />' : '') . OEmbed::getHTML($attributes['link']);
} catch (Exception $e) {
} else {
$text = ($is_quote_share? "\n" : '');
- $tpl = get_markup_template('shared_content.tpl');
- $text .= replace_macros($tpl, [
+ $tpl = Renderer::getMarkupTemplate('shared_content.tpl');
+ $text .= Renderer::replaceMacros($tpl, [
'$profile' => $attributes['profile'],
'$avatar' => $attributes['avatar'],
'$author' => $attributes['author'],
$expression = "=diaspora://.*?/post/([0-9A-Za-z\-_@.:]{15,254}[0-9A-Za-z])=ism";
$text = preg_replace($expression, System::baseUrl()."/display/$1", $text);
- $text = preg_replace("/([#])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",
- '$1<a href="' . System::baseUrl() . '/search?tag=$3" class="tag" title="$3">$3</a>', $text);
-
- $text = preg_replace("/\[url\=([$URLSearchString]*)\]#(.*?)\[\/url\]/ism",
- '#<a href="' . System::baseUrl() . '/search?tag=$2" class="tag" title="$2">$2</a>', $text);
+ /* Tag conversion
+ * Supports:
+ * - #[url=<anything>]<term>[/url]
+ * - [url=<anything>]#<term>[/url]
+ */
+ $text = preg_replace_callback("/(?:#\[url\=[$URLSearchString]*\]|\[url\=[$URLSearchString]*\]#)(.*?)\[\/url\]/ism", function($matches) {
+ return '#<a href="'
+ . System::baseUrl() . '/search?tag=' . rawurlencode($matches[1])
+ . '" class="tag" title="' . XML::escape($matches[1]) . '">'
+ . XML::escape($matches[1])
+ . '</a>';
+ }, $text);
$text = preg_replace("/\[url\]([$URLSearchString]*)\[\/url\]/ism", '<a href="$1" target="_blank">$1</a>', $text);
$text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '<a href="$1" target="_blank">$2</a>', $text);
- //$Text = preg_replace("/\[url\=([$URLSearchString]*)\]([$URLSearchString]*)\[\/url\]/ism", '<a href="$1" target="_blank">$2</a>', $Text);
// Red compatibility, though the link can't be authenticated on Friendica
$text = preg_replace("/\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '<a href="$1" target="_blank">$2</a>', $text);
$text = preg_replace("/\[mail\=([$MAILSearchString]*)\](.*?)\[\/mail\]/", '<a href="mailto:$1">$2</a>', $text);
// leave open the posibility of [map=something]
- // this is replaced in prepare_body() which has knowledge of the item location
+ // this is replaced in Item::prepareBody() which has knowledge of the item location
if (strpos($text, '[/map]') !== false) {
$text = preg_replace_callback(
$text = str_replace('[hr]', '<hr />', $text);
- // This is actually executed in prepare_body()
+ // This is actually executed in Item::prepareBody()
$text = str_replace('[nosmile]', '', $text);
// Summary (e.g. title) is required, earlier revisions only required description (in addition to
// start which is always required). Allow desc with a missing summary for compatibility.
- if ((x($ev, 'desc') || x($ev, 'summary')) && x($ev, 'start')) {
+ if ((!empty($ev['desc']) || !empty($ev['summary'])) && !empty($ev['start'])) {
$sub = Event::getHTML($ev, $simple_html);
$text = preg_replace("/\[event\-summary\](.*?)\[\/event\-summary\]/ism", '', $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;
+ }
}