4use Bitrix\Im\Integration\Socialnetwork\Extranet;
5use Bitrix\Im\V2\Message\Text\BbCode\Timestamp;
6use Bitrix\Im\V2\Message\Text\BbCode\Timestamp\DateFormat;
7use Bitrix\Main\Localization\Loc;
8use Bitrix\Main\Type\DateTime;
10Loc::loadMessages(__FILE__);
14 private static $replacements = Array();
15 private static $parsers = Array();
17 private static $emojiList = [
18 "file" =>
':f09f938e:',
19 "image" =>
':f09f96bc:',
20 "audio" =>
':f09f9488:',
21 "video" =>
':f09f93ba:',
22 "code" =>
':f09f9384:',
23 "call" =>
':f09f939e:',
24 "attach" =>
':f09fa7a9:',
25 "quote" =>
':f09f92ac:',
30 $linkParam =
$params[
'LINK'] ??
null;
31 $smilesParam =
$params[
'SMILES'] ??
null;
32 $linkLimitParam =
$params[
'LINK_LIMIT'] ??
null;
33 $textLimitParam =
$params[
'TEXT_LIMIT'] ??
null;
34 $cutStrikeParam =
$params[
'CUT_STRIKE'] ??
null;
36 $parseId = md5($linkParam.$smilesParam.$linkLimitParam.$textLimitParam);
37 if (isset(self::$parsers[$parseId]))
39 $parser = self::$parsers[$parseId];
43 $parser = new \CTextParser();
45 $parser->maxStringLen = intval($textLimitParam);
47 $parser->anchorType =
'bbcode';
48 $parser->maxAnchorLength = intval($linkLimitParam)? $linkLimitParam: 55;
50 foreach ($parser->allow as $tag => $value)
52 $parser->allow[$tag] =
'N';
54 $parser->allow[
'EMOJI'] =
'Y';
55 $parser->allow[
'HTML'] =
'Y';
56 $parser->allow[
'ANCHOR'] =
'Y';
57 $parser->allow[
'TEXT_ANCHOR'] =
'Y';
59 self::$parsers[$parseId] = $parser;
62 $text = preg_replace_callback(
"/\[CODE\](.*?)\[\/CODE\]/si", Array(
'\Bitrix\Im\Text',
'setReplacement'),
$text);
63 $text = preg_replace_callback(
"/\[PUT(?:=(.+?))?\](.+?)?\[\/PUT\]/i", Array(
'\Bitrix\Im\Text',
'setReplacement'),
$text);
64 $text = preg_replace_callback(
"/\[SEND(?:=(.+?))?\](.+?)?\[\/SEND\]/i", Array(
'\Bitrix\Im\Text',
'setReplacement'),
$text);
65 $text = preg_replace_callback(
"/\[USER=([0-9]{1,})\]\[\/USER\]/i", Array(
'\Bitrix\Im\Text',
'modifyShortUserTag'),
$text);
67 if ($cutStrikeParam ===
'Y')
69 $text = preg_replace(
"/\[s\].*?\[\/s\]/i",
"",
$text);
74 $text = str_replace([
'<br />',
'#BR#',
'[br]'],
"\n",
$text);
75 $text = str_replace([
"©",
"™",
"®"], [
"(c)",
"(tm)",
"(r)"],
$text);
101 $safeParam =
$params[
'SAFE'] ??
null;
102 $linkParam =
$params[
'LINK'] ??
null;
103 $fontParam =
$params[
'FONT'] ??
null;
104 $smilesParam =
$params[
'SMILES'] ??
null;
105 $textAnchorParam =
$params[
'TEXT_ANCHOR'] ??
null;
106 $linkLimitParam =
$params[
'LINK_LIMIT'] ??
null;
107 $textLimitParam =
$params[
'TEXT_LIMIT'] ??
null;
108 $linkTargetSelfParam =
$params[
'LINK_TARGET_SELF'] ??
null;
109 $cutStrikeParam =
$params[
'CUT_STRIKE'] ??
null;
111 if (!$safeParam || $safeParam ===
'Y')
119 'ANCHOR' => $linkParam ===
'N' ?
'N' :
'Y',
124 'FONT' => $fontParam ===
'Y' ?
'Y' :
'N',
127 'SMILES' => $smilesParam ===
'N' ?
'N' :
'Y',
133 'SHORT_ANCHOR' =>
'N',
135 'TEXT_ANCHOR' => $textAnchorParam ===
'N' ?
'N' :
'Y',
138 $parseId = md5(
'legacy'.$linkParam.$smilesParam.$linkLimitParam.$textLimitParam.$linkTargetSelfParam);
139 if (isset(self::$parsers[$parseId]))
141 $parser = self::$parsers[$parseId];
145 $parser = new \CTextParser();
147 $parser->maxAnchorLength = intval($linkLimitParam)? $linkLimitParam: 55;
148 $parser->maxStringLen = intval($textLimitParam);
149 $parser->allow = $allowTags;
150 if ($linkTargetSelfParam ===
'Y')
152 $parser->link_target =
"_self";
155 self::$parsers[$parseId] = $parser;
158 $text = preg_replace_callback(
"/\[PUT(?:=(.+?))?\](.+?)?\[\/PUT\]/i", Array(
'\Bitrix\Im\Text',
'setReplacement'),
$text);
159 $text = preg_replace_callback(
"/\[SEND(?:=(.+?))?\](.+?)?\[\/SEND\]/i", Array(
'\Bitrix\Im\Text',
'setReplacement'),
$text);
160 $text = preg_replace_callback(
"/\[CODE\](.*?)\[\/CODE\]/si", Array(
'\Bitrix\Im\Text',
'setReplacement'),
$text);
161 $text = preg_replace_callback(
"/\[USER=([0-9]{1,})\]\[\/USER\]/i", Array(
'\Bitrix\Im\Text',
'modifyShortUserTag'),
$text);
163 if ($cutStrikeParam ===
'Y')
165 $text = preg_replace(
"/\[s\].*?\[\/s\]/i",
"",
$text);
181 $dates = self::getDateConverterParams(
$text);
188 'START' =>
$result->getTextPosition(),
193 return self::resolveIntersect($replaces);
196 private static function resolveIntersect(
array $segments):
array
198 usort($segments, fn(
array $segmentA,
array $segmentB) => $segmentA[
'START'] <=> $segmentB[
'START']);
203 foreach ($segments as $segment)
205 if ($segment[
'START'] > $maxEnd)
208 $maxEnd = $segment[
'END'];
224 $text = preg_replace_callback(
"/\[PUT(?:=(.+?))?\](.+?)?\[\/PUT\]/i", Array(
'\Bitrix\Im\Text',
'setReplacement'),
$text);
225 $text = preg_replace_callback(
"/\[SEND(?:=(.+?))?\](.+?)?\[\/SEND\]/i", Array(
'\Bitrix\Im\Text',
'setReplacement'),
$text);
226 $text = preg_replace_callback(
'/\[URL\=([^\]]*)\]([^\]]*)\[\/URL\]/i', Array(
'\Bitrix\Im\Text',
'setReplacement'),
$text);
227 $text = preg_replace_callback(
'/(https?):\/\/(([a-z0-9$_\.\+!\*\'\(\),;\?&=-]|%[0-9a-f]{2})+(:([a-z0-9$_\.\+!\*\'\(\),;\?&=-]|%[0-9a-f]{2})+)?@)?(?#)((([a-z0-9]\.|[a-z0-9][a-z0-9-]*[a-z0-9]\.)*[a-z][a-z0-9-]*[a-z0-9]|((\d|[1-9]\d|1\d{2}|2[0-4][0-9]|25[0-5])\.){3}(\d|[1-9]\d|1\d{2}|2[0-4][0-9]|25[0-5]))(:\d+)?)(((\/+([a-z0-9$_\.\+!\*\'\(\),;:@&=-]|%[0-9a-f]{2})*)*(\?([a-z0-9$_\.\+!\*\'\(\),;:@&=-]|%[0-9a-f]{2})*)?)?)?(#([a-z0-9$_\.\+!\*\'\(\),;:@&=-]|%[0-9a-f]{2})*)?/im', Array(
'\Bitrix\Im\Text',
'setReplacement'),
$text);
228 $text = preg_replace_callback(
'#\-{54}(.+?)\-{54}#s', Array(
'\Bitrix\Im\Text',
'setReplacement'),
$text);
230 return \Bitrix\Main\Text\DateConverter::decode(
$text, 1000);
239 \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
240 | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
241 | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
263 $code =
'####REPLACEMENT_MARK_'.count(self::$replacements).
'####';
265 self::$replacements[
$code] = $match[0];
272 if (empty(self::$replacements))
277 foreach(self::$replacements as
$code => $value)
282 if (mb_strpos(
$text,
'####REPLACEMENT_MARK_') !==
false)
287 self::$replacements = Array();
296 return '[USER='.$userId.
' REPLACE]'.
$userName.
'[/USER]';
303 if ($attachValue ===
true || preg_match(
'/^(\d+)$/', $attachValue))
305 $text .=
" [".Loc::getMessage(
'IM_MESSAGE_ATTACH').
"]";
309 $text .=
' '. $attachValue;
313 $text = preg_replace(
"/\[s\](.*?)\[\/s\]/i",
"",
$text);
314 $text = preg_replace(
"/\[[buis]\](.*?)\[\/[buis]\]/i",
"$1",
$text);
315 $text = preg_replace(
"/\[url\](.*?)\[\/url\]/iu",
"$1",
$text);
316 $text = preg_replace(
"/\[url\\s*=\\s*((?:[^\\[\\]]++|\\[ (?: (?>[^\\[\\]]+) | (?:\\1) )* \\])+)\\s*\\](.*?)\\[\\/url\\]/ixsu",
"$2",
$text);
317 $text = preg_replace(
"/\[RATING=([1-5]{1})\]/i",
" [".Loc::getMessage(
'IM_MESSAGE_RATING').
"] ",
$text);
318 $text = preg_replace(
"/\[ATTACH=([0-9]{1,})\]/i",
" [".Loc::getMessage(
'IM_MESSAGE_ATTACH').
"] ",
$text);
319 $text = preg_replace_callback(
"/\[USER=([0-9]{1,})\]\[\/USER\]/i", Array(
'\Bitrix\Im\Text',
'modifyShortUserTag'),
$text);
320 $text = preg_replace(
"/\[USER=([0-9]+)( REPLACE)?](.*?)\[\/USER]/i",
"$3",
$text);
321 $text = preg_replace(
"/\[dialog=(chat\d+|\d+:\d)(?: message=(\d+))?](.*?)\[\/dialog]/i",
"$3",
$text);
322 $text = preg_replace(
"/\[context=(chat\d+|\d+:\d+)\/(\d+)](.*?)\[\/context]/i",
"$3",
$text);
323 $text = preg_replace(
"/\[CHAT=([0-9]{1,})\](.*?)\[\/CHAT\]/i",
"$2",
$text);
324 $text = preg_replace(
"/\[SEND(?:=(.+?))?\](.+?)?\[\/SEND\]/i",
"$2",
$text);
325 $text = preg_replace(
"/\[PUT(?:=(.+?))?\](.+?)?\[\/PUT\]/i",
"$2",
$text);
326 $text = preg_replace(
"/\[CALL(?:=(.+?))?\](.+?)?\[\/CALL\]/i",
"$2",
$text);
327 $text = preg_replace(
"/\[PCH=([0-9]{1,})\](.*?)\[\/PCH\]/i",
"$2",
$text);
328 $text = preg_replace(
"/\[size=(\d+)](.*?)\[\/size]/i",
"$2",
$text);
329 $text = preg_replace(
"/\[color=#([0-9a-f]{3}|[0-9a-f]{6})](.*?)\[\/color]/i",
"$2",
$text);
330 $text = preg_replace_callback(
"/\[ICON\=([^\]]*)\]/i", Array(
'\Bitrix\Im\Text',
'modifyIcon'),
$text);
331 $text = preg_replace_callback(
'/\[TIMESTAMP=(\d+) FORMAT=([^\]]*)\]/i', [__CLASS__,
'modifyTimestampCode'],
$text);
332 $text = preg_replace(
'#\-{54}.+?\-{54}#s',
" [".Loc::getMessage(
'IM_QUOTE').
"] ", str_replace(
array(
"#BR#"), Array(
" "),
$text));
337 $text .=
" [".Loc::getMessage(
'IM_MESSAGE_FILE').
"]";
344 $text = Loc::getMessage(
'IM_MESSAGE_DELETE');
352 return preg_replace_callback(
"/\[USER=([0-9]{1,})\]\[\/USER\]/i",
static function(
$matches){
355 return '[USER='.$userId.
' REPLACE]'.
$userName.
'[/USER]';
361 $timestamp = (int)(
$matches[1] ?? 0);
362 $date = DateTime::createFromTimestamp($timestamp);
370 return Timestamp::build($date,
$formatCode)->toPlain();
375 return \Bitrix\Main\Text\Emoji::encode(
$text);
380 return \Bitrix\Main\Text\Emoji::decode(
$text);
385 if (!isset(self::$emojiList[
$code]))
387 return $fallbackText;
390 return self::decodeEmoji(self::$emojiList[
$code]);
395 return array_map(fn ($element) => self::decodeEmoji($element), self::$emojiList);
400 if (!is_string($html))
405 $html = str_replace(
' ',
' ', $html);
406 $html = str_replace(
'<hr>',
'------[BR]', $html);
407 $html = str_replace(
'#BR#',
'[BR]', $html);
412 $html = preg_replace(
413 "/<([busi])[^>a-z]*>(.+?)<\\/(\\1)[^>a-z]*>/isu",
418 while($replaced > 0);
420 $html = preg_replace(
"/\\<br\s*\\/*\\>/isu",
"[br]", $html);
421 $html = preg_replace(
423 "#<a[^>]+href\\s*=\\s*('|\")(.+?)(?:\\1)[^>]*>(.*?)</a[^>]*>#isu",
424 "#<a[^>]+href(\\s*=\\s*)([^'\">]+)>(.*?)</a[^>]*>#isu"
426 "[url=\\2]\\3[/url]", $html
428 $html = preg_replace(
429 [
"/<font[^>]+color\s*=[\s'\"]*#([0-9a-f]{3}|[0-9a-f]{6})[\s'\"]*>(.+?)<\/font[^>]*>/iu"],
430 [
"[color=#\\1]\\2[/color]"],
433 $html = preg_replace(
434 [
"/<span[^>]+color\s*=[\s'\"]*#([0-9a-f]{3}|[0-9a-f]{6})[\s'\"]*>(.+?)<\/span[^>]*>/iu"],
435 [
"[color=#\\1]\\2[/color]"],
438 $html = preg_replace(
439 [
"/<font[^>]+size\s*=[\s'\"]*(\d+)[\s'\"]*>(.+?)<\/font[^>]*>/iu"],
440 [
"[size=\\1]\\2[/size]"],
447 $html = preg_replace(
448 "/<div(?:.*?)>(.*?)<\/div>/iu",
453 while($replaced > 0);
458 $html = preg_replace(
459 "/<span(?:.*?)>(.*?)<\/span>/iu",
464 while($replaced > 0);
466 $html = preg_replace(
467 "/<font(?:.*?)>(.*?)<\/font>/iu",
479 $title = Loc::getMessage(
'IM_MESSAGE_ICON');
481 preg_match(
'/title\=(.*[^\s\]])/i',
$text, $match);
485 if (mb_strpos(
$title,
'width=') !==
false)
489 if (mb_strpos(
$title,
'height=') !==
false)
493 if (mb_strpos(
$title,
'size=') !==
false)
500 return '('.$title.
')';
505 $code = mb_strpos(mb_strtoupper(
$params[0]),
'[SEND') === 0?
'SEND':
'PUT';
506 return preg_replace(
"/\[$code(?:=(.+))?\](.+?)?\[\/$code\]/i",
"$2",
$params[0]);
512 [__CLASS__,
'extendedEncodeEmoji']
519 [__CLASS__,
'extendedDecodeEmoji']
525 return isset(
$text) ? self::encodeEmoji(
$text) :
null;
530 return isset(
$text) ? self::decodeEmoji(
$text) :
null;
535 $search = [
"\\n",
"\\t",
'\\"',
"\\\\"];
536 $replace = [
"\n",
"\t",
'"',
"\\"];
538 if (is_string(
$data))
540 return str_replace($search, $replace,
$data);
547 $data[
$key] = self::convertSymbolsAfterJsonDecode($value);
556 $pattern =
"/\[USER=(\d+)(?: REPLACE)?](.*?)\[\/USER]/is";
560 $previousText =
$text;
562 return self::replaceUserBbCodeByAccess(
$matches, $currentUserId);
565 while ($previousText !==
$text);
570 private static function replaceUserBbCodeByAccess(
$matches,
int $currentUserId): string
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
static extendedEncodeEmoji($text)
static modifyIcon($params)
static getFetchModificator()
static parse($text, $params=Array())
static recoverReplacements($text)
static modifySendPut($params)
static populateUserBbCode(string $text)
static convertSymbolsAfterJsonDecode($data)
static extendedDecodeEmoji($text)
static filterUserBbCodes(string $text, int $currentUserId)
static encodeEmoji($text)
static setReplacement($match)
static modifyTimestampCode(array $matches)
static getSaveModificator()
static getDateConverterParams($text)
static convertHtmlToBbCode($html)
static parseLegacyFormat($text, $params=Array())
static getEmoji($code, $fallbackText='')
static modifyShortUserTag($matches)
static isOnlyEmoji($text)
static removeBbCodes($text, $withFile=false, $attachValue=false)
static getReplaceMap($text)
static decodeEmoji($text)
static getInstance($userId=null)
static getInstance(?int $id)
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
if(!is_null($config))($config as $configItem)(! $configItem->isVisible()) $code
htmlspecialcharsbx($string, $flags=ENT_COMPAT, $doubleEncode=true)
if(empty($signedUserToken)) $key
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
if(!Loader::includeModule('sale')) $pattern