Your IP : 18.191.22.141
<?php
/**
* Bitrix Framework
* @package bitrix
* @subpackage main
* @copyright 2001-2023 Bitrix
*/
use Bitrix\Main\Config\Option;
use Bitrix\Main\Localization\Loc;
use Bitrix\Main\Web\Uri;
use Bitrix\Main\UrlPreview\UrlPreview;
use Bitrix\Main\Application;
class CTextParser
{
public $type = 'html';
public $serverName = '';
public $preg;
public $imageWidth = 800;
public $imageHeight = 800;
public $maxStringLen = 0;
public $maxAnchorLength = 40;
//https://www.w3.org/TR/CSS2/fonts.html#propdef-font-size
public $arFontSize = [
1 => 'xx-small',
2 => 'small',
3 => 'medium',
4 => 'large',
5 => 'x-large',
6 => 'xx-large',
];
public $allow = [
'HTML' => 'N',
'ANCHOR' => 'Y',
'BIU' => 'Y',
'IMG' => 'Y',
'QUOTE' => 'Y',
'CODE' => 'Y',
'FONT' => 'Y',
'LIST' => 'Y',
'EMOJI' => 'Y',
'SMILES' => 'Y',
'CLEAR_SMILES' => 'N',
'NL2BR' => 'N',
'VIDEO' => 'Y',
'TABLE' => 'Y',
'CUT_ANCHOR' => 'N',
'SHORT_ANCHOR' => 'N',
'TEXT_ANCHOR' => 'Y',
'ALIGN' => 'Y',
'USERFIELDS' => 'N',
'USER' => 'Y',
'PROJECT' => 'Y',
'DEPARTMENT' => 'Y',
'P' => 'Y',
'TAG' => 'N',
'SPOILER' => 'Y',
];
public $anchorType = 'html';
public $smiles = null;
public $smilesGallery = CSmileGallery::GALLERY_DEFAULT;
public $bMobile = false;
public $LAZYLOAD = 'N';
public $parser_nofollow = 'N';
public $link_target = '_blank';
public $authorName = '';
public $pathToUser = '';
public $pathToUserEntityType = false;
public $pathToUserEntityId = false;
protected $wordSeparator = "\\s.,;:!?\\#\\-\\*\\|\\[\\]\\(\\)\\{\\}";
protected $smilePatterns = null;
protected $smileReplaces = null;
protected static $repoSmiles = [];
protected $defended_urls = [];
protected $anchorSchemes = null;
protected $userField;
protected $tagPattern = "/([\s]+|^)#([^\s,\.\[\]<>]+)/is";
protected $pathToSmile = '';
protected $ajaxPage;
protected $code_open = 0;
protected $code_error = 0;
protected $code_closed = 0;
protected $quote_open = 0;
protected $quote_error = 0;
protected $quote_closed = 0;
public function __construct()
{
global $APPLICATION;
$this->ajaxPage = $APPLICATION->GetCurPageParam('', ['bxajaxid', 'logout']);
}
public function getAnchorSchemes()
{
if ($this->anchorSchemes === null)
{
static $schemes = null;
if ($schemes === null)
{
$schemes = Option::get('main', '~parser_anchor_schemes', 'http|https|news|ftp|aim|mailto|file|tel|callto|skype|viber');
}
$this->anchorSchemes = $schemes;
}
return $this->anchorSchemes;
}
public function setAnchorSchemes($schemes)
{
$this->anchorSchemes = $schemes;
}
protected function initSmiles()
{
if (!array_key_exists($this->smilesGallery, self::$repoSmiles))
{
$smiles = CSmile::getByGalleryId(CSmile::TYPE_SMILE, $this->smilesGallery);
$arSmiles = [];
foreach ($smiles as $smile)
{
$arTypings = explode(' ', $smile['TYPING']);
foreach ($arTypings as $typing)
{
$arSmiles[] = array_merge($smile, [
'TYPING' => $typing,
'IMAGE' => CSmile::PATH_TO_SMILE . $smile['SET_ID'] . '/' . $smile['IMAGE'],
'DESCRIPTION' => $smile['NAME'],
'DESCRIPTION_DECODE' => 'Y',
]);
}
}
self::$repoSmiles[$this->smilesGallery] = $arSmiles;
}
$this->smiles = self::$repoSmiles[$this->smilesGallery];
}
protected function initSmilePatterns()
{
$this->smilePatterns = [];
$this->smileReplaces = [];
$pre = '';
foreach ($this->smiles as $row)
{
if (preg_match("/\\w\$/", $row['TYPING']))
{
$pre .= '|' . preg_quote($row['TYPING'], '/');
}
}
foreach ($this->smiles as $row)
{
if ($row['TYPING'] != '' && $row['IMAGE'] != '')
{
$code = str_replace(["'", "<", ">"], ["\\'", "<", ">"], $row["TYPING"]);
$patt = preg_quote($code, "/");
$code = preg_quote(str_replace(["\x5C"], ["\"], $code));
$image = preg_quote(str_replace("'", "\\'", $row["IMAGE"]));
$description = preg_quote(htmlspecialcharsbx(str_replace(["\x5C"], ["\"], $row["DESCRIPTION"]), ENT_QUOTES), "/");
$patternName = 'pattern' . count($this->smilePatterns);
$this->smilePatterns[] = "/(?<=^|\\>|[" . $this->wordSeparator . "\\&]" . $pre . ")(?P<" . $patternName . ">$patt)(?=$|\\<|[" . $this->wordSeparator . "\\&])/s" . BX_UTF_PCRE_MODIFIER;
$this->smileReplaces[$patternName] = [
'code' => $code,
'image' => $image,
'description' => $description,
'width' => intval($row['IMAGE_WIDTH']),
'height' => intval($row['IMAGE_HEIGHT']),
'descriptionDecode' => $row['DESCRIPTION_DECODE'] == 'Y',
'imageDefinition' => $row['IMAGE_DEFINITION'] ?: CSmile::IMAGE_SD
];
}
}
usort($this->smilePatterns, function($a, $b) { return (mb_strlen($a) > mb_strlen($b) ? -1 : 1); });
}
protected static function chr($a)
{
return \Bitrix\Main\Text\Encoding::convertEncoding($a, 'cp1251', SITE_CHARSET);
}
public function convertText($text)
{
if (!is_string($text) || $text == '')
{
return '';
}
$text = preg_replace(["#([?&;])PHPSESSID=([0-9a-zA-Z]{32})#i", "/\\x{00A0}/" . BX_UTF_PCRE_MODIFIER], ["\\1PHPSESSID1=", " "], $text);
$this->defended_urls = [];
if ($this->serverName == '' && $this->type == 'rss')
{
$dbSite = CSite::GetByID(SITE_ID);
$arSite = $dbSite->Fetch();
$serverName = $arSite['SERVER_NAME'];
if ($serverName == '')
{
if (defined('SITE_SERVER_NAME') && SITE_SERVER_NAME != '')
{
$serverName = SITE_SERVER_NAME;
}
else
{
$serverName = COption::GetOptionString('main', 'server_name');
}
}
if ($serverName != '')
{
$this->serverName = 'http://' . $serverName;
}
}
$this->preg = ['counter' => 0, 'pattern' => [], 'replace' => [], 'cache' => []];
foreach (GetModuleEvents('main', 'TextParserBefore', true) as $arEvent)
{
ExecuteModuleEventEx($arEvent, [&$text, &$this]);
}
if (($this->allow['CODE'] ?? '') == 'Y')
{
$text = preg_replace_callback(
[
"#(\\[code(?:\\s+[^]]*]|]))(.+?)(\\[/code(?:\\s+[^]]*]|]))#is" . BX_UTF_PCRE_MODIFIER,
"#(<code(?:\\s+[^>]*>|>))(.+?)(</code(?:\\s+[^>]*>|>))#is" . BX_UTF_PCRE_MODIFIER
],
[$this, 'convertCode'],
$text
);
}
if (($this->allow['HTML'] ?? '') != 'Y' && ($this->allow['NL2BR'] ?? '') == 'Y')
{
$text = preg_replace("#<br(.*?)>#is", "\n", $text);
}
if (($this->allow['HTML'] ?? '') != 'Y')
{
// ��� ��� ����������!
if (($this->allow['ANCHOR'] ?? '') == 'Y')
{
$text = preg_replace(
[
"#<a[^>]+href\\s*=\\s*(['\"])(.+?)(?:\\1)[^>]*>(.*?)</a[^>]*>#is" . BX_UTF_PCRE_MODIFIER,
"#<a[^>]+href(\\s*=\\s*)([^'\">]+)>(.*?)</a[^>]*>#is" . BX_UTF_PCRE_MODIFIER
],
"[url=\\2]\\3[/url]", $text
);
}
if (($this->allow['BIU'] ?? '') == 'Y')
{
$replaced = 0;
do
{
$text = preg_replace(
"/<([busi])[^>a-z]*>(.+?)<\\/(\\1)[^>a-z]*>/is" . BX_UTF_PCRE_MODIFIER,
"[\\1]\\2[/\\1]",
$text, -1, $replaced);
}
while ($replaced > 0);
}
if (($this->allow['P'] ?? '') == 'Y')
{
$replaced = 0;
do
{
$text = preg_replace(
"/<p[^>a-z]*>(.+?)<\\/p[^>a-z]*>/is" . BX_UTF_PCRE_MODIFIER,
"[p]\\1[/p]",
$text, -1, $replaced);
}
while ($replaced > 0);
}
if (($this->allow['IMG'] ?? '') == 'Y')
{
$text = preg_replace(
"#<img[^>]+src\\s*=[\\s'\"]*(((http|https|ftp)://[.\\-_:a-z0-9@]+)*(/[-_/=:.a-z0-9@{}&?%]+)+)[\\s'\"]*[^>]*>#is" . BX_UTF_PCRE_MODIFIER,
"[img]\\1[/img]", $text
);
}
if (($this->allow['FONT'] ?? '') == 'Y')
{
$text = preg_replace(
[
"/<font[^>]+size\\s*=[\\s'\"]*([0-9]+)[\\s'\"]*[^>]*>(.+?)<\\/font[^>]*>/is" . BX_UTF_PCRE_MODIFIER,
"/<font[^>]+color\\s*=[\\s'\"]*(#[a-f0-9]{6})[^>]*>(.+?)<\\/font[^>]*>/is" . BX_UTF_PCRE_MODIFIER,
"/<font[^>]+face\\s*=[\\s'\"]*([a-z\\s\\-]+)[\\s'\"]*[^>]*>(.+?)<\\/font[^>]*>/is" . BX_UTF_PCRE_MODIFIER,
],
[
"[size=\\1]\\2[/size]",
"[color=\\1]\\2[/color]",
"[font=\\1]\\2[/font]",
],
$text
);
}
if (($this->allow['LIST'] ?? '') == 'Y')
{
$text = preg_replace(
[
"/<ul((\\s[^>]*)|(\\s*))>(.+?)<\\/ul([^>]*)>/is" . BX_UTF_PCRE_MODIFIER,
"/<ol((\\s[^>]*)|(\\s*))>(.+?)<\\/ol([^>]*)>/is" . BX_UTF_PCRE_MODIFIER,
"/<li((\\s[^>]*)|(\\s*))>(.+?)<\\/li([^>]*)>/is" . BX_UTF_PCRE_MODIFIER,
"/<li((\\s[^>]*)|(\\s*))>/is" . BX_UTF_PCRE_MODIFIER,
],
[
"[list]\\4[/list]",
"[list=1]\\4[/list]",
"[*]\\4",
"[*]",
],
$text
);
}
if (($this->allow['TABLE'] ?? '') == 'Y')
{
$text = preg_replace(
[
"/<table((\\s[^>]*)|(\\s*))>/is" . BX_UTF_PCRE_MODIFIER,
"/<\\/table([^>]*)>/is" . BX_UTF_PCRE_MODIFIER,
"/<tr((\\s[^>]*)|(\\s*))>/is" . BX_UTF_PCRE_MODIFIER,
"/<\\/tr([^>]*)>/is" . BX_UTF_PCRE_MODIFIER,
"/<td((\\s[^>]*)|(\\s*))>/is" . BX_UTF_PCRE_MODIFIER,
"/<\\/td([^>]*)>/is" . BX_UTF_PCRE_MODIFIER,
"/<th((\\s[^>]*)|(\\s*))>/is" . BX_UTF_PCRE_MODIFIER,
"/<\\/th([^>]*)>/is" . BX_UTF_PCRE_MODIFIER,
],
[
"[table]",
"[/table]",
"[tr]",
"[/tr]",
"[td]",
"[/td]",
"[th]",
"[/th]",
],
$text
);
}
if (($this->allow['QUOTE'] ?? '') == 'Y')
{
$text = preg_replace("#<(/?)quote(.*?)>#is", "[\\1quote]", $text);
}
if (preg_match("/<cut/is" . BX_UTF_PCRE_MODIFIER, $text, $matches))
{
$text = preg_replace(
"/<cut([^>]*)>(.+?)<\/cut>/is" . BX_UTF_PCRE_MODIFIER,
"[cut=\\1]\\2[/cut]",
$text);
}
if ($text != '')
{
if ($this->preg['counter'] > 0)
{
$res = mb_strlen((string)$this->preg['counter']);
$p = ['\d'];
while (($res--) > 1)
{
$p[] = '\d{' . ($res + 1) . '}';
}
$text = preg_replace(
["/<(?!\017#(" . implode(")|(", $p) . ")>)/", "/(?<!<\017#(" . implode(")|(", $p) . "))>/", "/\"/"],
["<", ">", """],
$text
);
}
else
{
$text = str_replace(
["<", ">", "/\"/"],
["<", ">", """],
$text
);
}
}
}
$patt = [];
if (($this->allow['VIDEO'] ?? '') == 'Y')
{
$patt[] = "/\\[video([^\\]]*)\\](.+?)\\[\\/video[\\s]*\\]/is" . BX_UTF_PCRE_MODIFIER;
}
if (($this->allow['IMG'] ?? '') == 'Y')
{
$patt[] = "/\\[img([^\\]]*)\\](.+?)\\[\\/img\\]/is" . BX_UTF_PCRE_MODIFIER;
}
foreach (GetModuleEvents('main', 'TextParserBeforeAnchorTags', true) as $arEvent)
{
ExecuteModuleEventEx($arEvent, [&$text, &$this]);
}
if (($this->allow['ANCHOR'] ?? '') == 'Y')
{
$patt[] = "/\\[url\\](.*?)\\[\\/url\\]/i" . BX_UTF_PCRE_MODIFIER;
$patt[] = "/\\[url\\s*=\\s*(
(?:
[^\\[\\]]++
|\\[ (?: (?>[^\\[\\]]+) | (?:\\1) )* \\]
)+
)\\s*\\](.*?)\\[\\/url\\]/ixs" . BX_UTF_PCRE_MODIFIER;
$text = preg_replace_callback($patt, [$this, 'preconvertAnchor'], $text);
if (($this->allow['TEXT_ANCHOR'] ?? 'Y') == 'Y')
{
$schemes = $this->getAnchorSchemes();
$boundaries = [
'<' => '>',
'(' => ')', // doubtful
self::chr("�") => self::chr("�"),
self::chr("�") => self::chr("�"),
self::chr("�") => self::chr("�"),
];
$patt = [];
foreach ($boundaries as $start => $end)
{
if (str_contains($text, $start))
{
$patt[] = "/(?<=" . preg_quote($start) . ")(?<!\\[nomodify\\]|<nomodify>)((((" . $schemes . "):\\/\\/)|www\\.)[._:a-z0-9@-].*?)(?=" . preg_quote($end) . ")/is" . BX_UTF_PCRE_MODIFIER;
}
}
$patt[] = "/(?<=^|[" . $this->wordSeparator . "])(?<!\\[nomodify\\]|<nomodify>)((((" . $schemes . "):\\/\\/)|www\\.)[._:a-z0-9@-].*?)(?=[\\s\"{}]|"|\$)/is" . BX_UTF_PCRE_MODIFIER;
$text = preg_replace_callback($patt, [$this, 'preconvertUrl'], $text);
}
}
elseif (!empty($patt))
{
$text = preg_replace_callback($patt, [$this, 'preconvertAnchor'], $text);
}
$text = preg_replace("/<\\/?nomodify>/i" . BX_UTF_PCRE_MODIFIER, '', $text);
if (($this->allow['SPOILER'] ?? '') === 'Y')
{
if (preg_match("/\\[(cut|spoiler)/is" . BX_UTF_PCRE_MODIFIER, $text, $matches))
{
$text = preg_replace(
[
"/\\[(cut|spoiler)(([^]])*)]/is" . BX_UTF_PCRE_MODIFIER,
"/\\[\\/(cut|spoiler)]/is" . BX_UTF_PCRE_MODIFIER
],
[
"\001\\2\002",
"\003"
],
$text
);
while (preg_match("/(\001([^\002]*)\002([^\001\002\003]+)\003)/is" . BX_UTF_PCRE_MODIFIER, $text, $matches))
{
$text = preg_replace_callback("/\001([^\002]*)\002([^\001\002\003]+)\003/is" . BX_UTF_PCRE_MODIFIER, [ $this, 'convert_spoiler_tag' ], $text);
}
$text = preg_replace(
[
"/\001([^\002]+)\002/",
"/\001\002/",
"/\003/"
],
[
"[spoiler\\1]",
"[spoiler]",
"[/spoiler]"
],
$text
);
}
}
foreach (GetModuleEvents('main', 'TextParserBeforeTags', true) as $arEvent)
{
ExecuteModuleEventEx($arEvent, [&$text, &$this]);
}
if (
($this->allow['SMILES'] ?? '') == 'Y'
|| ($this->allow['CLEAR_SMILES'] ?? '') == 'Y'
)
{
if (str_contains($text, "<nosmile>"))
{
$text = preg_replace_callback(
"/<nosmile>(.*?)<\\/nosmile>/is" . BX_UTF_PCRE_MODIFIER,
[$this, "defendTags"],
$text
);
}
if ($this->smiles === null)
{
$this->initSmiles();
}
if (!empty($this->smiles))
{
if ($this->smilePatterns === null)
{
$this->initSmilePatterns();
}
if (!empty($this->smilePatterns))
{
$text = preg_replace_callback($this->smilePatterns, [$this, 'convertEmoticon'], ' ' . $text . ' ');
}
}
}
$text = $this->post_convert_anchor_tag($text);
if (!isset($this->allow['EMOJI']) || $this->allow['EMOJI'] != 'N')
{
$text = \Bitrix\Main\Text\Emoji::decode($text);
}
$res = array_merge(
[
'VIDEO' => 'N',
'IMG' => 'N',
'ANCHOR' => 'N',
'BIU' => 'N',
'LIST' => 'N',
'FONT' => 'N',
'TABLE' => 'N',
'ALIGN' => 'N',
'QUOTE' => 'N',
'P' => 'Y',
],
$this->allow
);
foreach ($res as $tag => $val)
{
if ($val != 'Y')
{
continue;
}
if (str_contains($text, '<nomodify>'))
{
$text = preg_replace_callback(
"/<nomodify>(.*?)<\\/nomodify>/is" . BX_UTF_PCRE_MODIFIER,
[$this, "defendTags"],
$text
);
}
switch ($tag)
{
case 'VIDEO':
$text = preg_replace_callback(
"/\\[video([^]]*)](.+?)\\[\\/video\\s*]/is" . BX_UTF_PCRE_MODIFIER,
[$this, 'convertVideo'],
$text
);
break;
case 'IMG':
$text = preg_replace_callback(
"/\\[img([^]]*)](.+?)\\[\\/img]/is" . BX_UTF_PCRE_MODIFIER,
[$this, 'convertImage'],
$text
);
break;
case 'ANCHOR':
$arUrlPatterns = [
"/\\[url\\](.*?)\\[\\/url\\]/i" . BX_UTF_PCRE_MODIFIER,
"/\\[url\\s*=\\s*(
(?:
[^\\[\\]]++
|\\[ (?: (?>[^\\[\\]]+) | (?:\\1) )* \\]
)+
)\\s*\\](.*?)\\[\\/url\\]/ixs" . BX_UTF_PCRE_MODIFIER,
];
if (($this->allow['CUT_ANCHOR'] ?? '') != 'Y')
{
$text = preg_replace_callback(
$arUrlPatterns,
[$this, 'convertAnchor'],
$text
);
}
else
{
$text = preg_replace($arUrlPatterns, '', $text);
}
break;
case 'BIU':
$replaced = 0;
do
{
$text = preg_replace(
"/\\[([busi])](.*?)\\[\\/(\\1)]/is" . BX_UTF_PCRE_MODIFIER,
"<\\1>\\2</\\1>",
$text, -1, $replaced);
}
while ($replaced > 0);
break;
case 'P':
$replaced = 0;
do
{
$text = preg_replace(
"/\\[p](.*?)\\[\\/p](([ \r\t]*)\n?)/is" . BX_UTF_PCRE_MODIFIER,
"<p>\\1</p>",
$text, -1, $replaced);
}
while ($replaced > 0);
break;
case 'LIST':
while (preg_match("/\\[list\\s*=\\s*([1a])\\s*](.+?)\\[\\/list]/is" . BX_UTF_PCRE_MODIFIER, $text))
{
$text = preg_replace(
[
"/\\[list\\s*=\\s*1\\s*](\\s*)(.+?)\\[\\/list](([\040\\r\\t]*)\\n?)/is" . BX_UTF_PCRE_MODIFIER,
"/\\[list\\s*=\\s*a\\s*](\\s*)(.+?)\\[\\/list](([\040\\r\\t]*)\\n?)/is" . BX_UTF_PCRE_MODIFIER,
"/\\[\\*]/" . BX_UTF_PCRE_MODIFIER,
],
[
"<ol>\\2</ol>",
"<ol type=\"a\">\\2</ol>",
"<li>",
],
$text
);
}
while (preg_match("/\\[list](.+?)\\[\\/list](([\\040\\r\\t]*)\\n?)/is" . BX_UTF_PCRE_MODIFIER, $text))
{
$text = preg_replace(
[
"/\\[list](\\s*)(.+?)\\[\\/list](([\\040\\r\\t]*)\\n?)/is" . BX_UTF_PCRE_MODIFIER,
"/\\[\\*]/" . BX_UTF_PCRE_MODIFIER,
],
[
"<ul>\\2</ul>",
"<li>",
],
$text
);
}
break;
case 'FONT':
while (preg_match("/\\[size\\s*=\\s*([^]]+)](.*?)\\[\\/size]/is" . BX_UTF_PCRE_MODIFIER, $text))
{
$text = preg_replace_callback(
"/\\[size\\s*=\\s*([^]]+)](.*?)\\[\\/size]/is" . BX_UTF_PCRE_MODIFIER,
[$this, 'convertFontSize'],
$text
);
}
while (preg_match("/\\[font\\s*=\\s*([^]]+)](.*?)\\[\\/font]/is" . BX_UTF_PCRE_MODIFIER, $text))
{
$text = preg_replace_callback(
"/\\[font\\s*=\\s*([^]]+)](.*?)\\[\\/font]/is" . BX_UTF_PCRE_MODIFIER,
[$this, 'convertFont'],
$text
);
}
while (preg_match("/\\[color\\s*=\\s*([^]]+)](.*?)\\[\\/color]/is" . BX_UTF_PCRE_MODIFIER, $text))
{
$text = preg_replace_callback(
"/\\[color\\s*=\\s*([^]]+)](.*?)\\[\\/color]/is" . BX_UTF_PCRE_MODIFIER,
[$this, 'convertFontColor'],
$text
);
}
break;
case 'TABLE':
while (preg_match("/\\[table]/is" . BX_UTF_PCRE_MODIFIER, $text))
{
$tagToCheckList = ['td', 'th', 'tr', 'table'];
foreach ($tagToCheckList as $tagToCheck)
{
preg_match_all("/\\[" . $tagToCheck . "]/is" . BX_UTF_PCRE_MODIFIER, $text, $matches);
$opentags = count($matches['0']);
preg_match_all("/\\[\\/" . $tagToCheck . "]/is", $text, $matches);
$closetags = count($matches['0']);
$unclosed = $opentags - $closetags;
if ($unclosed > 0)
{
$text .= str_repeat('[/' . $tagToCheck . ']', $unclosed);
}
}
$openTableTag = (
$this->bMobile
? "<div style=\"overflow-x: auto;\"><table class=\"data-table\">"
: "<table class=\"data-table\">"
);
$closeTableTag = (
$this->bMobile
? '</table></div>'
: '</table>'
);
$text = preg_replace(
[
"/\\[table]/is" . BX_UTF_PCRE_MODIFIER,
"/\\[\\/table](?:(?:[\\040\\r\\t]*)\\n?)/is" . BX_UTF_PCRE_MODIFIER,
"/(\\s*?)\\[tr]/is" . BX_UTF_PCRE_MODIFIER,
"/\\[\\/tr](\\s*?)/is" . BX_UTF_PCRE_MODIFIER,
"/(\\s*?)\\[td]/is" . BX_UTF_PCRE_MODIFIER,
"/\\[\\/td](\\s*?)/is" . BX_UTF_PCRE_MODIFIER,
"/(\\s*?)\\[th]/is" . BX_UTF_PCRE_MODIFIER,
"/\\[\\/th](\\s*?)/is" . BX_UTF_PCRE_MODIFIER,
],
[
$openTableTag,
$closeTableTag,
'<tr>',
'</tr>',
'<td>',
'</td>',
'<th>',
'</th>',
],
$text
);
}
break;
case 'ALIGN':
$replaced = 0;
do
{
$text = preg_replace(
[
"/\\[left](.*?)\\[\\/left](([\\040\\r\\t]*)\\n?)/is" . BX_UTF_PCRE_MODIFIER,
"/\\[right](.*?)\\[\\/right](([\\040\\r\\t]*)\\n?)/is" . BX_UTF_PCRE_MODIFIER,
"/\\[center](.*?)\\[\\/center](([\\040\\r\\t]*)\\n?)/is" . BX_UTF_PCRE_MODIFIER,
"/\\[justify](.*?)\\[\\/justify](([\\040\\r\\t]*)\\n?)/is" . BX_UTF_PCRE_MODIFIER,
],
[
"<div align=\"left\">\\1</div>",
"<div align=\"right\">\\1</div>",
"<div align=\"center\">\\1</div>",
"<div align=\"justify\">\\1</div>",
],
$text,
-1,
$replaced
);
}
while ($replaced > 0);
break;
case 'QUOTE':
while (preg_match("/\\[quote[^]]*](.*?)\\[\\/quote[^]]*]/is" . BX_UTF_PCRE_MODIFIER, $text))
{
$text = preg_replace_callback(
"/\\[quote[^]]*](.*?)\\[\\/quote[^]]*](([\\040\\r\\t]*)\\n?)/is" . BX_UTF_PCRE_MODIFIER,
[$this, 'convertQuote'],
$text
);
}
break;
}
}
if (preg_match("/\[cut/is" . BX_UTF_PCRE_MODIFIER, $text, $matches))
{
$text = preg_replace(
[
"/\[cut(([^]])*)]/is" . BX_UTF_PCRE_MODIFIER,
"/\[\/cut]/is" . BX_UTF_PCRE_MODIFIER,
],
[
"\001\\1\002",
"\003",
],
$text
);
$text = preg_replace_callback(
"/(\001([^\002]*)\002([^\001\002\003]+)\003)/is" . BX_UTF_PCRE_MODIFIER,
function($matches) {
return $this->convert_cut_tag($matches[3], $matches[2]);
},
$text
);
$text = preg_replace(
[
"/\001([^\002]+)\002/",
"/\001\002/",
"/\003/",
],
[
"[cut\\1]",
"[cut]",
"[/cut]",
],
$text
);
}
if (str_contains($text, '<nomodify>'))
{
$text = preg_replace_callback(
"/<nomodify>(.*?)<\\/nomodify>/is" . BX_UTF_PCRE_MODIFIER,
[$this, 'defendTags'],
$text
);
}
if (isset($this->allow['USERFIELDS']) && is_array($this->allow['USERFIELDS']))
{
foreach ($this->allow['USERFIELDS'] as $userField)
{
if (is_array($userField['USER_TYPE']) && array_key_exists('TAG', $userField['USER_TYPE']) )
{
$userField['TAG'] = $userField['USER_TYPE']['TAG'];
}
if (empty($userField['TAG']))
{
switch($userField['USER_TYPE_ID'])
{
case 'webdav_element' :
$userField['TAG'] = 'DOCUMENT ID';
break;
case 'vote' :
$userField['TAG'] = 'VOTE ID';
break;
}
}
if (!empty($userField['TAG']) && array_key_exists('VALUE', $userField) && !empty($userField['VALUE']) &&
method_exists($userField['USER_TYPE']['CLASS_NAME'], 'GetPublicViewHTML') )
{
$userField['VALUE'] = (is_array($userField['VALUE']) ? $userField['VALUE'] : [$userField['VALUE']]);
$this->userField = $userField;
$text = preg_replace_callback(
"/\\[(" . (is_array($userField["TAG"]) ? implode("|", $userField["TAG"]) : $userField["TAG"]) . ")\\s*=\\s*([a-z0-9]+)([^]]*)]/is" . BX_UTF_PCRE_MODIFIER,
[$this, 'convert_userfields'],
$text
);
}
}
}
if (!isset($this->allow['USER']) || $this->allow['USER'] != 'N')
{
do
{
$textOriginal = $text;
$text = preg_replace_callback(
"/\[user\s*=\s*([^]]*)]((?:(?!\[user\s*=\s*[^]]*]).)+?)\[\/user]/is" . BX_UTF_PCRE_MODIFIER,
[$this, 'convert_user'],
$text
);
}
while ($textOriginal !== $text);
}
if (!isset($this->allow['PROJECT']) || $this->allow['PROJECT'] !== 'N')
{
$text = preg_replace_callback(
"/\[project\s*=\s*([^]]*)](.+?)\[\/project]/is" . BX_UTF_PCRE_MODIFIER,
[ $this, 'convert_project' ],
$text
);
}
if (!isset($this->allow['DEPARTMENT']) || $this->allow['DEPARTMENT'] !== 'N')
{
$text = preg_replace_callback(
"/\[department\s*=\s*([^]]*)](.+?)\[\/department]/is" . BX_UTF_PCRE_MODIFIER,
[ $this, 'convert_department' ],
$text
);
}
if (isset($this->allow['TAG']) && $this->allow['TAG'] == 'Y')
{
$text = preg_replace_callback(
$this->getTagPattern(),
[$this, 'convert_tag'],
$text
);
}
foreach (GetModuleEvents('main', 'TextParserAfterTags', true) as $arEvent)
{
ExecuteModuleEventEx($arEvent, [&$text, &$this]);
}
if (($this->allow['HTML'] ?? '') != 'Y' || ($this->allow['NL2BR'] ?? '') == 'Y')
{
$text = str_replace(["\r\n", "\n"], "<br />", $text);
$text = preg_replace(
[
"/<br \\/>[\\t\\s]*(<\\/table[^>]*>)/is" . BX_UTF_PCRE_MODIFIER,
"/<br \\/>[\\t\\s]*(<thead[^>]*>)/is" . BX_UTF_PCRE_MODIFIER,
"/<br \\/>[\\t\\s]*(<\\/thead[^>]*>)/is" . BX_UTF_PCRE_MODIFIER,
"/<br \\/>[\\t\\s]*(<tfoot[^>]*>)/is" . BX_UTF_PCRE_MODIFIER,
"/<br \\/>[\\t\\s]*(<\\/tfoot[^>]*>)/is" . BX_UTF_PCRE_MODIFIER,
"/<br \\/>[\\t\\s]*(<tbody[^>]*>)/is" . BX_UTF_PCRE_MODIFIER,
"/<br \\/>[\\t\\s]*(<\\/tbody[^>]*>)/is" . BX_UTF_PCRE_MODIFIER,
"/<br \\/>[\\t\\s]*(<tr[^>]*>)/is" . BX_UTF_PCRE_MODIFIER,
"/<br \\/>[\\t\\s]*(<\\/tr[^>]*>)/is" . BX_UTF_PCRE_MODIFIER,
"/<br \\/>[\\t\\s]*(<td[^>]*>)/is" . BX_UTF_PCRE_MODIFIER,
"/<br \\/>[\\t\\s]*(<\\/td[^>]*>)/is" . BX_UTF_PCRE_MODIFIER,
],
"\\1",
$text
);
}
$text = str_replace(
[
"(c)", "(C)",
"(tm)", "(TM)", "(Tm)", "(tM)",
"(r)", "(R)",
],
[
"©", "©",
"™", "™", "™", "™",
"®", "®",
],
$text
);
if (($this->allow['HTML'] ?? '') != 'Y')
{
if ($this->maxStringLen > 0)
{
$text = preg_replace("/(&#\\d{1,3};)/is" . BX_UTF_PCRE_MODIFIER, "<\019\\1>", $text);
$text = preg_replace_callback("/(?<=^|>)([^<>\\[]+?)(?=<|\\[|$)/is" . BX_UTF_PCRE_MODIFIER, [$this, "partWords"], $text);
$text = preg_replace("/(<\019((&#\\d{1,3};))>)/is" . BX_UTF_PCRE_MODIFIER, "\\2", $text);
}
$text = preg_replace_callback("/(?<=^|>)([^<>\\[]+?)(?=<|\\[|$)/is" . BX_UTF_PCRE_MODIFIER, [$this, "parseSpaces"], $text);
}
foreach (GetModuleEvents('main', 'TextParserBeforePattern', true) as $arEvent)
{
ExecuteModuleEventEx($arEvent, [&$text, &$this]);
}
if ($this->preg['counter'] > 0)
{
$text = str_replace(array_reverse($this->preg['pattern']), array_reverse($this->preg['replace']), $text);
}
foreach (GetModuleEvents('main', 'TextParserAfter', true) as $arEvent)
{
ExecuteModuleEventEx($arEvent, [&$text, &$this]);
}
return trim($text);
}
public function defendTags($matches)
{
return $this->defended_tags($matches[1]);
}
public function defended_tags($text, $tag = 'replace')
{
$text = str_replace("\\\"", "\"", $text);
switch ($tag)
{
case 'replace':
if (($k = array_search($text, $this->preg['replace'])) !== false)
{
$text = "<\017#" . $k . ">";
break;
}
$this->preg["pattern"][] = "<\017#" . $this->preg["counter"] . ">";
$this->preg["replace"][] = $text;
$text = "<\017#" . $this->preg["counter"] . ">";
$this->preg["counter"]++;
break;
}
return $text;
}
public function convert4mail($text)
{
$text = trim($text);
if ($text == '')
{
return '';
}
$arPattern = [];
$arReplace = [];
$arPattern[] = "/\\[(code|quote)(.*?)\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "\n>================== \\1 ===================\n";
$arPattern[] = "/\\[\\/(code|quote)(.*?)\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "\n>===========================================\n";
$arPattern[] = "/\\<WBR[\\s\\/]?\\>/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "";
$arPattern[] = "/\\[\\*\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "- ";
$arPattern[] = "/^(\r|\n)+?(.*)$/";
$arReplace[] = "\\2";
$arPattern[] = "/\\[b\\](.+?)\\[\\/b\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "\\1";
$arPattern[] = "/\\[p\\](.*?)\\[\\/p\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "\\1";
$arPattern[] = "/\\[i\\](.+?)\\[\\/i\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "\\1";
$arPattern[] = "/\\[u\\](.+?)\\[\\/u\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "_\\1_";
$arPattern[] = "/\\[s\\](.+?)\\[\\/s\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "_\\1_";
$arPattern[] = "/\\[(\\/?)(color|font|size|left|right|center)([^\\]]*)\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "";
$arPattern[] = "/\\[url\\](\\S+?)\\[\\/url\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "(URL: \\1 )";
$arPattern[] = "/\\[url\\s*=\\s*(\\S+?)\\s*\\](.*?)\\[\\/url\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "\\2 (URL: \\1 )";
$arPattern[] = "/\\[img([^\\]]*)\\](.+?)\\[\\/img\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "(IMAGE: \\2)";
$arPattern[] = "/\\[video([^\\]]*)\\](.+?)\\[\\/video[\\s]*\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "(VIDEO: \\2)";
$arPattern[] = "/\\[(\\/?)list(.*?)\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "\n";
$arPattern[] = "/\\[user([^\\]]*)\\](.+?)\\[\\/user\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "\\2";
$arPattern[] = "/\\[project([^\\]]*)\\](.+?)\\[\\/project\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "\\2";
$arPattern[] = "/\\[department([^\\]]*)\\](.+?)\\[\\/department\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "\\2";
$arPattern[] = "/\\[DOCUMENT([^\\]]*)\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "";
$arPattern[] = "/\\[DISK(.+?)\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "";
$arPattern[] = "/\\[(table)(.*?)\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "\n>================== \\1 ===================";
$arPattern[] = "/\\[\\/table(.*?)\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "\n>===========================================\n";
$arPattern[] = "/\\[tr\\]\\s*/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "\n";
$arPattern[] = "/\\[(\\/?)(tr|td)\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "";
$text = preg_replace($arPattern, $arReplace, $text);
$text = str_replace('­', '', $text);
if (preg_match("/\[cut(([^]])*)]/is" . BX_UTF_PCRE_MODIFIER, $text))
{
$text = preg_replace(
[
"/\[cut(([^]])*)]/is" . BX_UTF_PCRE_MODIFIER,
"/\[\/cut]/is" . BX_UTF_PCRE_MODIFIER,
],
[
"\001\\1\002",
"\003",
],
$text
);
while (preg_match("/(\001([^\002]*)\002([^\001\002\003]+)\003)/is" . BX_UTF_PCRE_MODIFIER, $text))
{
$text = preg_replace(
"/(\001([^\002]*)\002([^\001\002\003]+)\003)/is" . BX_UTF_PCRE_MODIFIER,
"\n>================== CUT ===================\n\\3\n>==========================================\n",
$text
);
}
$text = preg_replace(
[
"/\001([^\002]+)\002/",
"/\001\002/",
"/\003/",
],
[
"[cut\\1]",
"[cut]",
"[/cut]",
],
$text
);
}
static $replacements = [
" " => " ",
""" => "\"",
"\" => "\\",
"$" => "\$",
"!" => "!",
"[" => "[",
"]" => "]",
"'" => "'",
"<" => "<",
">" => ">",
"|" => '|',
"&" => "&",
];
$text = strtr($text, $replacements);
return $text;
}
public function convertVideo($matches)
{
$params = $matches[1];
$path = $matches[2];
if ($path == '')
{
return '';
}
$width = '';
$height = '';
$preview = '';
$provider = '';
$type = '';
preg_match("/width=([0-9]+)/is" . BX_UTF_PCRE_MODIFIER, $params, $width);
preg_match("/height=([0-9]+)/is" . BX_UTF_PCRE_MODIFIER, $params, $height);
preg_match("/preview='([^']+)'/is" . BX_UTF_PCRE_MODIFIER, $params, $preview);
if (empty($preview))
{
preg_match("/preview=\"([^\"]+)\"/is" . BX_UTF_PCRE_MODIFIER, $params, $preview);
}
preg_match("/type=(YOUTUBE|RUTUBE|VIMEO|VK|FACEBOOK|INSTAGRAM)/is" . BX_UTF_PCRE_MODIFIER, $params, $provider);
preg_match("/mimetype='([^']+)'/is" . BX_UTF_PCRE_MODIFIER, $params, $type);
$width = intval($width[1] ?? 0);
$width = ($width > 0 ? $width : 400);
$height = intval($height[1] ?? 0);
$height = ($height > 0 ? $height : 300);
$preview = trim($preview[1] ?? '');
$preview = ($preview != '' ? $preview : '');
$provider = isset($provider[1])? mb_strtoupper(trim($provider[1])) : '';
$type = trim($type[1] ?? '');
$arFields = [
'PATH' => $path,
'WIDTH' => $width,
'HEIGHT' => $height,
'PREVIEW' => $preview,
'TYPE' => $provider,
'MIME_TYPE' => $type,
'PARSER_OBJECT' => $this,
];
foreach (GetModuleEvents('main', 'TextParserVideoConvert', true) as $arEvent)
{
ExecuteModuleEventEx($arEvent, [&$arFields, &$this]);
}
$video = $this->convert_video($arFields);
return $this->defended_tags($video);
}
protected function convert_video($arParams)
{
global $APPLICATION;
if (
!is_array($arParams)
|| $arParams["PATH"] == ''
)
{
return false;
}
$trustedProviders = [
'YOUTUBE',
'RUTUBE',
'VIMEO',
'VK',
'FACEBOOK',
'INSTAGRAM',
];
ob_start();
if ($this->type == 'mail')
{
$pathEncoded = htmlspecialcharsbx($arParams['PATH']);
?><a href="<?=$pathEncoded?>"><?=$pathEncoded?></a><?
}
elseif (in_array($arParams['TYPE'], $trustedProviders))
{
// add missing protocol to get host
if (mb_substr($arParams['PATH'], 0, 2) == '//')
{
$arParams['PATH'] = 'http:' . $arParams['PATH'];
}
$uri = new Uri($arParams['PATH']);
if (UrlPreview::isHostTrusted($uri) || $uri->getHost() == Application::getInstance()->getContext()->getServer()->getServerName())
{
// Replace http://someurl, https://someurl by //someurl
$arParams['PATH'] = preg_replace("/https?:\\/\\//i", '//', $arParams['PATH']);
$pathEncoded = htmlspecialcharsbx($arParams['PATH']);
if ($this->bMobile)
{
?><iframe class="bx-mobile-video-frame" src="<?=$pathEncoded?>" allowfullscreen="" frameborder="0" height="100%" width="100%" style="max-width: 600px; min-height: 300px;"></iframe><?
}
else
{
?><iframe src="<?=$pathEncoded?>" allowfullscreen="" frameborder="0" height="<?=intval($arParams["HEIGHT"])?>" width="<?=intval($arParams["WIDTH"])?>" style="max-width: 100%;"></iframe><?
}
}
}
else
{
$playerParams = $arParams;
$playerParams['TYPE'] = $arParams['MIME_TYPE'];
$playerComponent = 'bitrix:player';
if ($this->bMobile)
{
$playerComponent = 'bitrix:mobile.player';
}
$APPLICATION->IncludeComponent(
$playerComponent, '', $playerParams,
null,
[
'HIDE_ICONS' => 'Y',
]
);
}
return ob_get_clean();
}
public function convertEmoticon($matches)
{
$array = array_intersect_key($this->smileReplaces, $matches);
$replacement = reset($array);
if (!empty($replacement))
{
if (($this->allow['CLEAR_SMILES'] ?? '') == 'Y')
{
return $this->convert_emoticon($replacement['code']);
}
else
{
return $this->convert_emoticon(
$replacement['code'],
$replacement['image'],
$replacement['description'],
$replacement['width'],
$replacement['height'],
$replacement['descriptionDecode'],
$replacement['imageDefinition']
);
}
}
return $matches[0];
}
public function convert_emoticon($code = '', $image = '', $description = '', $width = '', $height = '', $descriptionDecode = false, $imageDefinition = CSmile::IMAGE_SD)
{
if ($code == '' || $image == '')
{
return '';
}
$code = stripslashes($code);
$description = stripslashes($description);
$image = stripslashes($image);
$width = intval($width);
$height = intval($height);
if ($descriptionDecode)
{
$description = htmlspecialcharsback($description);
}
$html = '<img src="' . htmlspecialcharsbx($this->serverName) . $this->pathToSmile . $image . '"'
. ' border="0"'
. ' data-code="' . $code . '"'
. ' data-definition="' . $imageDefinition . '"'
. ' alt="' . $code . '"'
. ' style="' . ($width > 0 ? 'width:' . $width . 'px;' : '') . ($height > 0 ? 'height:' . $height . 'px;' : '') . '"'
. ' title="' . $description . '"'
. ' class="bx-smile" />';
$cacheKey = md5($html);
if (!isset($this->preg['cache'][$cacheKey]))
{
$this->preg['cache'][$cacheKey] = $this->defended_tags($html);
}
return $this->preg['cache'][$cacheKey];
}
public function convertCode($matches)
{
$text = $matches[2];
if ($text == '')
{
return '';
}
$text = str_replace(
["[nomodify]", "[/nomodify]", "[", "]", "&", "<", ">", "\\r", "\\n", "\\\"", "\\", "[", "]", " ", "\t"],
["", "", "[", "]", "&", "<", ">", "\r", "\n", '\"', "\", "[", "]", " ", " "],
$text
);
$text = stripslashes($text);
return $this->defended_tags($this->convert_open_tag('code') . "<pre>" . $text . "</pre>" . $this->convert_close_tag('code'));
}
public function convertQuote($matches)
{
return $this->convert_quote_tag($matches[1]);
}
public function convert_quote_tag($text = '')
{
if ($text == '')
{
return '';
}
$text = str_replace("\\\"", "\"", $text);
return $this->convert_open_tag() . $text . $this->convert_close_tag();
}
public function convert_spoiler_tag($text, $title = '')
{
if (is_array($text))
{
$title = $text[1];
$text = $text[2];
}
if (empty($text))
{
return '';
}
$title = htmlspecialcharsbx(trim(htmlspecialcharsback($title), " =\"\\'"));
if ($this->type === 'mail')
{
return "<dl><dt>" . ($title ?: Loc::getMessage("MAIN_TEXTPARSER_SPOILER")) . "</dt><dd>" . htmlspecialcharsbx($text) . "</dd></dl>";
}
return self::renderSpoiler($text, $title);
}
function convert_cut_tag($text, $title = '')
{
if (empty($text))
{
return '';
}
$title = trim($title);
$title = ltrim($title, '=');
$title = trim($title);
return self::renderSpoiler($text, $title);
}
public static function renderSpoiler($text, $title = '')
{
$title = (empty($title) ? Loc::getMessage("MAIN_TEXTPARSER_HIDDEN_TEXT") : $title);
ob_start();
?><table class="forum-spoiler"><?
?><thead onclick="if (this.nextSibling.style.display=='none') { this.nextSibling.style.display=''; BX.addClass(this, 'forum-spoiler-head-open'); } else { this.nextSibling.style.display='none'; BX.removeClass(this, 'forum-spoiler-head-open'); } BX.onCustomEvent('BX.Forum.Spoiler:toggle', [{node: this}]); event.stopPropagation();"><?
?><tr><?
?><th><?
?><div><?=htmlspecialcharsbx($title)?></div><?
?></th><?
?></tr><?
?></thead><?
?><tbody class="forum-spoiler" style="display:none;"><?
?><tr><?
?><td><?=$text?></td><?
?></tr><?
?></tbody><?
?></table><?
return ob_get_clean();
}
public function convert_open_tag($marker = 'quote')
{
$marker = (mb_strtolower($marker) == 'code' ? 'code' : 'quote');
$this->{$marker . '_open'}++;
if ($this->type == 'rss')
{
return "\n====" . $marker . "====\n";
}
return "<div class='" . $marker . "'><table class='" . $marker . "'><tr><td>";
}
public function convert_close_tag($marker = 'quote')
{
$marker = (mb_strtolower($marker) == 'code' ? 'code' : 'quote');
if ($this->{$marker . '_open'} == 0)
{
$this->{$marker . '_error'}++;
return '';
}
$this->{$marker . '_closed'}++;
if ($this->type == 'rss')
{
return "\n=============\n";
}
return '</td></tr></table></div>';
}
public function convertImage($matches)
{
return $this->convert_image_tag($matches[2], $matches[1]);
}
public function convert_image_tag($url = '', $params = '')
{
$url = trim($url);
if ($url == '')
{
return '';
}
preg_match("/width=([0-9]+)/is" . BX_UTF_PCRE_MODIFIER, $params, $width);
preg_match("/height=([0-9]+)/is" . BX_UTF_PCRE_MODIFIER, $params, $height);
$width = intval($width[1] ?? 0);
$height = intval($height[1] ?? 0);
$bErrorIMG = false;
if (!preg_match("/^(http|https|ftp|\\/)/i" . BX_UTF_PCRE_MODIFIER, $url))
{
$bErrorIMG = true;
}
$url = htmlspecialcharsbx($url);
if ($bErrorIMG)
{
return '[img]' . $url . '[/img]';
}
$strPar = '';
if ($width > 0)
{
if ($width > $this->imageWidth)
{
$height = intval($height * ($this->imageWidth / $width));
$width = $this->imageWidth;
}
}
if ($height > 0)
{
if ($height > $this->imageHeight)
{
$width = intval($width * ($this->imageHeight / $height));
$height = $this->imageHeight;
}
}
if ($width > 0)
{
$strPar = " width=\"" . $width . "\"";
}
if ($height > 0)
{
$strPar .= " height=\"" . $height . "\"";
}
$serverName = htmlspecialcharsbx($this->serverName);
$image = '<img src="' . $serverName . $url . '" border="0"' . $strPar . ' data-bx-image="' . $serverName . $url . '" data-bx-onload="Y" />';
if ($this->serverName == '' || preg_match("/^(http|https|ftp):\\/\\//i" . BX_UTF_PCRE_MODIFIER, $url))
{
$image = '<img src="' . $url . '" border="0"' . $strPar . ' data-bx-image="' . $url . '" data-bx-onload="Y" />';
}
return $this->defended_tags($image);
}
public function convertFont($matches)
{
return $this->convert_font_attr('font', $matches[1], $matches[2]);
}
public function convertFontSize($matches)
{
return $this->convert_font_attr('size', $matches[1], $matches[2]);
}
public function convertFontColor($matches)
{
return $this->convert_font_attr('color', $matches[1], $matches[2]);
}
public function stripAllTags($text)
{
return preg_replace('|[[/!]*?[^\\[\\]]*?]|i', '', $text);
}
public function convert_font_attr($attr, $value = "", $text = "")
{
if ($text == '')
{
return '';
}
$text = str_replace("\\\"", "\"", $text);
if ($value == '')
{
return $text;
}
if ($attr == 'size')
{
if (mb_strlen($value) > 2 && mb_substr($value, -2) == 'pt')
{
$value = intval(mb_substr($value, 0, -2));
if ($value <= 0)
{
return $text;
}
return '<span class="bx-font" style="font-size:' . $value . 'pt; line-height: normal;">' . $text . '</span>';
}
$count = count($this->arFontSize);
if ($count <= 0)
{
return $text;
}
$value = intval($value > $count ? ($count - 1) : $value);
//compatibility with old percent values
$size = (is_numeric($this->arFontSize[$value])? $this->arFontSize[$value] . '%' : $this->arFontSize[$value]);
return '<span class="bx-font" style="font-size:' . $size . ';">' . $text . '</span>';
}
elseif ($attr == 'color')
{
$value = preg_replace("/[^\\w#]/", "" , $value);
return '<span class="bx-font" style="color:' . $value . '">' . $text . '</span>';
}
elseif ($attr == 'font')
{
$value = preg_replace("/[^\\w\\s\\-,()]/", "" , $value);
return '<span class="bx-font" style="font-family:' . $value . '">' . $text . '</span>';
}
return '';
}
public function convert_userfields($matches)
{
$vars = get_object_vars($this);
$vars['TEMPLATE'] = ($this->bMobile ? 'mobile' : $this->type);
$vars['LAZYLOAD'] = $this->LAZYLOAD;
$userField = $this->userField;
$id = $matches[2];
foreach (GetModuleEvents('main', 'TextParserUserField', true) as $arEvent)
{
ExecuteModuleEventEx($arEvent, [$id, &$userField, &$vars, &$this]);
}
if ($userField['USER_TYPE']['USER_TYPE_ID'] == 'disk_file' || in_array($id, $userField['VALUE']))
{
if (defined('BX_COMP_MANAGED_CACHE'))
{
global $CACHE_MANAGER;
$CACHE_MANAGER->RegisterTag('webdav_element_internal_' . $id);
}
return call_user_func_array(
[$userField['USER_TYPE']['CLASS_NAME'], 'GetPublicViewHTML'],
[$userField, $id, $matches[3], $vars, $matches]
);
}
return $matches[0];
}
public function convert_user($userId = 0, $userName = '')
{
static $userTypeList = [];
if (is_array($userId))
{
$userName = $userId[2];
$userId = $userId[1];
}
$userId = (int)$userId;
$renderParams = [
'USER_ID' => $userId,
'USER_NAME' => $userName,
];
if ($userId > 0)
{
$type = false;
if (isset($userTypeList[$userId]))
{
$type = $userTypeList[$userId];
}
else
{
if (\Bitrix\Main\Loader::includeModule('intranet'))
{
$res = \Bitrix\Intranet\UserTable::getList([
'filter' => [
'ID' => $userId
],
'select' => [
'USER_TYPE'
]
]);
if ($userFields = $res->fetch())
{
$type = $userFields['USER_TYPE'];
}
}
$userTypeList[$userId] = $type;
}
$pathToUser = (
!empty($this->userPath)
? $this->userPath // forum
: $this->pathToUser
);
if (empty($pathToUser))
{
$pathToUser = COption::GetOptionString('main', 'TOOLTIP_PATH_TO_USER', '', SITE_ID);
}
switch($type)
{
case 'extranet':
$classAdditional = ' blog-p-user-name-extranet';
break;
case 'email':
$classAdditional = ' blog-p-user-name-email';
$pathToUser .= '';
if (
$this->pathToUserEntityType && $this->pathToUserEntityType != ''
&& (int)$this->pathToUserEntityId > 0
)
{
$pathToUser .= (!str_contains($pathToUser, '?') ? '?' : '&') . 'entityType=' . $this->pathToUserEntityType . '&entityId=' . intval($this->pathToUserEntityId);
}
break;
default:
$classAdditional = '';
}
$renderParams = [
'CLASS_ADDITIONAL' => $classAdditional,
'PATH_TO_USER' => $pathToUser,
'USER_ID' => $userId,
'USER_NAME' => $userName,
];
if (
$type === 'email'
&& !empty($this->pathToUserEntityType)
&& !empty($this->pathToUserEntityId)
)
{
$renderParams['TOOLTIP_PARAMS'] = \Bitrix\Main\Web\Json::encode([
'entityType' => $this->pathToUserEntityType,
'entityId' => (int)$this->pathToUserEntityId,
]);
}
}
$res = $this->render_user($renderParams);
return $this->defended_tags($res);
}
protected function render_user($fields)
{
$classAdditional = (!empty($fields['CLASS_ADDITIONAL']) ? $fields['CLASS_ADDITIONAL'] : '');
$pathToUser = (!empty($fields['PATH_TO_USER']) ? $fields['PATH_TO_USER'] : '');
$userId = (!empty($fields['USER_ID']) ? $fields['USER_ID'] : '');
$userName = (!empty($fields['USER_NAME']) ? $fields['USER_NAME'] : '');
if (empty($userId))
{
return "<span class=\"blog-p-user-name\">{$userName}</span>";
}
return '<a class="blog-p-user-name' . $classAdditional . '"'
. ' href="' . CComponentEngine::MakePathFromTemplate($pathToUser, ["user_id" => $userId]) . '"'
. ' bx-tooltip-user-id="' . (!$this->bMobile ? $userId : '') . '"'
. (!empty($fields['TOOLTIP_PARAMS']) ? ' bx-tooltip-params="' . htmlspecialcharsbx($fields['TOOLTIP_PARAMS']) . '"' : '') . '>'
. $userName . '</a>';
}
public function convert_project(array $matches): string
{
static $projectTypeList = [];
static $extranetProjectIdList = null;
static $pathToProject = null;
$projectName = $matches[2];
$projectId = (int)$matches[1];
$renderParams = [
'PROJECT_ID' => $projectId,
'PROJECT_NAME' => $projectName,
];
if ($projectId > 0)
{
if ($extranetProjectIdList === null)
{
$extranetSiteId = (\Bitrix\Main\Loader::includeModule('extranet') ? CExtranet::getExtranetSiteId() : '');
if (!empty($extranetSiteId))
{
$res = \Bitrix\Socialnetwork\WorkgroupSiteTable::getList([
'filter' => [
'=SITE_ID' => $extranetSiteId,
],
'select' => [ 'GROUP_ID' ],
]);
while ($projectSiteFields = $res->fetch())
{
$extranetProjectIdList[] = (int)$projectSiteFields['GROUP_ID'];
}
}
}
$type = false;
if (isset($projectTypeList[$projectId]))
{
$type = $projectTypeList[$projectId];
}
else
{
if (!empty($extranetProjectIdList))
{
$type = (in_array($projectId, $extranetProjectIdList, true) ? 'extranet' : false);
}
$projectTypeList[$projectId] = $type;
}
if ($pathToProject === null)
{
// then replace to \Bitrix\Socialnetwork\Helper\Path::get('group_path_template')
$pathToProject = Option::get('socialnetwork', 'group_path_template', SITE_DIR . 'workgroups/group/#group_id#/', SITE_ID);
}
switch ($type)
{
case 'extranet':
$classAdditional = ' blog-p-user-name-extranet';
break;
default:
$classAdditional = '';
}
$renderParams['CLASS_ADDITIONAL'] = $classAdditional;
$renderParams['PATH_TO_PROJECT'] = $pathToProject;
}
$res = $this->render_project($renderParams);
return $this->defended_tags($res);
}
protected function render_project($fields): string
{
$classAdditional = ($fields['CLASS_ADDITIONAL'] ?? '');
$pathToProject = ($fields['PATH_TO_PROJECT'] ?? '');
$projectId = (int)($fields['PROJECT_ID'] ?? 0);
$projectName = (string)($fields['PROJECT_NAME'] ?? '');
if ($projectId <= 0)
{
return "<span class=\"blog-p-user-name\">{$projectName}</span>";
}
return '<a class="blog-p-user-name' . $classAdditional . '" href="' . CComponentEngine::MakePathFromTemplate($pathToProject, [ 'group_id' => $projectId ]) . '" >' . $projectName . '</a>';
}
public function convert_department(array $matches): string
{
static $pathToDepartment = null;
$departmentName = $matches[2];
$departmentId = (int)$matches[1];
$renderParams = [
'DEPARTMENT_ID' => $departmentId,
'DEPARTMENT_NAME' => $departmentName,
];
if ($departmentId > 0)
{
if ($pathToDepartment === null)
{
// then replace to \Bitrix\Socialnetwork\Helper\Path::get('department_path_template')
$pathToDepartment = Option::get('main', 'TOOLTIP_PATH_TO_CONPANY_DEPARTMENT', SITE_DIR . 'company/structure.php?set_filter_structure=Y&structure_UF_DEPARTMENT=#ID#', SITE_ID);
}
$renderParams['PATH_TO_DEPARTMENT'] = $pathToDepartment;
}
$res = $this->render_department($renderParams);
return $this->defended_tags($res);
}
protected function render_department($fields): string
{
$pathToDepartment = ($fields['PATH_TO_DEPARTMENT'] ?? '');
$departmentId = (int)($fields['DEPARTMENT_ID'] ?? 0);
$departmentName = (string)($fields['DEPARTMENT_NAME'] ?? '');
if ($departmentId <= 0)
{
return "<span class=\"blog-p-user-name\">{$departmentName}</span>";
}
return '<a class="blog-p-user-name" href="' . CComponentEngine::MakePathFromTemplate($pathToDepartment, [ 'ID' => $departmentId ]) . '" >' . $departmentName . '</a>';
}
public function getTagPattern()
{
return $this->tagPattern.BX_UTF_PCRE_MODIFIER;
}
public static function cleanTag($tag)
{
return trim(html_entity_decode(str_replace(' ', ' ', $tag), (ENT_COMPAT | ENT_HTML401), SITE_CHARSET));
}
public function detectTags($text)
{
$result = [];
$text = str_replace((Application::isUtfMode() ? "\xC2\xA0" : "\xA0"), ' ', $text);
if (preg_match_all($this->getTagPattern(), ' ' . $text, $matches))
{
$result = array_unique($matches[2]);
}
$result = array_map(
function($tag) { return CTextParser::cleanTag($tag); },
$result
);
$result = array_filter(
$result,
function($tag) { return $tag != ''; }
);
return $result;
}
public function convert_tag($tag = [])
{
$res = '';
if (
!is_array($tag)
|| $tag[2] == ''
)
{
return $res;
}
$tagText = self::cleanTag($tag[2]);
if ($tagText == '')
{
return $tag[0];
}
$res = htmlentities($tagText, (ENT_COMPAT | ENT_HTML401), SITE_CHARSET);
$res = '<span class="bx-inline-tag" bx-tag-value="' . $res . '">#' . $res . '</span>';
return $tag[1].$this->defended_tags($res);
}
// Only for public using
public function wrap_long_words($text = '')
{
if ($this->maxStringLen > 0 && !empty($text))
{
$text = str_replace([chr(11), chr(12), chr(34), chr(39)], ["", "", chr(11), chr(12)], $text);
$text = preg_replace_callback("/(?<=^|>)([^<]+)(?=<|$)/is" . BX_UTF_PCRE_MODIFIER, [$this, "partWords"], $text);
$text = str_replace([chr(11), chr(12)], [chr(34), chr(39)], $text);
}
return $text;
}
public function partWords($matches)
{
return $this->part_long_words($matches[1]);
}
public function part_long_words($str)
{
$word_separator = $this->wordSeparator;
if (($this->maxStringLen > 0) && (trim($str) != ''))
{
$str = str_replace(
[chr(1), chr(2), chr(3), chr(4), chr(5), chr(6), chr(7), chr(8),
"&", "<", ">", """, " ", "©", "®", "™",
chr(34), chr(39),
],
["", "", "", "", "", "", "", "",
chr(1), "<", ">", chr(2), chr(3), chr(4), chr(5), chr(6),
chr(7), chr(8),
],
$str
);
$str = preg_replace_callback(
"/(?<=[" . $word_separator . "]|^)(([^" . $word_separator . "]+))(?=[" . $word_separator . "]|$)/is" . BX_UTF_PCRE_MODIFIER,
[$this, "cutWords"],
$str
);
$str = str_replace(
[chr(1), "<", ">", chr(2), chr(3), chr(4), chr(5), chr(6), chr(7), chr(8), "<WBR/>", "<WBR>", "&shy;"],
["&", "<", ">", """, " ", "©", "®", "™", chr(34), chr(39), "<WBR/>", "<WBR/>", "­"],
$str
);
}
return $str;
}
public function cutWords($matches)
{
return $this->cut_long_words($matches[2]);
}
public function cut_long_words($str)
{
if (($this->maxStringLen > 0) && ($str != ''))
{
$str = preg_replace("/([^ \n\r\t\x01]{" . $this->maxStringLen . "})/is" . BX_UTF_PCRE_MODIFIER, "\\1<WBR/>­", $str);
}
return $str;
}
protected function parseSpaces($matches)
{
if ($matches[1] != '')
{
return preg_replace("/\x20{2}/", "\x20 ", $matches[1]);
}
return $matches[1];
}
public function convertAnchor($matches)
{
return $this->convert_anchor_tag($matches[1], (!empty($matches[2]) ? $matches[2] : $matches[1]));
}
public function convert_anchor_tag($url, $text)
{
$url = trim(str_replace(['[nomodify]', '[/nomodify]'], '', $url));
$text = trim(str_replace(['[nomodify]', '[/nomodify]'], '', $text));
$text = ($text == '' ? $url : $text);
$bTextUrl = ($text == $url);
$bShortUrl = (($this->allow['SHORT_ANCHOR'] ?? '') == 'Y');
$text = str_replace("\\\"", "\"", $text);
$postfix = "";
$pattern = "/([.,?!;]|!)$/" . BX_UTF_PCRE_MODIFIER;
if ($bTextUrl && preg_match($pattern, $url, $match))
{
$postfix = $match[1];
$url = preg_replace($pattern, '', $url);
$text = preg_replace($pattern, '', $text);
}
$url = preg_replace(
[
"/&/" . BX_UTF_PCRE_MODIFIER,
"/javascript:/i" . BX_UTF_PCRE_MODIFIER,
"/[" . chr(12) . "']/" . BX_UTF_PCRE_MODIFIER,
"/[/" . BX_UTF_PCRE_MODIFIER,
"/]/" . BX_UTF_PCRE_MODIFIER,
],
[
"&",
"java script: ",
"%27",
"[",
"]",
],
$url
);
if (mb_substr($url, 0, 1) != '/' && !preg_match("/^(" . $this->getAnchorSchemes() . "):/i" . BX_UTF_PCRE_MODIFIER, $url))
{
$url = 'http://' . $url;
}
$text = preg_replace(
["/&/i" . BX_UTF_PCRE_MODIFIER, "/javascript:/i" . BX_UTF_PCRE_MODIFIER],
["&", "javascript: "],
$text
);
if ($bShortUrl &&
mb_strlen($text) > $this->maxAnchorLength &&
preg_match("/^(" . $this->getAnchorSchemes() . "):\\/\\/(\\S+)$/i" . BX_UTF_PCRE_MODIFIER, $text, $matches))
{
$uri_type = $matches[1];
$stripped = $matches[2];
$text = $uri_type . '://' . (mb_strlen($stripped) > $this->maxAnchorLength ?
mb_substr($stripped, 0, $this->maxAnchorLength - 10) . '...' . mb_substr($stripped, -10) :
$stripped
);
}
if ($this->anchorType === 'bbcode')
{
if ($url === $text)
{
$link = '[URL]' . $url . '[/URL]';
}
else
{
$link = '[URL=' . $url . ']' . $text . '[/URL]';
}
}
else
{
$url = $this->defended_tags(htmlspecialcharsbx($url, ENT_COMPAT, false));
if (!str_contains($text, "<\017"))
{
// it could be "defended" tag inside URL code
$text = htmlspecialcharsbx($text, ENT_COMPAT, false);
}
$noFollowAttribute = $this->parser_nofollow == 'Y'? ' rel="nofollow"': '';
$link = '<a href="' . $url . '" target="' . $this->link_target . '"' . $noFollowAttribute . '>' . $text . '</a>';
if ($noFollowAttribute)
{
$link = '<noindex>' . $link . '</noindex>';
}
}
return $link . $postfix;
}
private function preconvertUrl($matches)
{
return $this->pre_convert_anchor_tag($matches[0], $matches[0], '[url]' . $matches[0] . '[/url]');
}
public function preconvertAnchor($matches)
{
return $this->pre_convert_anchor_tag($matches[1], $matches[2] ?? '', $matches[0] ?? '');
}
public function pre_convert_anchor_tag($url, $text = '', $str = '')
{
if (stripos($str, '[url') !== 0)
{
$url = $str;
}
elseif ($text != '')
{
$url = str_replace(['[', ']'], ['%5B', '%5D'], $url);
$url = '[url=' . $url . ']' . $text . '[/url]';
}
else
{
$url = '[url]' . $url . '[/url]';
}
if (isset($this->defended_urls[$url]))
{
return $this->defended_urls[$url];
}
else
{
$tag = "<\x18#" . count($this->defended_urls) . ">";
$this->defended_urls[$url] = $tag;
return $tag;
}
}
public function post_convert_anchor_tag($str)
{
if (!empty($this->defended_urls))
{
return str_replace(array_reverse(array_values($this->defended_urls)), array_reverse(array_keys($this->defended_urls)), $str);
}
return $str;
}
public function strip_words($string, $count)
{
$splice_pos = null;
$ar = preg_split("/(<.*?>|\\s+)/s", $string, -1, PREG_SPLIT_DELIM_CAPTURE);
foreach ($ar as $i => $s)
{
if (mb_substr($s, 0, 1) != '<')
{
$count -= mb_strlen($s);
if ($count <= 0)
{
$splice_pos = $i;
break;
}
}
}
if (isset($splice_pos))
{
array_splice($ar, $splice_pos+1);
return implode('', $ar);
}
return $string;
}
public static function closeTags($html)
{
preg_match_all("#<([a-z0-9]+)([^>]*)(?<!/)>#i" . BX_UTF_PCRE_MODIFIER, $html, $result);
$openedtags = array_map('strtolower', $result[1]);
preg_match_all("#</([a-z0-9]+)>#i" . BX_UTF_PCRE_MODIFIER, $html, $result);
$closedtags = array_map('strtolower', $result[1]);
$len_opened = count($openedtags);
if (count($closedtags) == $len_opened)
{
return $html;
}
$openedtags = array_reverse($openedtags);
static $tagsWithoutClose = ['input'=>1, 'img'=>1, 'br'=>1, 'hr'=>1, 'meta'=>1, 'area'=>1, 'base'=>1, 'col'=>1, 'embed'=>1, 'keygen'=>1, 'link'=>1, 'param'=>1, 'source'=>1, 'track'=>1, 'wbr'=>1];
for ($i = 0; $i < $len_opened; $i++)
{
if (isset($tagsWithoutClose[$openedtags[$i]]))
{
continue;
}
if (!in_array($openedtags[$i], $closedtags))
{
$html .= '</' . $openedtags[$i] . '>';
}
else
{
unset($closedtags[array_search($openedtags[$i], $closedtags)]);
}
}
return $html;
}
public static function clearAllTags($text)
{
$text = strip_tags(trim($text));
if ($text == '')
{
return '';
}
if (mb_stripos($text, '<cut') !== false || mb_stripos($text, '[cut') !== false)
{
$text = preg_replace([
"/^(.+?)<cut(.*?)>/is" . BX_UTF_PCRE_MODIFIER,
"/^(.+?)\\[cut(.*?)]/is" . BX_UTF_PCRE_MODIFIER,
], "\\1", $text);
}
if (mb_stripos($text, '[quote') !== false)
{
while (preg_match("/\\[(?:quote)(?:.*?)](.*?)\\[\\/quote(.*?)]/is" . BX_UTF_PCRE_MODIFIER, $text))
{
$text = preg_replace(
[
"/\\[quote(?:.*?)](.*?)\\[\\/quote(.*?)]/is" . BX_UTF_PCRE_MODIFIER,
"/<quote(?:.*?)>(.*?)<\\/quote(.*?)>/is" . BX_UTF_PCRE_MODIFIER,
],
"\"\\1\"",
$text
);
}
}
$text = preg_replace("/\\[url\\s*=\\s*(\\S+?)\\s*](.*?)\\[\\/url]/is" . BX_UTF_PCRE_MODIFIER, "\\2", $text);
$arPattern = [];
$arReplace = [];
$arPattern[] = "/\\<WBR[\\s\\/]?\\>/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "";
$arPattern[] = "/^(\r|\n)+?(.*)$/";
$arReplace[] = "\\2";
$arPattern[] = "/\\<(\\/?)(code|font|color|video)(.*?)\\>/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "";
$arPattern[] = "/\\[\\/td(.*?)\\]\\[td(.*?)\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = " ";
$arPattern[] = "/\\[(\\/?)(p|b|i|u|s|list|code|quote|size|font|color|url|img|video|td|tr|table|file|document id|disk file id|user|project|left|right|center|justify|\\*)(.*?)\\]/is" . BX_UTF_PCRE_MODIFIER;
$arReplace[] = "";
return preg_replace($arPattern, $arReplace, $text);
}
public function html_cut($html, $size)
{
$symbols = strip_tags($html);
$symbols_len = mb_strlen($symbols);
if ($symbols_len < mb_strlen($html))
{
$strip_text = $this->strip_words($html, $size);
if ($symbols_len > $size)
{
$strip_text = $strip_text . '...';
}
$final_text = $this->closetags($strip_text);
}
elseif ($symbols_len > $size)
{
$final_text = mb_substr($html, 0, $size) . '...';
}
else
{
$final_text = $html;
}
return $final_text;
}
public function convertHTMLToBB($html = '', $allow = null)
{
if (empty($html))
{
return $html;
}
$handler = AddEventHandler('main', 'TextParserBeforeTags', ['CTextParser', 'TextParserHTMLToBBHack']);
$this->allow = array_merge(
is_array($allow) ? $allow : [
'ANCHOR' => 'Y',
'BIU' => 'Y',
'IMG' => 'Y',
'QUOTE' => 'Y',
'CODE' => 'Y',
'FONT' => 'Y',
'LIST' => 'Y',
'SMILES' => 'Y',
'NL2BR' => 'Y',
'VIDEO' => 'Y',
'TABLE' => 'Y',
'ALIGN' => 'Y',
'P' => 'Y',
],
['HTML' => 'N']
);
$html = $this->convertText($html);
$html = preg_replace("/<br\s*\\/*>/is" . BX_UTF_PCRE_MODIFIER,"\n", $html);
$html = preg_replace("/ /is" . BX_UTF_PCRE_MODIFIER, '', $html);
RemoveEventHandler('main', 'TextParserBeforeTags', $handler);
return $html;
}
public static function TextParserHTMLToBBHack($text, $TextParser)
{
$TextParser->allow = [];
return true;
}
}