X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FModel%2FItem.php;h=30c29e1518b18cea736de93613f6a9c9657abd3a;hb=67f4fdab322f6e717ad99ed324878552579fd24f;hp=8e0a397e24564bf819aba22992a5bb7a7d8eca41;hpb=c6ce9ddaa41a59496cbe5cd93ace9bc552478ccd;p=friendica.git diff --git a/src/Model/Item.php b/src/Model/Item.php index 8e0a397e24..30c29e1518 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -8,25 +8,32 @@ namespace Friendica\Model; use Friendica\BaseObject; use Friendica\Content\Text\BBCode; +use Friendica\Content\Text\HTML; use Friendica\Core\Addon; use Friendica\Core\Config; use Friendica\Core\Lock; use Friendica\Core\Logger; +use Friendica\Core\L10n; use Friendica\Core\PConfig; use Friendica\Core\Protocol; +use Friendica\Core\Renderer; use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\Model\Contact; +use Friendica\Model\Event; use Friendica\Model\FileTag; use Friendica\Model\PermissionSet; +use Friendica\Model\Term; use Friendica\Model\ItemURI; use Friendica\Object\Image; use Friendica\Protocol\Diaspora; use Friendica\Protocol\OStatus; use Friendica\Util\DateTimeFormat; +use Friendica\Util\Map; use Friendica\Util\XML; use Friendica\Util\Security; +use Friendica\Util\Strings; use Text_LanguageDetect; require_once 'boot.php'; @@ -1143,7 +1150,7 @@ class Item extends BaseObject private static function guid($item, $notify) { if (!empty($item['guid'])) { - return notags(trim($item['guid'])); + return Strings::escapeTags(trim($item['guid'])); } if ($notify) { @@ -1258,7 +1265,7 @@ class Item extends BaseObject } $item['guid'] = self::guid($item, $notify); - $item['uri'] = notags(trim(defaults($item, 'uri', self::newURI($item['uid'], $item['guid'])))); + $item['uri'] = Strings::escapeTags(trim(defaults($item, 'uri', self::newURI($item['uid'], $item['guid'])))); // Store URI data $item['uri-id'] = ItemURI::insert(['uri' => $item['uri'], 'guid' => $item['guid']]); @@ -1528,7 +1535,7 @@ class Item extends BaseObject Logger::log("Checking if parent ".$parent_id." has to be tagged as mention for user ".$item['uid'], Logger::DEBUG); $user = DBA::selectFirst('user', ['nickname'], ['uid' => $item['uid']]); if (DBA::isResult($user)) { - $self = normalise_link(System::baseUrl() . '/profile/' . $user['nickname']); + $self = Strings::normaliseLink(System::baseUrl() . '/profile/' . $user['nickname']); $self_id = Contact::getIdForURL($self, 0, true); Logger::log("'myself' is ".$self_id." for parent ".$parent_id." checking against ".$item['author-id']." and ".$item['owner-id'], Logger::DEBUG); if (($item['author-id'] == $self_id) || ($item['owner-id'] == $self_id)) { @@ -1607,7 +1614,7 @@ class Item extends BaseObject $item["deleted"] = $parent_deleted; // Fill the cache field - put_item_in_cache($item); + self::putInCache($item); if ($notify) { $item['edit'] = false; @@ -2396,7 +2403,7 @@ class Item extends BaseObject public static function setHashtags(&$item) { - $tags = get_tags($item["body"]); + $tags = BBCode::getTags($item["body"]); // No hashtags? if (!count($tags)) { @@ -2538,18 +2545,18 @@ class Item extends BaseObject return; } - $link = normalise_link(System::baseUrl() . '/profile/' . $user['nickname']); + $link = Strings::normaliseLink(System::baseUrl() . '/profile/' . $user['nickname']); /* * Diaspora uses their own hardwired link URL in @-tags * instead of the one we supply with webfinger */ - $dlink = normalise_link(System::baseUrl() . '/u/' . $user['nickname']); + $dlink = Strings::normaliseLink(System::baseUrl() . '/u/' . $user['nickname']); $cnt = preg_match_all('/[\@\!]\[url\=(.*?)\](.*?)\[\/url\]/ism', $item['body'], $matches, PREG_SET_ORDER); if ($cnt) { foreach ($matches as $mtch) { - if (link_compare($link, $mtch[1]) || link_compare($dlink, $mtch[1])) { + if (Strings::compareLink($link, $mtch[1]) || Strings::compareLink($dlink, $mtch[1])) { $mention = true; Logger::log('mention found: ' . $mtch[2]); } @@ -3247,4 +3254,295 @@ class Item extends BaseObject return $sql; } + + /** + * get translated item type + * + * @param array $itme + * @return string + */ + public static function postType($item) + { + if (!empty($item['event-id'])) { + return L10n::t('event'); + } elseif (!empty($item['resource-id'])) { + return L10n::t('photo'); + } elseif (!empty($item['verb']) && $item['verb'] !== ACTIVITY_POST) { + return L10n::t('activity'); + } elseif ($item['id'] != $item['parent']) { + return L10n::t('comment'); + } + + return L10n::t('post'); + } + + /** + * Sets the "rendered-html" field of the provided item + * + * Body is preserved to avoid side-effects as we modify it just-in-time for spoilers and private image links + * + * @param array $item + * @param bool $update + * + * @todo Remove reference, simply return "rendered-html" and "rendered-hash" + */ + public static function putInCache(&$item, $update = false) + { + $body = $item["body"]; + + $rendered_hash = defaults($item, 'rendered-hash', ''); + $rendered_html = defaults($item, 'rendered-html', ''); + + if ($rendered_hash == '' + || $rendered_html == "" + || $rendered_hash != hash("md5", $item["body"]) + || Config::get("system", "ignore_cache") + ) { + $a = self::getApp(); + redir_private_images($a, $item); + + $item["rendered-html"] = prepare_text($item["body"]); + $item["rendered-hash"] = hash("md5", $item["body"]); + + $hook_data = ['item' => $item, 'rendered-html' => $item['rendered-html'], 'rendered-hash' => $item['rendered-hash']]; + Addon::callHooks('put_item_in_cache', $hook_data); + $item['rendered-html'] = $hook_data['rendered-html']; + $item['rendered-hash'] = $hook_data['rendered-hash']; + unset($hook_data); + + // Force an update if the generated values differ from the existing ones + if ($rendered_hash != $item["rendered-hash"]) { + $update = true; + } + + // Only compare the HTML when we forcefully ignore the cache + if (Config::get("system", "ignore_cache") && ($rendered_html != $item["rendered-html"])) { + $update = true; + } + + if ($update && !empty($item["id"])) { + self::update( + [ + 'rendered-html' => $item["rendered-html"], + 'rendered-hash' => $item["rendered-hash"] + ], + ['id' => $item["id"]] + ); + } + } + + $item["body"] = $body; + } + + /** + * @brief Given an item array, convert the body element from bbcode to html and add smilie icons. + * If attach is true, also add icons for item attachments. + * + * @param array $item + * @param boolean $attach + * @param boolean $is_preview + * @return string item body html + * @hook prepare_body_init item array before any work + * @hook prepare_body_content_filter ('item'=>item array, 'filter_reasons'=>string array) before first bbcode to html + * @hook prepare_body ('item'=>item array, 'html'=>body string, 'is_preview'=>boolean, 'filter_reasons'=>string array) after first bbcode to html + * @hook prepare_body_final ('item'=>item array, 'html'=>body string) after attach icons and blockquote special case handling (spoiler, author) + */ + public static function prepareBody(array &$item, $attach = false, $is_preview = false) + { + $a = self::getApp(); + Addon::callHooks('prepare_body_init', $item); + + // In order to provide theme developers more possibilities, event items + // are treated differently. + if ($item['object-type'] === ACTIVITY_OBJ_EVENT && isset($item['event-id'])) { + $ev = Event::getItemHTML($item); + return $ev; + } + + $tags = Term::populateTagsFromItem($item); + + $item['tags'] = $tags['tags']; + $item['hashtags'] = $tags['hashtags']; + $item['mentions'] = $tags['mentions']; + + // Compile eventual content filter reasons + $filter_reasons = []; + if (!$is_preview && public_contact() != $item['author-id']) { + if (!empty($item['content-warning']) && (!local_user() || !PConfig::get(local_user(), 'system', 'disable_cw', false))) { + $filter_reasons[] = L10n::t('Content warning: %s', $item['content-warning']); + } + + $hook_data = [ + 'item' => $item, + 'filter_reasons' => $filter_reasons + ]; + Addon::callHooks('prepare_body_content_filter', $hook_data); + $filter_reasons = $hook_data['filter_reasons']; + unset($hook_data); + } + + // Update the cached values if there is no "zrl=..." on the links. + $update = (!local_user() && !remote_user() && ($item["uid"] == 0)); + + // Or update it if the current viewer is the intented viewer. + if (($item["uid"] == local_user()) && ($item["uid"] != 0)) { + $update = true; + } + + self::putInCache($item, $update); + $s = $item["rendered-html"]; + + $hook_data = [ + 'item' => $item, + 'html' => $s, + 'preview' => $is_preview, + 'filter_reasons' => $filter_reasons + ]; + Addon::callHooks('prepare_body', $hook_data); + $s = $hook_data['html']; + unset($hook_data); + + if (!$attach) { + // Replace the blockquotes with quotes that are used in mails. + $mailquote = '
'; + $s = str_replace(['
', '
', '
'], [$mailquote, $mailquote, $mailquote], $s); + return $s; + } + + $as = ''; + $vhead = false; + $matches = []; + preg_match_all('|\[attach\]href=\"(.*?)\" length=\"(.*?)\" type=\"(.*?)\"(?: title=\"(.*?)\")?|', $item['attach'], $matches, PREG_SET_ORDER); + foreach ($matches as $mtch) { + $mime = $mtch[3]; + + $the_url = Contact::magicLinkById($item['author-id'], $mtch[1]); + + if (strpos($mime, 'video') !== false) { + if (!$vhead) { + $vhead = true; + $a->page['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('videos_head.tpl'), [ + '$baseurl' => System::baseUrl(), + ]); + } + + $url_parts = explode('/', $the_url); + $id = end($url_parts); + $as .= Renderer::replaceMacros(Renderer::getMarkupTemplate('video_top.tpl'), [ + '$video' => [ + 'id' => $id, + 'title' => L10n::t('View Video'), + 'src' => $the_url, + 'mime' => $mime, + ], + ]); + } + + $filetype = strtolower(substr($mime, 0, strpos($mime, '/'))); + if ($filetype) { + $filesubtype = strtolower(substr($mime, strpos($mime, '/') + 1)); + $filesubtype = str_replace('.', '-', $filesubtype); + } else { + $filetype = 'unkn'; + $filesubtype = 'unkn'; + } + + $title = Strings::escapeHtml(trim(!empty($mtch[4]) ? $mtch[4] : $mtch[1])); + $title .= ' ' . $mtch[2] . ' ' . L10n::t('bytes'); + + $icon = '
'; + $as .= '' . $icon . ''; + } + + if ($as != '') { + $s .= '
'.$as.'
'; + } + + // Map. + if (strpos($s, '
') !== false && x($item, 'coord')) { + $x = Map::byCoordinates(trim($item['coord'])); + if ($x) { + $s = preg_replace('/\
/', '$0' . $x, $s); + } + } + + + // Look for spoiler. + $spoilersearch = '
'; + + // Remove line breaks before the spoiler. + while ((strpos($s, "\n" . $spoilersearch) !== false)) { + $s = str_replace("\n" . $spoilersearch, $spoilersearch, $s); + } + while ((strpos($s, "
" . $spoilersearch) !== false)) { + $s = str_replace("
" . $spoilersearch, $spoilersearch, $s); + } + + while ((strpos($s, $spoilersearch) !== false)) { + $pos = strpos($s, $spoilersearch); + $rnd = Strings::getRandomHex(8); + $spoilerreplace = '
' . L10n::t('Click to open/close') . ''. + '