Файловый менеджер - Редактировать - /var/www/html/libraries/kunena/src/BBCode/KunenaBBCode.php
Ðазад
<?php /** * Kunena Component * * @package Kunena.Framework * @subpackage BBCode * * @copyright Copyright (C) 2008 - @currentyear@ Kunena Team. All rights reserved. * @license https://www.gnu.org/copyleft/gpl.html GNU/GPL * @link https://www.kunena.org **/ namespace Kunena\Forum\Libraries\BBCode; \defined('_JEXEC') or die(); use Exception; use Joomla\CMS\Cache\CacheControllerFactoryInterface; use Joomla\CMS\Document\HtmlDocument; use Joomla\CMS\Factory; use Joomla\Filesystem\Folder; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Http\Http; use Joomla\CMS\Http\Transport\StreamTransport; use Joomla\CMS\Language\Text; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Router\Route; use Joomla\CMS\Uri\Uri; use Joomla\Component\Content\Site\Helper\RouteHelper; use Joomla\Registry\Registry; use Joomla\String\StringHelper; use Joomla\Uri\UriHelper; use Kunena\Forum\Libraries\Attachment\KunenaAttachment; use Kunena\Forum\Libraries\Attachment\KunenaAttachmentHelper; use Kunena\Forum\Libraries\Config\KunenaConfig; use Kunena\Forum\Libraries\Factory\KunenaFactory; use Kunena\Forum\Libraries\Forum\KunenaForum; use Kunena\Forum\Libraries\Forum\Message\KunenaMessage; use Kunena\Forum\Libraries\Forum\Message\KunenaMessageHelper; use Kunena\Forum\Libraries\Layout\KunenaLayout; use Kunena\Forum\Libraries\User\KunenaUserHelper; use Nbbc\BBCode; use Nbbc\BBCodeLibrary; use stdClass; // TODO: add possibility to hide contents from these tags: // [hide], [confidential], [spoiler], [attachment], [code] require_once KPATH_FRAMEWORK . '/External/Nbbc/src/BBCode.php'; require_once KPATH_FRAMEWORK . '/External/Nbbc/src/BBCodeLibrary.php'; require_once KPATH_FRAMEWORK . '/External/Nbbc/src/BBCodeLexer.php'; require_once KPATH_FRAMEWORK . '/External/Nbbc/src/Debugger.php'; /** * @see \Nbbc\BBCode; * Class KunenaBBCode * * @since 6.0 */ class KunenaBBCode extends BBCode { /** * @var integer * @since Kunena 6.0 */ public $autoLink_disable = 0; /** * @var object * @since Kunena 6.0 */ public $parent = null; /** * @var integer * @since Kunena 6.0 */ public $output_limit = 0; /** * @var integer * @since Kunena 6.0 */ public $text_length = 0; /** * @var string * @since Kunena 6.0 */ public $url_target = null; /** * @var KunenaBBCodeLibrary * @since Kunena 6.0 */ protected $defaults; /** * @var array|array[] * @since Kunena 6.0 */ protected $tag_rules; /** * @var array|string[] * @since Kunena 6.0 */ protected $smileys; /** * @var array|string[] * @since Kunena 6.0 */ protected $url_pattern; /** * @var KunenaConfig * @since Kunena 6.0 */ public $config; public $context; /** * Use KunenaBbcode::getInstance() instead. * * @internal * * @param bool $relative relative * * @since Kunena 6.0 * * @throws Exception */ public function __construct($relative = true) { parent::__construct(); $this->defaults = new KunenaBBCodeLibrary(); $this->tag_rules = $this->defaults->default_tag_rules; $this->smileys = $this->defaults->default_smileys; if (empty($this->smileys)) { $this->SetEnableSmileys(false); } $this->config = KunenaFactory::getConfig(); if (JDEBUG && $this->config->debug && KunenaForum::isDev()) { /* * Uncomment the two lines only whne need to have the log of debug else it's way too slow * * $this->setDebug(true); * $this->setLogFile(Factory::getApplication()->get('log_path'). '/kunena.NBBC_BBCODE.php'); */ } $this->SetSmileyDir(JPATH_ROOT); $this->SetSmileyURL($relative ? Uri::root(true) : rtrim(Uri::root(), '/')); $this->SetDetectURLs(true); // The following call works with a hack in Nbbc\BBCode class in he method fillTemplate $this->SetURLPattern([$this, 'parseUrl']); $this->SetURLTarget('_blank'); PluginHelper::importPlugin('kunena'); Factory::getApplication()->triggerEvent('onKunenaBbcodeConstruct', [$this]); // Load Kunena Library Language file as this method can also be used outside Kunena (e.g. EasySocial) Factory::getApplication()->getLanguage()->load('com_kunena.libraries', JPATH_ADMINISTRATOR . '/components/com_kunena'); } /** * Get global instance from BBCode parser. * * @param bool $relative relative * * @return mixed * * @since Kunena 6.0 * @throws Exception */ public static function getInstance($relative = true): KunenaBBCode { static $instance = false; if (!isset($instance[\intval($relative)])) { $instance = []; $instance[\intval($relative)] = new KunenaBBCode($relative); } $instance[\intval($relative)]->autoLink_disable = 0; return $instance[\intval($relative)]; } /** * @param mixed $params params * * @return string|void * * @since Kunena 6.0 * @throws Exception */ public function parseUrl($params) { $url = $params['url']; $text = $params['text']; if ($this->config->autoLink) { if (preg_match('#^mailto:#ui', $url)) { // Cloak email addresses $email = $text; $layout = KunenaLayout::factory('BBCode/Email'); if ($layout->getPath()) { return (string) $layout ->set('email', $email) ->set('mailto', $this->IsValidEmail($email)); } if ($this->canCloakEmail($params)) { return HTMLHelper::_('email.cloak', $email, $this->IsValidEmail($email)); } else { return '<a href="mailto:' . $email . '">' . $email . '</a>'; } } // Remove http(s):// from the text $text = preg_replace('#^http(s?)://#ui', '', $text); if ($this->config->trimLongUrls) { // Shorten URL text if they are too long $text = preg_replace('#^(.{' . $this->config->trimLongUrlsFront . '})(.{4,})(.{' . $this->config->trimLongUrlsBack . '})$#u', '\1...\3', $text); } } if (!isset($params['query'])) { $params['query'] = ''; } if (!isset($params['path'])) { $params['path'] = ''; } if ($this->config->autoEmbedSoundcloud && empty($this->parent->forceMinimal) && isset($params['host'])) { parse_str($params['query'], $query); $path = explode('/', $params['path']); if (strstr($params['host'], 'soundcloud.') && !empty($path[1])) { return '<iframe allowtransparency="true" width="100%" height="350" src="https://w.soundcloud.com/player/?url=' . $params['url'] . '&auto_play=false&visual=true" style="border: 0"></iframe><br />'; } } if ($this->config->autoEmbedInstagram && empty($this->parent->forceMinimal) && isset($params['host'])) { parse_str($params['query'], $query); $path = explode('/', $params['path']); if (strstr($params['host'], 'instagram.') && !empty($path[1])) { return KunenaBBCodeLibrary::DoInstagram('', '', '', '', '', rtrim($params['url'])); } } if ($this->config->autoEmbedYoutube && empty($this->parent->forceMinimal) && isset($params['host'])) { // Convert youtube links to embedded player parse_str($params['query'], $query); $path = explode('/', $params['path']); if (strstr($params['host'], '.youtube.') && !empty($path[1]) && $path[1] == 'watch' && !empty($query['v'])) { $video = $query['v']; } elseif ($params['host'] == 'youtu.be' && !empty($path[1])) { $video = $path[1]; } elseif (strstr($params['host'], '.youtube.') && !empty($path[1]) && $path[1] == 'embed') { $video = $path[2]; } if (isset($video)) { $uri = Uri::getInstance(); if ($uri->isSSL()) { return '<div class="embed-responsive embed-responsive-16by9"><iframe width="425" height="344" src="https://www.youtube-nocookie.com/embed/' . urlencode($video) . '" allowfullscreen style="border: 0"></iframe></div>'; } else { return '<div class="embed-responsive embed-responsive-16by9"><iframe width="425" height="344" src="http://www.youtube-nocookie.com/embed/' . urlencode($video) . '" allowfullscreen style="border: 0"></iframe></div>'; } } } if ($this->config->autoEmbedEbay && empty($this->parent->forceMinimal) && isset($params['host']) && strstr($params['host'], '.ebay.')) { parse_str($params['query'], $query); $path = explode('/', $params['path']); $itemid = ''; if (!empty($path[1])) { if ($path[1] == 'itm') { if (isset($path[3]) && is_numeric($path[3])) { $itemid = $path[3]; } elseif (isset($path[2]) && is_numeric($path[2])) { $itemid = $path[2]; } if (isset($itemid)) { // Convert ebay item to embedded widget return KunenaBBCodeLibrary::renderEbayLayout($itemid); } return; } parse_str($params['query'], $query); if (isset($path[1]) && $path[1] == 'sch' && !empty($query['_nkw'])) { // Convert ebay search to embedded widget KunenaBBCodeLibrary::renderEbayLayout($itemid); } if (strstr($params['host'], 'myworld.') && !empty($path[1])) { // Convert seller listing to embedded widget KunenaBBCodeLibrary::renderEbayLayout($itemid); } } } if (isset($params['host']) && strstr($params['host'], 'bsky.')) { $path = explode('/', $params['path']); if (isset($path[3])) { // TODO : add render for bluesky } } if ($this->config->autoLink) { $internal = false; $layout = KunenaLayout::factory('BBCode/URL'); if ($this->config->smartLinking) { $text = $this->get_title($url); } $uri = Uri::getInstance($url); $host = $uri->getHost(); // The cms will catch most of these well if (empty($host) || Uri::isInternal($url)) { $internal = true; } if ($layout->getPath()) { return (string) $layout ->set('content', $text) ->set('url', $url) ->set('target', $this->url_target) ->set('internal', $internal); } $url = htmlspecialchars($url, ENT_COMPAT, 'UTF-8'); if (strpos($url, '/index.php') !== 0) { return "<a class=\"bbcode_url\" href=\"{$url}\" target=\"_blank\" rel=\"nofollow\">{$text}</a>"; } else { return "<a class=\"bbcode_url\" href=\"{$url}\" target=\"_blank\">{$text}</a>"; } } // Auto-linking has been disabled. return $text; } /** * @see BBCode::SetEnableSmileys() * * @param string $email email * * @return void * @since Kunena 6.0 */ public function IsValidEmail($email) {} /** * @param mixed $params params * * @return boolean * * @since Kunena 6.0 */ public function canCloakEmail(&$params): bool { if (PluginHelper::isEnabled('content', 'emailcloak')) { $plugin = PluginHelper::getPlugin('content', 'emailcloak'); $params = new Registry($plugin->params); if ($params->get('mode', 1)) { return true; } } return false; } /** * Used for Smart Auto Linking, it loads the content of the url given to search the title from it * * @param string $url url * * @return string * * @since Kunena 6.0 */ public function get_title(string $url): string { $str = @file_get_contents($url); if ($str !== false) { if (\strlen($str) > 0) { // Supports line breaks inside <title> $str = trim(preg_replace('/\s+/', ' ', $str)); // Ignore case preg_match("/\<title\>(.*)\<\/title\>/i", $str, $title); return $title[1]; } } return ''; } /** * @param string $string string * * @return array * * @since Kunena 6.0 */ protected function autoDetectURLs($string): array { $search = preg_split('/(?xi) \b ( (?: (?:https?|ftp):\/\/ | www\d{0,3}\. | mailto: | (?:[a-zA-Z0-9._-]{2,}@) ) (?: [^\s()<>]+ | \((?:[^\s()<>]+|(\(?:[^\s()<>]+\)))*\) )+ (?: \((?:[^\s()<>]+|(\(?:[^\s()<>]+\)))*\) | [^\s`!()\[\]{};:\'"\.,<>?«»“�‘’™] ) )/u', $string, -1, PREG_SPLIT_DELIM_CAPTURE); $output = []; if ($search !== false) { foreach ($search as $index => $token) { if ($index && 1) { if (preg_match("/^(https?|ftp|mailto):/ui", $token)) { // Protocol has been provided, so just use it as-is. $url = $token; } else { // Add scheme to emails and raw domain URLs. $url = (strpos($token, '@') ? 'mailto:' : 'http://') . $token; } // Never start URL from the middle of text (except for punctuation). $invalid = preg_match('#[^\s`!()\[\]{};\'"\.,<>?«»“�‘’]$#u', $search[$index - 1]); $invalid |= !$this->IsValidURL($url, true); // We have a full, complete, and properly-formatted URL, with protocol. // Now we need to apply the $this->getURLPattern() template to turn it into HTML. $params = UriHelper::parse_url($url); if (!$invalid && substr($url, 0, 7) == 'mailto:') { $email = StringHelper::substr($url, 7); if ($this->canCloakEmail($params)) { $output[$index] = HTMLHelper::_('email.cloak', $email, $this->IsValidEmail($email)); } else { $output[$index] = $email; } } elseif ($invalid || empty($params['host']) || !empty($params['pass'])) { $output[$index - 1] .= $token; $output[$index] = ''; } else { $params['url'] = $url; $params['link'] = $url; $params['text'] = $token; $output[$index] = $this->FillTemplate($this->getURLPattern(), $params); } } else { $output[$index] = $token; } } } return $output; } /** * @see BBCode::IsValidURL() * Regular expression taken from https://gist.github.com/729294 * * @param bool $local_too local * * @param string $string string * * @param bool $email_too email * * @return boolean * * @since Kunena 6.0 */ public function IsValidURL($string, $email_too = true, $local_too = false) { static $re = '_^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)*(?:\.(?:[a-z\x{00a1}-\x{ffff}]{2,})))(?::\d{2,5})?(?:/[^\s]*)?$_iuS'; if (empty($string)) { return false; } if ($local_too && $string[0] == '/') { $string = 'http://www.domain.com' . $string; } if ($email_too && substr($string, 0, 7) == "mailto:") { return $this->IsValidEmail(substr($string, 7)); } if (preg_match($re, $string)) { return true; } return false; } } /** * Class KunenaBbcodeLibrary * * @since Kunena 6.0 */ class KunenaBBCodeLibrary extends BBCodeLibrary { /** * The bearer token to get tweet data * * @var string * @since Kunena 4.0 */ public $token = null; /** * @var integer * @since Kunena 6.0 */ public $mapid = 0; /** * @var array * @since Kunena 6.0 */ public $default_tag_rules = [ 'b' => [ 'simple_start' => "<b>", 'simple_end' => "</b>", 'class' => 'inline', 'allow_in' => ['listitem', 'block', 'columns', 'inline', 'link'], 'plain_start' => "<b>", 'plain_end' => "</b>", 'allow_params' => false, ], 'i' => [ 'simple_start' => "<i>", 'simple_end' => "</i>", 'class' => 'inline', 'allow_in' => ['listitem', 'block', 'columns', 'inline', 'link'], 'plain_start' => "<i>", 'plain_end' => "</i>", 'allow_params' => false, ], 'u' => [ 'simple_start' => "<u>", 'simple_end' => "</u>", 'class' => 'inline', 'allow_in' => ['listitem', 'block', 'columns', 'inline', 'link'], 'plain_start' => "<u>", 'plain_end' => "</u>", 'allow_params' => false, ], 's' => [ 'simple_start' => "<s>", 'simple_end' => "</s>", 'class' => 'inline', 'allow_in' => ['listitem', 'block', 'columns', 'inline', 'link'], 'plain_start' => "<s>", 'plain_end' => "</s>", 'allow_params' => false, ], 'pre' => [ 'simple_start' => "<pre>", 'simple_end' => "</pre>", 'class' => 'block', 'allow_in' => ['listitem', 'block', 'columns'], 'plain_start' => "<i>", 'plain_end' => "</i>", ], 'font' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'allow' => ['_default' => '/^[a-zA-Z0-9._, -]+$/'], 'method' => 'doFont', 'class' => 'inline', 'allow_in' => ['listitem', 'block', 'columns', 'inline', 'link'], ], 'color' => [ 'mode' => BBCode::BBCODE_MODE_ENHANCED, 'allow' => ['_default' => '/^#?[a-zA-Z0-9._ -]+$/'], 'template' => '<span style="color: {$_default/tw};">{$_content/v}</span>', 'class' => 'inline', 'allow_in' => ['listitem', 'block', 'columns', 'inline', 'link'], ], 'size' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'allow' => ['_default' => '/^[0-9.]+$/D'], 'method' => 'doSize', 'class' => 'inline', 'allow_in' => ['listitem', 'block', 'columns', 'inline', 'link'], ], 'sup' => [ 'simple_start' => "<sup>", 'simple_end' => "</sup>", 'class' => 'inline', 'allow_in' => ['listitem', 'block', 'columns', 'inline', 'link'], 'allow_params' => false, ], 'sub' => [ 'simple_start' => "<sub>", 'simple_end' => "</sub>", 'class' => 'inline', 'allow_in' => ['listitem', 'block', 'columns', 'inline', 'link'], 'allow_params' => false, ], 'spoiler' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'DoSpoiler', 'class' => 'block', 'allow_in' => ['listitem', 'block', 'columns'], 'content' => BBCode::BBCODE_REQUIRED, 'plain_start' => "\nSpoiler:\n<i>", 'plain_end' => "</i>", ], 'hide' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'DoHide', 'class' => 'block', 'allow_in' => ['listitem', 'block', 'columns'], 'content' => BBCode::BBCODE_REQUIRED, 'plain_content' => [], ], 'confidential' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'DoConfidential', 'class' => 'block', 'allow_in' => ['listitem', 'block', 'columns'], 'content' => BBCode::BBCODE_REQUIRED, 'plain_content' => [], ], 'map' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'DoMap', 'class' => 'block', 'allow' => ['type' => '/^[\w\d.-_]*$/', 'zoom' => '/^\d*$/', 'control' => '/^\d*$/'], 'allow_in' => ['listitem', 'block', 'columns'], 'content' => BBCode::BBCODE_VERBATIM, ], 'ebay' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'DoEbay', 'class' => 'block', 'allow_in' => ['listitem', 'block', 'columns'], 'content' => BBCode::BBCODE_VERBATIM, 'plain_start' => "[ebay]", 'plain_end' => "", 'plain_content' => [], ], 'article' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'DoArticle', 'class' => 'block', 'allow_in' => ['listitem', 'block', 'columns'], 'content' => BBCode::BBCODE_REQUIRED, 'plain_start' => "\n[article]\n", 'plain_end' => "", 'plain_content' => [], ], 'tableau' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'DoTableau', 'class' => 'block', 'allow_in' => ['listitem', 'block', 'columns'], 'content' => BBCode::BBCODE_VERBATIM, 'plain_start' => "\n[tableau]\n", 'plain_end' => "", 'plain_content' => [], ], 'video' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'DoVideo', 'allow' => ['type' => '/^[\w\d.-_]*$/', 'param' => '/^[\w]*$/', 'size' => '/^\d*$/', 'width' => '/^\d*$/', 'height' => '/^\d*$/'], 'class' => 'block', 'allow_in' => ['listitem', 'block', 'columns'], 'content' => BBCode::BBCODE_VERBATIM, 'plain_start' => "[video]", 'plain_end' => "", 'plain_content' => [], ], 'img' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'DoImage', 'allow' => ['size' => '/^\d*$/'], 'class' => 'block', 'allow_in' => ['listitem', 'block', 'columns', 'link'], 'content' => BBCode::BBCODE_VERBATIM, 'plain_start' => "[image]", 'plain_end' => "", 'plain_content' => [], ], 'file' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'DoFile', 'allow' => ['size' => '/^\d*$/'], 'class' => 'block', 'allow_in' => ['listitem', 'block', 'columns'], 'content' => BBCode::BBCODE_VERBATIM, 'plain_start' => "\n[file]\n", 'plain_end' => "", 'plain_content' => [], ], 'attachment' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'DoAttachment', 'allow' => ['_default' => '/^\d*$/'], 'class' => 'block', 'allow_in' => ['listitem', 'block', 'columns'], 'content' => BBCode::BBCODE_VERBATIM, 'plain_start' => "\n[attachment]\n", 'plain_end' => "", 'plain_content' => [], ], 'highlight' => [ 'simple_start' => "<span style='font-weight: 700;'>", 'simple_end' => "</span>", 'class' => 'inline', 'allow_in' => ['listitem', 'block', 'columns', 'inline', 'link'], 'plain_start' => "<i>", 'plain_end' => "</i>", ], 'acronym' => [ 'mode' => BBCode::BBCODE_MODE_ENHANCED, 'template' => '<span class="bbcode_acronym" data-bs-toggle="tooltip" title="{$_default/e}">{$_content/v}</span>', 'class' => 'inline', 'allow_in' => ['listitem', 'block', 'columns', 'inline', 'link'], ], 'url' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'DoUrl', 'class' => 'link', 'allow_in' => ['listitem', 'block', 'columns', 'inline'], 'content' => BBCode::BBCODE_REQUIRED, 'plain_content' => ['_content', '_default'], 'plain_link' => ['_default', '_content'], ], 'email' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'doEmail', 'class' => 'link', 'allow_in' => ['listitem', 'block', 'columns', 'inline'], 'content' => BBCode::BBCODE_REQUIRED, 'plain_start' => "<a href=\"mailto:{\$link}\">", 'plain_end' => "</a>", 'plain_content' => ['_content', '_default'], 'plain_link' => ['_default', '_content'], ], 'wiki' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => "doWiki", 'class' => 'link', 'allow_in' => ['listitem', 'block', 'columns', 'inline'], 'end_tag' => BBCode::BBCODE_PROHIBIT, 'content' => BBCode::BBCODE_PROHIBIT, 'plain_start' => "<b>[", 'plain_end' => "]</b>", 'plain_content' => ['title', '_default'], 'plain_link' => ['_default', '_content'], ], 'rule' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => "doRule", 'class' => 'block', 'allow_in' => ['listitem', 'block', 'columns'], 'end_tag' => BBCode::BBCODE_PROHIBIT, 'content' => BBCode::BBCODE_PROHIBIT, 'before_tag' => "sns", 'after_tag' => "sns", 'plain_start' => "\n-----\n", 'plain_end' => "", 'plain_content' => [], ], 'br' => [ 'mode' => BBCode::BBCODE_MODE_SIMPLE, 'simple_start' => "<br>\n", 'simple_end' => "", 'class' => 'inline', 'allow_in' => ['listitem', 'block', 'columns', 'inline', 'link'], 'end_tag' => BBCode::BBCODE_PROHIBIT, 'content' => BBCode::BBCODE_PROHIBIT, 'before_tag' => "s", 'after_tag' => "s", 'plain_start' => "\n", 'plain_end' => "", 'plain_content' => [], ], 'left' => [ 'simple_start' => "\n<div class=\"bbcode_left\" style=\"text-align:left\">\n", 'simple_end' => "\n</div>\n", 'allow_in' => ['listitem', 'block', 'columns'], 'before_tag' => "sns", 'after_tag' => "sns", 'before_endtag' => "sns", 'after_endtag' => "sns", 'plain_start' => "\n", 'plain_end' => "\n", ], 'right' => [ 'simple_start' => "\n<div class=\"bbcode_right\" style=\"text-align:right\">\n", 'simple_end' => "\n</div>\n", 'allow_in' => ['listitem', 'block', 'columns'], 'before_tag' => "sns", 'after_tag' => "sns", 'before_endtag' => "sns", 'after_endtag' => "sns", 'plain_start' => "\n", 'plain_end' => "\n", ], 'center' => [ 'simple_start' => "\n<div class=\"bbcode_center\" style=\"text-align:center\">\n", 'simple_end' => "\n</div>\n", 'allow_in' => ['listitem', 'block', 'columns'], 'before_tag' => "sns", 'after_tag' => "sns", 'before_endtag' => "sns", 'after_endtag' => "sns", 'plain_start' => "\n", 'plain_end' => "\n", ], 'rtl' => [ 'simple_start' => '<div style="direction: rtl;">', 'simple_end' => '</div>', 'class' => 'inline', 'allow_in' => ['listitem', 'block', 'columns', 'inline', 'link'], ], 'indent' => [ 'simple_start' => "\n<div class=\"bbcode_indent\" style=\"margin-left:4em\">\n", 'simple_end' => "\n</div>\n", 'allow_in' => ['listitem', 'block', 'columns'], 'before_tag' => "sns", 'after_tag' => "sns", 'before_endtag' => "sns", 'after_endtag' => "sns", 'plain_start' => "\n", 'plain_end' => "\n", ], 'table' => [ 'simple_start' => "\n<table>", 'simple_end' => "</table>\n", 'class' => 'table', 'allow_in' => ['listitem', 'block', 'columns'], 'end_tag' => BBCode::BBCODE_REQUIRED, 'content' => BBCode::BBCODE_REQUIRED, 'before_tag' => "sns", 'after_tag' => "sns", 'before_endtag' => "sns", 'after_endtag' => "sns", 'plain_start' => "\n", 'plain_end' => "\n", ], 'tr' => [ 'simple_start' => "\n<tr>", 'simple_end' => "</tr>\n", 'class' => 'tr', 'allow_in' => ['table'], 'end_tag' => BBCode::BBCODE_REQUIRED, 'content' => BBCode::BBCODE_REQUIRED, 'before_tag' => "sns", 'after_tag' => "sns", 'before_endtag' => "sns", 'after_endtag' => "sns", 'plain_start' => "\n", 'plain_end' => "\n", ], 'th' => [ 'simple_start' => "<th>", 'simple_end' => "</th>", 'class' => 'columns', 'allow_in' => ['tr'], 'before_tag' => "sns", 'after_tag' => "sns", 'before_endtag' => "sns", 'after_endtag' => "sns", 'plain_start' => "\n", 'plain_end' => "\n", ], 'td' => [ 'simple_start' => "<td>", 'simple_end' => "</td>", 'class' => 'columns', 'allow_in' => ['tr'], 'before_tag' => "sns", 'after_tag' => "sns", 'before_endtag' => "sns", 'after_endtag' => "sns", 'plain_start' => "\n", 'plain_end' => "\n", ], 'columns' => [ 'simple_start' => "\n<table class=\"bbcode_columns\"><tbody><tr><td class=\"bbcode_column bbcode_firstcolumn\">\n", 'simple_end' => "\n</td></tr></tbody></table>\n", 'class' => 'columns', 'allow_in' => ['listitem', 'block', 'columns'], 'end_tag' => BBCode::BBCODE_REQUIRED, 'content' => BBCode::BBCODE_REQUIRED, 'before_tag' => "sns", 'after_tag' => "sns", 'before_endtag' => "sns", 'after_endtag' => "sns", 'plain_start' => "\n", 'plain_end' => "\n", ], 'nextcol' => [ 'simple_start' => "\n</td><td class=\"bbcode_column\">\n", 'class' => 'nextcol', 'allow_in' => ['columns'], 'end_tag' => BBCode::BBCODE_PROHIBIT, 'content' => BBCode::BBCODE_PROHIBIT, 'before_tag' => "sns", 'after_tag' => "sns", 'before_endtag' => "sns", 'after_endtag' => "sns", 'plain_start' => "\n", 'plain_end' => "", ], 'code' => [ 'mode' => BBCode::BBCODE_MODE_ENHANCED, 'template' => "\n<div class=\"bbcode_code\">\n<div class=\"bbcode_code_head\">Code:</div>\n<div class=\"bbcode_code_body\" style=\"white-space:pre\">{\$_content/v}</div>\n</div>\n", 'class' => 'code', 'allow_in' => ['listitem', 'block', 'columns'], 'content' => BBCode::BBCODE_VERBATIM, 'before_tag' => "sns", 'after_tag' => "sn", 'before_endtag' => "sn", 'after_endtag' => "sns", 'plain_start' => "\n<b>Code:</b>\n", 'plain_end' => "\n", ], 'quote' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => "DoQuote", 'allow_in' => ['listitem', 'block', 'columns'], 'before_tag' => "sns", 'after_tag' => "sns", 'before_endtag' => "sns", 'after_endtag' => "sns", 'plain_start' => "\n<b>Quote:</b>\n", 'plain_end' => "\n", ], 'list' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'DoList', 'class' => 'list', 'allow_in' => ['listitem', 'block', 'columns'], 'before_tag' => "sns", 'after_tag' => "sns", 'before_endtag' => "sns", 'after_endtag' => "sns", 'plain_start' => "\n", 'plain_end' => "\n", ], 'ul' => [ 'mode' => BBcode::BBCODE_MODE_LIBRARY, 'method' => 'DoList', 'default' => ['_default' => 'disc'], 'class' => 'list', 'allow_in' => ['listitem', 'block', 'columns'], 'before_tag' => "sns", 'after_tag' => "sns", 'before_endtag' => "sns", 'after_endtag' => "sns", 'plain_start' => "\n", 'plain_end' => "\n", ], 'ol' => [ 'mode' => BBcode::BBCODE_MODE_LIBRARY, 'method' => 'DoList', 'allow' => ['_default' => '/^[\d\w]*$/'], 'default' => ['_default' => '1'], 'class' => 'list', 'allow_in' => ['listitem', 'block', 'columns'], 'before_tag' => "sns", 'after_tag' => "sns", 'before_endtag' => "sns", 'after_endtag' => "sns", 'plain_start' => "\n", 'plain_end' => "\n", ], '*' => [ 'simple_start' => "<li>", 'simple_end' => "</li>\n", 'class' => 'listitem', 'allow_in' => ['list'], 'end_tag' => BBCode::BBCODE_OPTIONAL, 'before_tag' => "s", 'after_tag' => "s", 'before_endtag' => "sns", 'after_endtag' => "sns", 'plain_start' => "\n * ", 'plain_end' => "\n", ], 'li' => [ 'simple_start' => "<li>", 'simple_end' => "</li>\n", 'class' => 'listitem', 'allow_in' => ['listitem', 'block', 'columns', 'list'], 'before_tag' => "s", 'after_tag' => "s", 'before_endtag' => "sns", 'after_endtag' => "sns", 'plain_start' => "\n * ", 'plain_end' => "\n", ], 'terminal' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'DoTerminal', 'allow_in' => ['listitem', 'block', 'columns'], 'class' => 'code', 'allow' => ['colortext' => '/^|#[0-9a-fA-F]+|[a-zA-Z]+$/'], 'before_tag' => "sns", 'after_tag' => "sn", 'before_endtag' => "ns", 'after_endtag' => "sns", 'content' => BBCode::BBCODE_VERBATIM, 'plain_start' => "\nTerminal:\n", 'plain_end' => "\n", ], 'tweet' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'DoTweet', 'class' => 'block', 'allow_in' => ['listitem', 'block', 'columns'], 'content' => BBCode::BBCODE_REQUIRED, 'plain_content' => [], ], 'soundcloud' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'DoSoundcloud', 'class' => 'block', 'allow_in' => ['listitem', 'block', 'columns'], 'content' => BBCode::BBCODE_VERBATIM, 'plain_start' => "[soundcloud]", 'plain_end' => "", 'plain_content' => [], ], 'instagram' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'DoInstagram', 'allow_in' => ['listitem', 'block', 'columns'], 'class' => 'block', 'allow' => ['colortext' => '/^[\w\d.-_]*$/'], 'content' => BBCode::BBCODE_PROHIBIT, ], 'private' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'DoPrivate', 'class' => 'block', 'allow_in' => ['listitem', 'block', 'columns'], 'content' => BBCode::BBCODE_REQUIRED, 'plain_content' => [], ], 'mention' => [ 'mode' => BBCode::BBCODE_MODE_LIBRARY, 'method' => 'DoMention', 'class' => 'block', 'allow_in' => ['listitem', 'block', 'columns'], 'content' => BBCode::BBCODE_REQUIRED, 'plain_content' => [], ], ]; public $config; public $templateParams; public $me; /** * @since Kunena 6.0 * @throws Exception */ public function __construct() { $this->config = KunenaFactory::getConfig(); $this->templateParams = KunenaFactory::getTemplate()->params; $this->me = KunenaUserHelper::getMyself(); if (!$this->templateParams->get('disableEmoticons', '0')) { $db = Factory::getContainer()->get('DatabaseDriver'); $query = $db->createQuery(); $query->select([$db->quoteName('code'), $db->quoteName('location')]) ->from($db->quoteName('#__kunena_smileys')); $db->setQuery($query); $smileys = $db->loadObjectList(); $template = KunenaFactory::getTemplate(); foreach ($smileys as $smiley) { $this->default_smileys[$smiley->code] = $template->getSmileyPath($smiley->location); } } // Translate plain text "Quote:" $this->default_tag_rules['quote']['plain_start'] = Text::_('COM_KUNENA_LIB_BBCODE_QUOTE_TITLE'); } /** * Query from eBay API the JSON stream of item id given to render * * @param int $ItemID The eBay ID of object to query * @param KunenaConfig $config Kunena configuration object * * @return string * * @since Kunena 6.0 * @throws Exception */ public static function getEbayItem(int $ItemID, KunenaConfig $config): stdClass { $options = new Registry(); $transport = new StreamTransport($options); // Create a 'stream' transport. $http = new Http($options, $transport); $data = ['grant_type' => 'client_credentials', 'scope' => 'https://api.ebay.com/oauth/api_scope']; $headersOauth = [ 'Content-Type' => 'application/x-www-form-urlencoded', 'Authorization' => 'Basic ' . base64_encode($config->ebayApiKey . ':' . $config->ebayCertId), ]; $responseOauth = $http->post('https://api.ebay.com/identity/v1/oauth2/token', $data, $headersOauth); if ($responseOauth->code == '200') { $resp = json_decode($responseOauth->body); $token = $resp->access_token; $headers = ['X-EBAY-API-IAF-TOKEN' => $token, 'X-EBAY-API-CALL-NAME' => 'GetSingleItem', 'X-EBAY-API-VERSION' => 1157]; $response = $http->get('https://open.api.ebay.com/shopping?callname=GetSingleItem&siteid=0&responseencoding=JSON&ItemID=' . $ItemID . '&trackingid=' . $config->ebayAffiliateId . '&trackingpartnercode=9', $headers, '10'); if ($response->code == '200') { $responseItem = json_decode($response->body); if ($responseItem->Ack == 'Success') { return $responseItem->Item; } else { $errors = $responseItem->Errors; throw new Exception('Render ebay item ' . $errors[0]->LongMessage); } } } else { $respOauthError = json_decode($responseOauth->body); throw new Exception($respOauthError->error_description); } } /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.0 */ public static function DoInstagram($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { return true; } if (!empty($content)) { return self::renderInstagram($bbcode, $content); } return false; } /** * Method to render the instagram content * * @param string $content * * @return string * @since Kunena 5.2 */ public static function renderInstagram($bbcode, $content) { $before = $content; $content = strip_tags($content); $content = trim($content); $url_parsed = parse_url($content); if (isset($url_parsed['scheme'])) { if ($url_parsed['scheme'] == 'https' || $url_parsed['scheme'] == 'http') { $content = $url_parsed['host'] . $url_parsed['path']; } else { $content = $url_parsed['path']; } } if (preg_match('/(?:(?:http|https):\/\/)?(?:www.)?(?:instagram.com|instagr.am)\/([A-Za-z0-9-_]+)/im', $content)) { if (!preg_match('#^(/|https?:|ftp:)#ui', $content)) { // Add scheme to raw domain URLs. $url = "https://{$content}"; } return '<div class="embed-container"><iframe src="' . rtrim($url, '/') . '/embed/" style="border: 0"></iframe></div>'; } // Display tag in activity streams etc.. if (!empty($bbcode->parent->forceMinimal)) { return "<a href=\"" . $content . "\" rel=\"nofollow\" target=\"_blank\">" . $content . '</a>'; } if (!empty($content)) { return '<div class="embed-container"><iframe src="https://www.instagram.com/p/' . $content . '/embed/" style="border: 0"></iframe></div>'; } else { return $before; } } /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|mixed|string * * @since Kunena 6.0 * @throws Exception */ public function DoEmail($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { return true; } $email = \is_string($default) ? $default : $bbcode->UnHTMLEncode($content); $result = filter_var($email, FILTER_VALIDATE_EMAIL); if (!$result) return; $text = \is_string($default) ? $bbcode->UnHTMLEncode($content) : $default; $text = trim($text && $email != $text ? $text : ''); $mailto = $bbcode->IsValidEmail($email); $result = filter_var($email, FILTER_VALIDATE_EMAIL); if (\is_string($result)) { $isLink = true; } else { $isLink = false; $mailto = $result; } $layout = KunenaLayout::factory('BBCode/Email'); if ($layout->getPath()) { return (string) $layout ->set('email', $email) ->set('isLink', $isLink) ->set('mailto', $mailto) ->set('text', $text); } if ($bbcode->canCloakEmail($params)) { return HTMLHelper::_('email.cloak', htmlspecialchars($email), $bbcode->IsValidEmail($email), htmlspecialchars($text), $bbcode->IsValidEmail($text)); } else { return '<a href="mailto:' . htmlspecialchars($email) . '">' . htmlspecialchars($text) . '</a>'; } } // Format a [size] tag by producing a <span> with a style with a different font-size. /** * Format a [url] tag by producing an <a>...</a> element. * The URL only allows http, https, mailto, and ftp protocols for safety. * * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.0 * @throws Exception */ public function DoURL($bbcode, $action, $name, $default, $params, $content) { // We can't check this with BBCODE_CHECK because we may have no URL before the content // Has been processed. if ($action == BBCode::BBCODE_CHECK) { $bbcode->autoLink_disable++; return true; } $bbcode->autoLink_disable--; $url = $default ? $default : strip_tags($bbcode->UnHTMLEncode($content)); $url = preg_replace('# #u', '%20', $url); $internal = false; if (preg_match('#^(index.php?)#uim', $url)) { $url = Route::_($url, false); } if (preg_match('#^(/index.php?)#uim', $url)) { $str = substr($url, 1); $url = Route::_($str, false); } if (!preg_match('#^(/|https?:|ftp:)#uim', $url)) { $url = "http://{$url}"; } if (!$bbcode->IsValidURL($url, false, true)) { if (KunenaFactory::getConfig()->autoEmbedYoutube) { return $content; } else { return htmlspecialchars($params['_tag'], ENT_COMPAT, 'UTF-8') . $content . htmlspecialchars($params['_endtag'], ENT_COMPAT, 'UTF-8'); } } if (isset($params['target'])) { $target = $bbcode->url_target; $class = $params['class']; } else { $target = ''; $class = null; } $uri = Uri::getInstance($url); $host = $uri->getHost(); // The cms will catch most of these well if (empty($host) || Uri::isInternal($url)) { $internal = true; } $smart = $this->config->smartLinking; if ($smart) { $content = $bbcode->get_title($url); if (!isset($content)) { $content = $url; } } $layout = KunenaLayout::factory('BBCode/URL'); if ($layout->getPath()) { return (string) $layout ->set('class', $class) ->set('content', $content) ->set('url', $url) ->set('target', $target) ->set('internal', $internal); } return false; } // Format a [list] tag, which is complicated by the number of different // ways a list can be started. The following parameters are allowed: // // [list] Unordered list, using default marker // [list=circle] Unordered list, using circle marker // [list=disc] Unordered list, using disc marker // [list=square] Unordered list, using square marker // // [list=1] Ordered list, numeric, starting at 1 // [list=A] Ordered list, capital letters, starting at A // [list=a] Ordered list, lowercase letters, starting at a // [list=I] Ordered list, capital Roman numerals, starting at I // [list=i] Ordered list, lowercase Roman numerals, starting at i // [list=greek] Ordered list, lowercase Greek letters, starting at alpha // [list=01] Ordered list, two-digit numeric with 0-padding, starting at 01 /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.0 * @throws Exception */ public function DoSize($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { return true; } if ($default == 200) { $default = 6; } elseif ($default == 150) { $default = 4; } elseif ($default == 100) { $default = 3; } elseif ($default == 85) { $default = 2; } elseif ($default == 50) { $default = 1; } $layout = KunenaLayout::factory('BBCode/Size'); if ($layout->getPath()) { return (string) $layout ->set('content', $content) ->set('size', $default); } return false; } /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.0 */ public function DoList($bbcode, $action, $name, $default, $params, $content) { // Allowed list styles, striaght from the CSS 2.1 spec. The only prohibited // list style is that with image-based markers, which often slows down web sites. $list_styles = ['1' => 'decimal', '01' => 'decimal-leading-zero', 'i' => 'lower-roman', 'I' => 'upper-roman', 'a' => 'lower-alpha', 'A' => 'upper-alpha']; $ci_list_styles = ['circle' => 'circle', 'disc' => 'disc', 'square' => 'square', 'greek' => 'lower-greek', 'armenian' => 'armenian', 'georgian' => 'georgian']; $ul_types = ['circle' => 'circle', 'disc' => 'disc', 'square' => 'square']; $default = trim($default); if (!$default) { $tag_rule = $bbcode->getRule($name); if (isset($tag_rule['default'])) { $default = $tag_rule['default']['_default']; } else { $default = $tag_rule['default'] = array(); } } if ($action == BBCode::BBCODE_CHECK) { if (!\is_string($default) || \strlen($default) == "") { return true; } elseif (isset($list_styles[$default])) { return true; } elseif (isset($ci_list_styles[strtolower($default)])) { return true; } else { return false; } } // Choose a list element (<ul> or <ol>) and a style. $type = ''; $elem = 'ul'; if (!\is_string($default) || \strlen($default) == "") { $elem = 'ul'; } elseif ($default == '1') { $elem = 'ol'; } elseif (isset($list_styles[$default])) { $elem = 'ol'; $type = $list_styles[$default]; } else { $default = strtolower($default); if (isset($ul_types[$default])) { $elem = 'ul'; $type = $ul_types[$default]; } elseif (isset($ci_list_styles[$default])) { $elem = 'ol'; $type = $ci_list_styles[$default]; } } // Generate the HTML for it. if (\strlen($type)) { return "\n<$elem class=\"bbcode_list\" style=\"list-style-type:$type\">\n$content</$elem>\n"; } else { return "\n<$elem class=\"bbcode_list\">\n$content</$elem>\n"; } } /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.0 * @throws Exception */ public function DoSpoiler($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { return true; } if (!empty($bbcode->lost_start_tags[$name]) && !$bbcode->was_limited) { return "[{$name}]{$content}"; } // Display only spoiler text in activity streams etc.. if (!empty($bbcode->parent->forceMinimal)) { return '[' . ($default ? $default : Text::_('COM_KUNENA_BBCODE_SPOILER')) . ']'; } $document = Factory::getApplication()->getDocument(); $title = $default ? $default : Text::_('COM_KUNENA_BBCODE_SPOILER'); $hidden = ($document instanceof HtmlDocument); $layout = KunenaLayout::factory('BBCode/Spoiler'); if ($layout->getPath()) { $content = preg_replace('#<script(.*?)>(.*?)</script(.*?)>#is', '', $content); return (string) $layout ->set('title', htmlspecialchars($title, ENT_COMPAT, 'UTF-8')) ->set('hidden', $hidden) ->set('content', $content) ->set('params', $params); } return false; } /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.0 * @throws Exception */ public function DoHide($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { return true; } if (!empty($bbcode->lost_start_tags[$name]) && !$bbcode->was_limited) { return "[{$name}]{$content}"; } // Display nothing in activity streams etc.. if (!empty($bbcode->parent->forceSecure)) { return ''; } // Display nothing in subscription mails if (!empty($bbcode->context)) { return ''; } if (!Factory::getApplication()->getIdentity()->guest) { $layout = KunenaLayout::factory('BBCode/Hide'); if ($layout->getPath()) { return (string) $layout ->set('me', $this->me) ->set('content', $content) ->set('params', $params); } } else { return '<br />' . Text::_('COM_KUNENA_BBCODE_HIDDENTEXT') . '<br />'; } return false; } /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.0 * @throws Exception */ public function DoConfidential($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { return true; } if (!empty($bbcode->lost_start_tags[$name]) && !$bbcode->was_limited) { return "[{$name}]{$content}"; } // Display nothing in activity streams etc.. if (!empty($bbcode->parent->forceSecure)) { return ''; } // Display nothing in subscription mails if (!empty($bbcode->context)) { return ''; } $me = KunenaUserHelper::getMyself(); if ($bbcode->parent->message instanceof KunenaMessage) { $message_userid = $bbcode->parent->message->userid; $KunenaForumMessage = $bbcode->parent->message; } elseif ($bbcode->parent instanceof KunenaMessage) { $message_userid = $bbcode->parent->userid; $KunenaForumMessage = $bbcode->parent; } else { $message_userid = 0; // Just create here empty KunenaForumMessage object just in case to avoid issue when calling it just after $KunenaForumMessage = KunenaMessageHelper::get(); } $moderator = $me->userid && $me->isModerator($KunenaForumMessage->getCategory()); if (($me->userid && $message_userid == $me->userid) || $moderator) { $layout = KunenaLayout::factory('BBCode/Confidential'); if ($layout->getPath()) { return (string) $layout ->set('me', $this->me) ->set('content', $content) ->set('params', $params); } } else { return '<div class="kmsgtext-confidentialguests">' . Text::_('COM_KUNENA_BBCODE_CONFIDENTIAL_TEXT_GUESTS') . '</div>'; } return false; } /** * @return mixed * * @since Kunena 6.0 */ protected function getMessage() { if (empty($this->parent)) { return false; } if ($this->parent instanceof KunenaMessage) { return $this->parent; } return $this->parent->message ?? false; } /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return bool|string * * @since Kunena 6.0 * @throws Exception */ public function DoMap($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { return true; } $content = trim($content); if (empty($content)) { echo '<div class="alert alert-error">' . Text::_('COM_KUNENA_LIB_BBCODE_MAP_ERROR_CITY_MISSING') . '</div>'; return false; } $document = Factory::getApplication()->getDocument(); // Display only link in activity streams etc.. if (!empty($bbcode->parent->forceMinimal) || !($document instanceof HtmlDocument) || KunenaFactory::getTemplate()->isHmvc() && !$this->templateParams->get('Map')) { $url = 'https://maps.google.com/?q=' . urlencode($bbcode->UnHTMLEncode($content)); return '<a href="' . $url . '" rel="nofollow noopener noreferrer" target="_blank">' . $content . '</a>'; } $this->mapid++; $layout = KunenaLayout::factory('BBCode/Map'); if ($layout->getPath()) { return (string) $layout ->set('content', $content) ->set('mapid', $this->mapid) ->set('params', $params) ->set('config', $this->config); } return false; } /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.0 * @throws Exception */ public function DoEbay($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { return true; } if (KunenaFactory::getTemplate()->isHmvc() && !$this->templateParams->get('Ebay')) { return false; } $config = KunenaFactory::getConfig(); if (!is_numeric($content)) { echo '<b>' . Text::_('COM_KUNENA_LIB_BBCODE_EBAY_ERROR_WRONG_ITEM_ID') . '</b>'; return false; } // Display tag in activity streams etc.. if (!empty($bbcode->parent->forceMinimal)) { if (!is_numeric($config->ebayAffiliateId)) { return false; } return '<a target="_blank" rel="noopener noreferrer" href="https://www.ebay.com/itm/' . $content . '?lang=' . $this->config->ebayLanguageCode . '&campid=' . $this->config->ebayAffiliateId . '">www.ebay.com/itm/' . $content . '</a>'; } return self::renderEbayLayout($content); } /** * Render eBay layout from template * * @param int $ItemID id * * @return false|string * * @since Kunena 6.0 * @throws Exception */ public static function renderEbayLayout(int $ItemID) { // Because the method renderEbayLayout is called in static way need to keep the call of config class here $config = KunenaFactory::getConfig(); if (empty($config->ebayApiKey) || empty($config->ebayCertId)) { echo '<b>' . Text::_('COM_KUNENA_LIB_BBCODE_EBAY_ERROR_NO_EBAY_APP_ID') . '</b>'; return false; } $layout = KunenaLayout::factory('BBCode/eBay'); if ($layout->getPath()) { $ebay = self::getEbayItemFromCache($ItemID, $config); if (\is_object($ebay)) { return (string) $layout ->set('content', $ItemID) // ->set('params', $params) ->set('naturalurl', $ebay->ViewItemURLForNaturalSearch) ->set('pictureurl', $ebay->PictureURL[0]) ->set('status', $ebay->ListingStatus) ->set('title', $ebay->Title) ->setLayout(is_numeric($ItemID) ? 'default' : 'search'); } else { echo '<b>' . $ebay . '</b>'; return false; } } return false; } /** * Load eBay object item from cache * * @param int $ItemID The eBay ID of object to query. * @param KunenaConfig $config Kunena configuration object * * @return string * * @since Kunena 6.0 * @throws Exception */ public static function getEbayItemFromCache(int $ItemID, KunenaConfig $config): stdClass { $options = ['defaultgroup' => 'Kunena_ebay_request']; $cache = Factory::getContainer()->get(CacheControllerFactoryInterface::class)->createCacheController('output', $options); $cache->setCaching(true); if ($config->cacheTime == 0) { $config->cacheTime = 60; } $cache->setLifeTime($config->cacheTime); /** * TOOD : fix method call() give an error */ //return $cache->call(['KunenaBbcodeLibrary', 'getEbayItem'], $ItemID); return KunenaBbcodeLibrary::getEbayItem($ItemID, $config); } /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.0 * @throws Exception */ public function DoArticle($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { return true; } $lang = Factory::getApplication()->getLanguage(); $lang->load('com_content'); $articleid = \intval($content); $user = Factory::getApplication()->getIdentity(); $site = Factory::getApplication('site'); $db = Factory::getContainer()->get('DatabaseDriver'); $query = $db->createQuery(); $query->select('a.*, u.name AS author, cc.title AS category, 0 AS sec_pub, 0 AS sectionid, cc.published AS cat_pub, cc.access AS cat_access') ->from($db->quoteName('#__content', 'a')) ->leftJoin($db->quoteName('#__categories', 'cc') . ' ON cc.id = a.catid') ->leftJoin($db->quoteName('#__users', 'u') . ' ON u.id = a.created_by') ->where('a.id = ' . $db->quote($articleid)); $db->setQuery($query); $article = $db->loadObject(); if ($article) { // Get credentials to check if the user has right to see the article $params = $site->getParams('com_content'); $registry = new Registry(); $registry->loadString($article->attribs); $article->params = clone $params; $article->params->merge($registry); $params = $article->params; $viewlevels = $user->getAuthorisedViewLevels(); if (!\in_array($article->access, $viewlevels)) { $denied = true; } } $html = $link = ''; if (!$article || (!$article->cat_pub && $article->catid) || (!$article->sec_pub && $article->sectionid)) { $html = Text::_('COM_KUNENA_LIB_BBCODE_ARTICLE_ERROR_UNPUBLISHED'); } elseif (!empty($denied) && !$params->get('show_noauth')) { $html = Text::_('COM_KUNENA_LIB_BBCODE_ARTICLE_ERROR_NO_PERMISSIONS'); } else { $article->slug = !empty($article->alias) ? ($article->id . ':' . $article->alias) : $article->id; $article->catslug = !empty($article->category_alias) ? ($article->catid . ':' . $article->category_alias) : $article->catid; $url = Route::_(RouteHelper::getArticleRoute($article->slug, $article->catslug)); if (!$default) { $default = $this->config->articleDisplay; } // Do not display full text if there's no permissions to display the full article. if (!empty($denied) && $default == 'full') { $default = 'intro'; } switch ($default) { case 'full': if (!empty($article->fulltext) && !empty($article->introtext)) { $article->text = $article->introtext . '<br />' . $article->fulltext; break; } elseif (empty($article->fulltext) && !empty($article->introtext)) { $article->text = $article->introtext; break; } break; // Continue to intro if fulltext is empty case 'intro': if (!empty($article->introtext)) { $article->text = $article->introtext; if (!empty($article->fulltext)) { $link = '<a href="' . $url . '" class="readon">' . Text::_('COM_KUNENA_LIB_BBCODE_ARTICLE_MORE') . '</a>'; } else { $link = ''; } } break; // Continue to link if introtext is empty case 'link': default: $link = '<a href="' . $url . '" class="readon">' . $article->title . '</a>'; break; } if (!empty($article->text)) { // Identify the source of the event to be Kunena itself // this is important to avoid recursive event behaviour with our own plugins $params->set('ksource', 'kunena'); PluginHelper::importPlugin('content'); Factory::getApplication()->triggerEvent('onContentPrepare', ['text', &$article, &$params, 0]); $article->text = HTMLHelper::_('string.truncate', $article->text, $bbcode->output_limit - $bbcode->text_length); $bbcode->text_length += \strlen($article->text); $html = $article->text; } if (!empty($denied)) { $link = '<span class="readon">' . Text::_('COM_CONTENT_REGISTER_TO_READ_MORE') . '</span>'; } } return ($html ? '<div class="kmsgtext-article">' . $html . '</div>' : '') . $link; } /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.0 * @throws Exception */ public function DoQuote($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { return true; } $default = isset($default) ? htmlspecialchars($default, ENT_COMPAT, 'UTF-8') : false; $matches = []; preg_match('/userid=(\d+)/', $default, $matches); $userid = 0; foreach ($matches as $match) { if (is_numeric($match)) { $userid = (int) $match; } } $username = ''; if ($userid > 0) { $username = KunenaUserHelper::get($userid)->getName(); } $matches_post = []; preg_match('/post=(\d+)/', $default, $matches_post); $postid = 0; foreach ($matches_post as $match) { if (is_numeric($match)) { $postid = (int) $match; } } if ($postid > 0) { $message = KunenaMessageHelper::get($postid); $msglink = Uri::getInstance()->toString(array('scheme', 'host', 'port')) . $message->getUrl(null, false); } // Support bbcode quote tag done in K5.1 and first versions of K5.2 if ($userid == 0 && $postid == 0) { $user = isset($default) ? htmlspecialchars($default, ENT_COMPAT, 'UTF-8') : false; if ($user) { $username = $user . " " . Text::_('COM_KUNENA_POST_WROTE') . ': '; } $msglink = ''; } $layout = KunenaLayout::factory('BBCode/Quote'); if ($layout->getPath()) { return (string) $layout ->set('username', $username) ->set('msglink', $msglink) ->set('content', $content); } return ''; } /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.0 * @throws Exception */ public function DoCode($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { return true; } $type = isset($params["type"]) ? $params["type"] : (isset($default) ? $default : "php"); if ($type == 'js') { $type = 'javascript'; } elseif ($type == 'html') { $type = 'html4strict'; } if ($type == 'less' || $type == 'scss' || $type == 'sass') { $type = 'css'; } $type = preg_replace('/[^A-Z0-9_\.-]/i', '', $type); if ($type) { $code = '<pre xml:' . $type . '>' . $content . '</pre>'; } else { $code = '<pre>' . $content . '</pre>'; } return '<div class="highlight">' . $code . '</div>'; } /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.0 * @throws Exception */ public function doTableau($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { $bbcode->autoLink_disable++; return true; } $bbcode->autoLink_disable--; if (!$content) { return ''; } // Display tag in activity streams etc.. if (!empty($bbcode->parent->forceMinimal)) { return '[tableau]'; } $maxwidth = (int) $this->config->rteWidth; $maxheight = (int) (isset($params["height"]) && is_numeric($params["height"])) ? $params["height"] : $this->config->rteHeight; if (preg_match('/(https:\/\/public.tableau.com\/views)\/(.*)\/(.*)\?.*/', $content, $matches)) { $tableauserver = $matches[1]; $vizualization = $matches[2]; $vizualizationTab = $matches[3]; if ($tableauserver != 'https://public.tableau.com/views') { return ''; } $layout = KunenaLayout::factory('BBCode/Tableau'); if ($layout->getPath()) { return (string) $layout ->set('params', $params) ->set('width', $maxwidth) ->set('height', $maxheight) ->set('vizualization', $vizualization) ->set('vizualizationTab', $vizualizationTab); } } return ''; } /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string|void * * @since Kunena 6.0 * @throws Exception */ public function DoVideo($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { $bbcode->autoLink_disable++; return true; } if (!$content || KunenaFactory::getTemplate()->isHmvc() && !$this->templateParams->get('Video')) { return ''; } // Display tag in activity streams etc.. if (!empty($bbcode->parent->forceMinimal)) { return '[video]'; } // Display nothing in subscription mails if (!empty($bbcode->context)) { return ''; } $vid_minwidth = 200; $vid_minheight = 44; // Min. display size $vid_sizemax = 100; // max. display zoom in percent $vid["type"] = (isset($params["type"])) ? StringHelper::strtolower($params["type"]) : ''; $vid["param"] = (isset($params["param"])) ? $params["param"] : ''; if (!$vid["type"]) { $vid_players = ['divx' => 'divx', 'flash' => 'swf', 'mediaplayer' => 'avi,mp3,wma,wmv', 'quicktime' => 'mov,qt,qti,qtif,qtvr', 'realplayer', 'rm']; foreach ($vid_players as $vid_player => $vid_exts) { foreach (explode(',', $vid_exts) as $vid_ext) { if (preg_match('/^(.*\.' . $vid_ext . ')$/i', $content) > 0) { $vid["type"] = $vid_player; break 2; } } } unset($vid_players); } if (!$vid["type"]) { $vid_auto = preg_match('#^https?://.*?([^.]*)\.[^.]*(/|$)#u', $content, $vid_regs); if ($vid_auto) { $vid["type"] = StringHelper::strtolower($vid_regs[1]); switch ($vid["type"]) { case 'wideo': $vid["type"] = 'wideo.fr'; break; } } } $vid_providers = [ 'bofunk' => ['flash', 446, 370, 0, 0, 'https://www.bofunk.com/e/%vcode%', '', ''], 'break' => ['flash', 464, 392, 0, 0, 'https://embed.break.com/%vcode%', '', ''], 'clipfish' => ['flash', 464, 380, 0, 0, 'https://www.clipfish.de/videoplayer.swf?as=0&videoid=%vcode%&r=1&c=0067B3', 'videoid=([\w\-]*)', ''], 'dailymotion' => ['flash', 464, 380, 0, 0, 'https://www.dailymotion.com/swf/video/%vcode%?autoPlay=0', '\/([\w]*)_', [[6, 'wmode', 'transparent']]], 'metacafe' => ['flash', 400, 345, 0, 0, 'https://www.metacafe.com/fplayer/%vcode%/.swf', '\/watch\/(\d*\/[\w\-]*)', [[6, 'wmode', 'transparent']]], 'myspace' => ['iframe', 430, 346, 0, 0, 'https://media.myspace.com/play/video/%vcode%', '', [[6, 'wmode', 'transparent']]], 'rutube' => ['flash', 400, 353, 0, 0, 'https://video.rutube.ru/%vcode%', '\.html\?v=([\w]*)'], 'sapo' => ['flash', 400, 322, 0, 0, 'https://rd3.videos.sapo.pt/play?file=https://rd3.videos.sapo.pt/%vcode%/mov/1', 'videos\.sapo\.pt\/([\w]*)', [[6, 'wmode', 'transparent']]], 'veoh' => ['flash', 540, 438, 0, 0, 'https://www.veoh.com/videodetails2.swf?player=videodetailsembedded&type=v&permalinkId=%vcode%', '\/videos\/([\w-]*)', ''], 'videojug' => ['flash', 400, 345, 0, 0, 'https://www.videojug.com/film/player?id=%vcode%', '', ''], 'vimeo' => ['iframe', 400, 321, 0, 0, 'https://player.vimeo.com/video/%vcode%?color=ff0179', '\.com\/(\d*)', ''], 'youtube' => ['iframe', 425, 355, 0, 0, 'https://www.youtube-nocookie.com/embed/%vcode%', '\/watch\?v=([\w\-]*)', [[6, 'wmode', 'transparent']]], 'youku' => ['flash', 425, 355, 0, 0, 'https://player.youku.com/player.php/Type/Folder/Fid/18787874/Ob/1/sid/%vcode%/v.swf', '\/watch\?v=([\w\-]*)', [[6, 'wmode', 'transparent']]], // Cannot allow public flash objects as it opens up a whole set of vulnerabilities through hacked flash files // '_default' => array ($vid ["type"], 480, 360, 0, 25, $content, '', '' ) // ]; if (isset($vid_providers[$vid["type"]])) { list($vid_type, $vid_width, $vid_height, $vid_addx, $vid_addy, $vid_source, $vid_match, $vid_par2) = (isset($vid_providers[$vid["type"]])) ? $vid_providers[$vid["type"]] : $vid_providers["_default"]; } else { return; } unset($vid_providers); if (!empty($vid_auto)) { if ($vid_match && (preg_match("/$vid_match/i", $content, $vid_regs) > 0)) { $content = $vid_regs[1]; } else { return; } } $uri = Uri::getInstance(); if ($uri->isSSL() && $vid["type"] == 'youtube') { $vid_source = preg_replace("/^http:/", "https:", $vid_source); } $vid_source = preg_replace('/%vcode%/', $content, $vid_source); if (!\is_array($vid_par2)) { $vid_par2 = []; } $vid_size = isset($params["size"]) ? \intval($params["size"]) : 0; if (($vid_size > 0) && ($vid_size < $vid_sizemax)) { $vid_width = (int) ($vid_width * $vid_size / 100); $vid_height = (int) ($vid_height * $vid_size / 100); } $vid_width += $vid_addx; $vid_height += $vid_addy; if (!isset($params["size"])) { if (isset($params["width"])) { if ($params['width'] == '1') { $params['width'] = $vid_minwidth; } } if (isset($params["width"])) { $vid_width = \intval($params["width"]); } if (isset($params["height"])) { if ($params['height'] == '1') { $params['height'] = $vid_minheight; } } if (isset($params["height"])) { $vid_height = \intval($params["height"]); } } switch ($vid_type) { case 'divx': $vid_par1 = [[1, 'classid', 'clsid:67DABFBF-D0AB-41fa-9C46-CC0F21721616'], [1, 'codebase', 'https://go.divx.com/plugin/DivXBrowserPlugin.cab'], [4, 'type', 'video/divx'], [4, 'pluginspage', 'https://go.divx.com/plugin/download/'], [6, 'src', $vid_source], [6, 'autoplay', 'false'], [5, 'width', $vid_width], [5, 'height', $vid_height]]; $vid_allowpar = ['previewimage']; break; case 'flash': $vid_par1 = [[1, 'classid', 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000'], [1, 'codebase', 'https://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab'], [2, 'movie', $vid_source], [4, 'src', $vid_source], [4, 'type', 'application/x-shockwave-flash'], [4, 'pluginspage', 'https://www.macromedia.com/go/getflashplayer'], [6, 'quality', 'high'], [6, 'allowFullScreen', 'true'], [6, 'allowScriptAccess', 'never'], [5, 'width', $vid_width], [5, 'height', $vid_height]]; $vid_allowpar = ['flashvars', 'wmode', 'bgcolor', 'quality']; break; case 'iframe': return '<div class="embed-responsive embed-responsive-16by9"><iframe src="' . $vid_source . '" width="' . $vid_width . '" height="' . $vid_height . '" allowfullscreen style="border: 0"></iframe></div>'; break; case 'mediaplayer': $vid_par1 = [[1, 'classid', 'clsid:22d6f312-b0f6-11d0-94ab-0080c74c7e95'], [1, 'codebase', 'https://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab'], [4, 'type', 'application/x-mplayer2'], [4, 'pluginspage', 'https://www.microsoft.com/Windows/MediaPlayer/'], [6, 'src', $vid_source], [6, 'autostart', 'false'], [6, 'autosize', 'true'], [5, 'width', $vid_width], [5, 'height', $vid_height]]; $vid_allowpar = []; break; case 'quicktime': $vid_par1 = [[1, 'classid', 'clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B'], [1, 'codebase', 'https://www.apple.com/qtactivex/qtplugin.cab'], [4, 'type', 'video/quicktime'], [4, 'pluginspage', 'https://www.apple.com/quicktime/download/'], [6, 'src', $vid_source], [6, 'autoplay', 'false'], [6, 'scale', 'aspect'], [5, 'width', $vid_width], [5, 'height', $vid_height]]; $vid_allowpar = []; break; case 'realplayer': $vid_par1 = [[1, 'classid', 'clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA'], [4, 'type', 'audio/x-pn-realaudio-plugin'], [6, 'src', $vid_source], [6, 'autostart', 'false'], [6, 'controls', 'ImageWindow,ControlPanel'], [5, 'width', $vid_width], [5, 'height', $vid_height]]; $vid_allowpar = []; break; default: return; } $vid_par3 = []; foreach ($params as $vid_key => $vid_value) { if (\in_array(StringHelper::strtolower($vid_key), $vid_allowpar)) { array_push($vid_par3, [6, $vid_key, $bbcode->HTMLEncode($vid_value)]); } } $vidinternalObject = $vid_param = $vid_embed = []; foreach (array_merge($vid_par1, $vid_par2, $vid_par3) as $vid_data) { list($vid_key, $vid_name, $vid_value) = $vid_data; if ($vid_key && 1) { $vidinternalObject[$vid_name] = ' ' . $vid_name . '="' . preg_replace('/%vcode%/', $content, $vid_value) . '"'; } if ($vid_key && 2) { $vid_param[$vid_name] = '<param name="' . $vid_name . '" value="' . preg_replace('/%vcode%/', $content, $vid_value) . '" />'; } if ($vid_key && 4) { $vid_embed[$vid_name] = ' ' . $vid_name . '="' . preg_replace('/%vcode%/', $content, $vid_value) . '"'; } } $tag_new = '<div class="embed-responsive embed-responsive-16by9"> <object'; foreach ($vidinternalObject as $vid_data) { $tag_new .= $vid_data; } $tag_new .= '>'; foreach ($vid_param as $vid_data) { $tag_new .= $vid_data; } $tag_new .= '<embed'; foreach ($vid_embed as $vid_data) { $tag_new .= $vid_data; } $tag_new .= ' /></object></div>'; return $tag_new; } /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.0 * @throws Exception * @throws null */ public function DoAttachment($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { return true; } // Display nothing in subscription mails if (!empty($bbcode->context)) { return ''; } $attachments = null; if ($bbcode->parent instanceof KunenaMessage) { $attachments = $bbcode->parent->getAttachments(); } elseif (\is_object($bbcode->parent) && isset($bbcode->parent->attachments)) { $attachments = &$bbcode->parent->attachments; } $attachment = null; if (!empty($default)) { $attachment = KunenaAttachmentHelper::get($default); unset($attachments[$attachment->id]); } elseif (empty($content) && !empty($attachments)) { $attachment = array_shift($attachments); } elseif (!empty($attachments)) { foreach ($attachments as $att) { if ($att->getFilename() == $content) { $attachment = $att; unset($attachments[$att->id]); break; } } } else { return ''; } // Display tag in activity streams etc.. if (!isset($attachments) || !empty($bbcode->parent->forceMinimal)) { if ($attachment->isImage()) { $hide = $this->config->showImgForGuest == 0 && Factory::getApplication()->getIdentity()->id == 0; if (!$hide) { return "<div class=\"kmsgimage\">{$attachment->getImageLink()}</div>"; } } elseif ($attachment->isVideo()) { $hide = $this->config->showFileForGuest == 0 && Factory::getApplication()->getIdentity()->id == 0; if (!$hide) { return "<div class=\"kmsgvideo\">{$attachment->getUrl()}</div>"; } } else { $hide = $this->config->showFileForGuest == 0 && Factory::getApplication()->getIdentity()->id == 0; if (!$hide) { return "<div class=\"kmsgattach\"><h4>" . Text::_('COM_KUNENA_FILEATTACH') . "</h4>" . Text::_('COM_KUNENA_FILENAME') . " <a href=\"" . $attachment->getUrl() . "\" target=\"_blank\" rel=\"nofollow\">" . $attachment->filename . "</a><br />" . Text::_('COM_KUNENA_FILESIZE') . ' ' . number_format(\intval($attachment->size) / 1024, 0, '', ',') . ' KB' . "</div>"; } } } if (!$attachment && !empty($bbcode->parent->inline_attachments)) { foreach ($bbcode->parent->inline_attachments as $att) { if ($att->getFilename() == trim(strip_tags($content))) { $attachment = $att; break; } } } if (!$attachment) { return $bbcode->HTMLEncode($content); } return $this->renderAttachment($attachment, $bbcode); } /** * @param KunenaAttachment $attachment attachment * @param object $bbcode bbcode * @param bool $displayImage display image * * @return string|void * * @since Kunena 6.0 * @throws null * @throws Exception */ protected function renderAttachment(KunenaAttachment $attachment, object $bbcode, $displayImage = true) { // Display nothing in subscription mails if (!empty($bbcode->context)) { return ''; } $layout = KunenaLayout::factory('BBCode/Attachment') ->set('attachment', $attachment) ->set('canLink', $bbcode->autoLink_disable == 0); $bbcode->parent->inline_attachments[$attachment->id] = $attachment; if (!$attachment->exists() || !$attachment->getPath()) { return (string) $layout->setLayout('deleted'); } if (!$attachment->isAuthorised() && !$this->config->showImgForGuest && $attachment->id != '0') { return (string) $layout->setLayout('unauthorised'); } if (!$attachment->isAuthorised()) { return (string) $layout->setLayout('unauthorised'); } if ($displayImage && $attachment->isImage()) { $layout->setLayout('image'); } return (string) $layout; } /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.0 * @throws Exception * @throws null */ public function DoFile($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { return true; } // Display nothing in subscription mails if (!empty($bbcode->context)) { return ''; } // Display tag in activity streams etc.. if (!empty($bbcode->parent->forceMinimal)) { return '[ ' . basename(!empty($params["name"]) ? $params["name"] : trim(strip_tags($content))) . ' ]'; } // Make sure that filename does not contain path or URL. $filename = basename(!empty($params['name']) ? $params['name'] : $bbcode->UnHTMLEncode(trim(strip_tags($content)))); $path = "attachments/legacy/files/{$filename}"; $filepath = KPATH_MEDIA . '/' . $path; $fileurl = KURL_MEDIA . '/' . $path; // Legacy attachments support. if (isset($bbcode->parent->attachments)) { $attachments = &$bbcode->parent->attachments; foreach ($attachments as $id => $attachment) { if ($attachment->getFilename() == $filename && $attachment->folder == 'media/kunena/attachments/legacy/files') { unset($attachments[$id]); return $this->renderAttachment($attachment, $bbcode, false); } } } $layout = KunenaLayout::factory('BBCode/File') ->set('url', null) ->set('filename', null) ->set('size', 0) ->set('canLink', $bbcode->autoLink_disable == 0); if (Factory::getApplication()->getIdentity()->id == 0 && $this->config->showFileForGuest == 0) { // Hide between content from non registered users return (string) $layout ->set('title', Text::_('COM_KUNENA_SHOWIMGFORGUEST_HIDEFILE')) ->setLayout('unauthorised'); } $layout->set('filename', $filename); $layout->set('size', isset($params['size']) ? $params['size'] : 0); if (!is_file($filepath)) { // File does not exist (or URL was pointing somewhere else). $layout ->set('title', Text::sprintf('COM_KUNENA_ATTACHMENT_DELETED', $bbcode->HTMLEncode($filename))) ->setLayout('deleted'); } else { $layout ->set('title', Text::_('COM_KUNENA_FILEATTACH')) ->set('url', $fileurl) ->set('size', fileSize($filepath)); } return (string) $layout; } /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.0 * @throws Exception * @throws null */ public function DoImage($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { return true; } $fileurl = $bbcode->UnHTMLEncode(trim(strip_tags($content))); if (!$bbcode->IsValidURL($fileurl, false, true)) { return htmlspecialchars($params['_tag'], ENT_COMPAT, 'UTF-8') . $content . htmlspecialchars($params['_endtag'], ENT_COMPAT, 'UTF-8'); } $filename = basename($fileurl); // Display tag in activity streams etc.. if (!empty($bbcode->parent->forceMinimal)) { return "<a href=\"" . $bbcode->HTMLEncode($fileurl) . "\" rel=\"nofollow\" target=\"_blank\">" . $bbcode->HTMLEncode($filename) . '</a>'; } // Legacy attachments support. if (isset($bbcode->parent->attachments) && strpos($fileurl, '/media/kunena/attachments/legacy/images/')) { // Remove attachment from the attachments list and show it if it exists. $attachments = &$bbcode->parent->attachments; foreach ($attachments as $id => $attachment) { if ($attachment->getFilename() == $filename && $attachment->folder == 'media/kunena/attachments/legacy/images') { unset($attachments[$id]); return $this->renderAttachment($attachment, $bbcode); } } } // Get the words set on alt params when alt is used like that : alt=my words; see issue #6751 $matches = array(); $altText = null; preg_match('/[img(\s*(?!alt)([\w\-\.]+\s*\/?]/', $params['_tag'], $matches); if (\count($matches) > 0) { $altText = rtrim($matches[0], "]"); } $layout = KunenaLayout::factory('BBCode/Image') ->set('title', Text::_('COM_KUNENA_FILEATTACH')) ->set('url', null) ->set('filename', null) ->set('size', isset($params['size']) ? $params['size'] : 0) ->set('alt', \count($matches) > 0 ? $altText : 0) ->set('canLink', $bbcode->autoLink_disable == 0); // When image is set to don't show to guest, it should display the smilies if (Factory::getApplication()->getIdentity()->id == 0 && $this->config->showImgForGuest == 0 && !preg_match('@media\/kunena\/emoticons@', $fileurl)) { // Hide between content from non registered users. return (string) $layout->set('title', Text::_('COM_KUNENA_SHOWIMGFORGUEST_HIDEIMG'))->setLayout('unauthorised'); } // Obey image security settings. if ($this->config->bbcodeImgSecure != 'image') { if ($bbcode->autoLink_disable == 0 && !preg_match("/\\.(?:gif|jpeg|jpg|jpe|png)$/ui", $fileurl)) { // If the image has not legal extension, return it as link or text. if ($this->config->bbcodeImgSecure == 'link') { if (!preg_match('`^(/|https?://)`', $fileurl)) { $fileurl = 'http://' . $fileurl; } // TODO: call URL layout instead.. return "<a href=\"" . $bbcode->HTMLEncode($fileurl) . "\" rel=\"nofollow\" target=\"_blank\">" . $bbcode->HTMLEncode($fileurl) . '</a>'; } else { return $bbcode->HTMLEncode($fileurl); } } } return (string) $layout->set('url', $fileurl); } /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.0 * @throws Exception */ public function DoTerminal($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { return true; } $layout = KunenaLayout::factory('BBCode/Terminal'); // Check if value entered by user for the colortext params is right in hexadecimal if (ctype_xdigit($params['colortext'])) { if ($layout->getPath()) { return (string) $layout ->set('content', $content) ->set('params', $params); } } return false; } /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.0 * @throws Exception */ public function DoTweet($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { return true; } // Display nothing in subscription mails if (!empty($bbcode->context)) { return ''; } if (KunenaFactory::getTemplate()->isHmvc() && !$this->templateParams->get('X_Social')) { return false; } $tweetid = trim($content); if (!is_numeric($tweetid)) { return false; } // Display tag in activity streams etc.. if (!empty($bbcode->parent->forceMinimal)) { return "<a href=\"https://x.com/kunena/status/" . $tweetid . "\" rel=\"nofollow\" target=\"_blank\">" . Text::_('COM_KUNENA_LIB_BBCODE_TWEET_STATUS_LINK') . "</a>"; } return $this->renderTweet($tweetid); } /** * Render the tweet by loading the right layout * * @param int $tweetid The tweet id to render in layout * * @return string * * @since Kunena 6.0 * @throws \Exception */ public function renderTweet(int $tweetid): string { $tweet = $this->getTweet($tweetid); $layout = KunenaLayout::factory('BBCode/x'); if ($tweet->error === false) { if ($layout->getPath()) { return (string) $layout ->set('tweetid', $tweet->id_str) ->set('user_profile_url_normal', $tweet->user->profile_image_url) ->set('user_profile_url_big', $tweet->user->profile_image_url_big) ->set('user_name', $tweet->user->name) ->set('user_screen_name', $tweet->user->screen_name) ->set('tweet_created_at', $tweet->created_at) ->set('tweet_text', $tweet->text) ->set('retweet_count', $tweet->retweet_count) ->set('favorite_count', $tweet->favorite_count) ->set('verified', $tweet->user->verified) ->setLayout('default'); } } else { return '<b>' . $tweet->error . '</b>'; } return false; } /** * Get JSON tweet data by using OAuth 2.0 authentication * * @param int $tweetid The tweet ID to query against twitter API * * @return object * * @since Kunena 6.0 * @throws Exception */ protected function getTweet(int $tweetid) { // FIXME: use AJAX instead... $uri = Uri::getInstance(); $consumer_key = trim($this->config->XConsumerKey); $consumer_secret = trim($this->config->XConsumerSecret); if (is_file(JPATH_CACHE . '/kunena_tweet/kunenatweetdisplay-' . $tweetid . '.json')) { $tweet_data = file_get_contents(JPATH_CACHE . '/kunena_tweet/kunenatweetdisplay-' . $tweetid . '.json'); if ($tweet_data !== false) { return json_decode($tweet_data); } } if (!empty($consumer_key) && !empty($consumer_secret) && empty($this->token)) { $bearer_token_credentials = $consumer_key . ":" . $consumer_secret; $b64_bearer_token_credentials = base64_encode($bearer_token_credentials); $url = 'https://api.twitter.com/oauth2/token'; $options = new Registry(); $transport = new StreamTransport($options); // Create a 'stream' transport. $http = new Http($options, $transport); $headers = [ 'Authorization' => "Basic " . $b64_bearer_token_credentials, ]; $data = "grant_type=client_credentials"; $response = $http->post($url, $data, $headers, '10'); if ($response->code == 200) { $this->token = json_decode($response->body)->access_token; } else { $tweet = new stdClass(); $tweet->error = Text::_('COM_KUNENA_LIB_BBCODE_X_SOCIAL_COULD_NOT_GET_TOKEN'); return $tweet; } } elseif (empty($consumer_key) || empty($consumer_secret)) { $tweet = new stdClass(); $tweet->error = Text::_('COM_KUNENA_LIB_BBCODE_X_SOCIAL_CONSUMMER_KEY_SECRET_INVALID'); return $tweet; } if (!empty($this->token)) { $url = 'https://api.twitter.com/1.1/statuses/show.json?id=' . $tweetid; $options = new Registry(); $transport = new StreamTransport($options); // Create a 'stream' transport. $http = new Http($options, $transport); $headers = [ 'Authorization' => "Bearer " . $this->token, ]; $response = $http->get($url, $headers, '10'); if ($response->code == 200) { $tweet_data = json_decode($response->body); if ($uri->isSSL()) { $tweet_data->user->profile_image_url = $tweet_data->user->profile_image_url_https; } $tweet_data->user->profile_image_url_big = str_replace('normal', 'bigger', $tweet_data->user->profile_image_url); if (!empty($tweet_data->entities->urls)) { foreach ($tweet_data->entities->urls as $url) { if (isset($url->display_url)) { $d_url = $url->display_url; } else { $d_url = $url->url; } // We need to check to verify that the URL has the protocol, just in case if (strpos($url->url, 'http') !== 0) { // Prepend http since there's no protocol $link = 'http://' . $url->url; } else { $link = $url->url; } $tweet_data->text = str_replace($url->url, '<a href="' . $link . '" target="_blank" rel="nofollow noopener noreferrer">' . $d_url . '</a>', $tweet_data->text); } } if (!empty($tweet_data->entities->user_mentions)) { foreach ($tweet_data->entities->user_mentions as $mention) { $tweet_data->text = str_replace('@' . $mention->screen_name, '<a href="https://x.com/' . $mention->screen_name . '" target="_blank" rel="nofollow noopener noreferrer">@' . $mention->screen_name . '</a>', $tweet_data->text); } } if (!empty($tweet_data->entities->hashtags)) { foreach ($tweet_data->entities->hashtags as $hashtag) { $tweet_data->text = str_replace('#' . $hashtag->text, '<a href="https://x.com/hashtag/' . $hashtag->text . '?src=hash" target="_blank" rel="nofollow noopener noreferrer">#' . $hashtag->text . '</a>', $tweet_data->text); } } if (!empty($tweet_data->extended_entities->media)) { foreach ($tweet_data->extended_entities->media as $media) { $tweet_data->text = str_replace($tweet_data->extended_entities->media[0]->url, '', $tweet_data->text); if ($media->type == 'photo') { if ($uri->isSSL()) { $tweet_data->text .= '<img loading=lazy src="' . $media->media_url_https . '" alt="tweet" />'; } else { $tweet_data->text .= '<img loading=lazy src="' . $media->media_url . '" alt="tweet" />'; } } elseif ($media->type == 'video') { if ($uri->isSSL()) { $tweet_data->text .= '<a href="' . $media->url . '"><img loading=lazy src="' . $media->media_url_https . '" alt="tweet" /></a>'; } else { $tweet_data->text .= '<a href="' . $media->url . '"><img loading=lazy src="' . $media->media_url . '" alt="tweet" /></a>'; } } elseif ($media->type == 'animated_gif') { if ($uri->isSSL()) { $tweet_data->text .= '<a href="' . $media->url . '"><img loading=lazy src="' . $media->media_url_https . '" alt="tweet" /></a>'; } else { $tweet_data->text .= '<a href="' . $media->url . '"><img loading=lazy src="' . $media->media_url . '" alt="tweet" /></a>'; } } } } if (!is_dir(JPATH_CACHE . '/kunena_tweet')) { Folder::create(JPATH_CACHE . '/kunena_tweet'); } $tweet_data->error = false; file_put_contents(JPATH_CACHE . '/kunena_tweet/kunenatweetdisplay-' . $tweetid . '.json', json_encode($tweet_data)); return $tweet_data; } else { $tweet = new stdClass(); $tweet->error = Text::_('COM_KUNENA_LIB_BBCODE_X_SOCIAL_INVALID_TWEET_ID'); return $tweet; } } return false; } /** * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.0 */ public function DoSoundcloud($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { return true; } if (!empty($content)) { // Display tag in activity streams etc.. if (!empty($bbcode->parent->forceMinimal)) { return "<a href=\"" . $content . "\" rel=\"nofollow\" target=\"_blank\">" . $content . '</a>'; } $content = strip_tags($content); $url = trim($content); if (!preg_match('#^(/|https?:|ftp:)#ui', $url)) { // Add scheme to raw domain URLs. $url = "https://{$content}"; } $url_parsed = parse_url($url); if ($url_parsed['host'] == 'soundcloud.com') { return '<iframe allowtransparency="true" width="100%" height="350" style="border: 0" src="https://w.soundcloud.com/player/?url=' . $content . '&auto_play=false&visual=true"></iframe><br />'; } } return false; } /** * Handle private bbcode tag in the message * * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.0 * @throws Exception */ public function DoPrivate($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { return true; } if (!empty($bbcode->lost_start_tags[$name]) && !$bbcode->was_limited) { return "[{$name}]{$content}"; } // Display nothing in activity streams etc.. if (!empty($bbcode->parent->forceSecure)) { return ''; } // Display nothing in subscription mails if (!empty($bbcode->context)) { return ''; } $moderator = $this->me->userid && $this->me->isModerator($message ? $message->getCategory() : null); return '<div class="kmsgtext-confidentialguests">' . Text::_('COM_KUNENA_BBCODE_SECURE_TEXT_GUESTS') . '</div>'; } /** * Handle mention bbcode tag in the message * * @param mixed $bbcode bbcode * @param mixed $action action * @param mixed $name name * @param mixed $default default * @param mixed $params params * @param mixed $content content * * @return boolean|string * * @since Kunena 6.3 * @throws Exception */ public function DoMention($bbcode, $action, $name, $default, $params, $content) { if ($action == BBCode::BBCODE_CHECK) { return true; } $user = KunenaUserHelper::get($params['userid']); $urlUserProfile = $user->getURL(); return '<a href="' . $urlUserProfile . '" data-bs-toggle="tooltip" title="' . $content . '">@' . $content . '</a>'; } }
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0.01 |
proxy
|
phpinfo
|
ÐаÑтройка