%PDF- %PDF-
Direktori : /data/www_bck/varak.cloud_bck/tracker.varak.cloud/src/Legacy/ |
Current File : //data/www_bck/varak.cloud_bck/tracker.varak.cloud/src/Legacy/BBCode.php |
<?php /** * TorrentPier – Bull-powered BitTorrent tracker engine * * @copyright Copyright (c) 2005-2018 TorrentPier (https://torrentpier.com) * @link https://github.com/torrentpier/torrentpier for the canonical source repository * @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License */ namespace TorrentPier\Legacy; /** * Class BBCode * @package TorrentPier\Legacy */ class BBCode { /** @var array $tpl Replacements for some code elements */ public $tpl = []; /** @var array $smilies Replacements for smilies */ public $smilies; /** @var array $tidy_cfg Tidy preprocessor configuration */ public $tidy_cfg = [ 'drop-empty-paras' => false, 'fix-uri' => false, 'force-output' => true, 'hide-comments' => true, 'join-classes' => false, 'join-styles' => false, 'merge-divs' => false, 'newline' => 'LF', 'output-xhtml' => true, 'preserve-entities' => true, 'quiet' => true, 'quote-ampersand' => false, 'show-body-only' => true, 'show-errors' => false, 'show-warnings' => false, 'wrap' => 0, ]; /** @var array $block_tags Define some elements as block-processed */ public $block_tags = [ 'align', 'br', 'clear', 'hr', 'list', 'pre', 'quote', 'spoiler', ]; public $preg = []; public $str = []; public $preg_search = []; public $preg_repl = []; public $str_search = []; public $str_repl = []; /** * Constructor */ public function __construct() { $this->tpl = get_bbcode_tpl(); $this->init_replacements(); } /** * Initialize replacements for elements */ private function init_replacements(): void { $tpl = $this->tpl; $img_exp = '(https?:)?//[^\s\?&;=\#\"<>]+?\.(jpg|jpeg|gif|png)([a-z0-9/?&%;][^\[\]]*)?'; $email_exp = '[a-z0-9&\-_.]+?@[\w\-]+\.([\w\-\.]+\.)?[\w]+'; $this->preg = [ '#\[quote="(.+?)"\]#isu' => $tpl['quote_username_open'], '#\[spoiler="(.+?)"\]#isu' => $tpl['spoiler_title_open'], '#\[list=(a|A|i|I|1)\]#isu' => '<ul type="$1">', '#\[\*=(\d+)\]#isu' => '<li value="$1">', '#\[pre\](.*?)\[/pre\]#isu' => '<pre class="post-pre">$1</pre>', '#\[name=([a-zA-Z0-9_]+?)\]#isu' => '<a name="$1"></a>', '#\[url=\#([a-zA-Z0-9_]+?)\](.*?)\[/url\]#isu' => '<a class="postLink-name" href="#$1">$2</a>', '#\[color=([\#0-9a-zA-Z]+)\]#isu' => '<span style="color: $1;">', '#\[size=([1-2]?[0-9])\]#isu' => '<span style="font-size: $1px; line-height: normal;">', '#\[align=(left|right|center|justify)\]#isu' => '<span class="post-align" style="text-align: $1;">', '#\[font="([\w\- \']+)"\]#isu' => '<span style="font-family: $1;">', "#\[img\]($img_exp)\[/img\]#isu" => $tpl['img'], "#\[img=(left|right|center)\]($img_exp)\[/img\]\s*#isu" => $tpl['img_aligned'], "#\[email\]($email_exp)\[/email\]#isu" => '<a href="mailto:$1">$1</a>', "#\[qpost=([0-9]*)\]#isu" => '<u class="q-post">$1</u>', ]; $this->str = [ '[quote]' => $tpl['quote_open'], '[/quote]' => $tpl['quote_close'], '[spoiler]' => $tpl['spoiler_open'], '[/spoiler]' => $tpl['spoiler_close'], '[list]' => '<ul>', '[*]' => '<li>', '[/list]' => '</ul>', '[/color]' => '</span>', '[/size]' => '</span>', '[/align]' => '</span>', '[/font]' => '</span>', '[tab]' => ' ', '[br]' => "\n\n", '[hr]' => $tpl['hr'], '[b]' => '<span class="post-b">', '[/b]' => '</span>', '[u]' => '<span class="post-u">', '[/u]' => '</span>', '[i]' => '<span class="post-i">', '[/i]' => '</span>', '[s]' => '<span class="post-s">', '[/s]' => '</span>', '[del]' => '<span class="post-s">', '[/del]' => '</span>', '[clear]' => '<div class="clear"> </div>', ]; $this->preg_search = array_keys($this->preg); $this->preg_repl = array_values($this->preg); $this->str_search = array_keys($this->str); $this->str_repl = array_values($this->str); } /** * Convert bbcodes to html. Text must be prepared with htmlCHR * * @param string $text * * @return string */ public function bbcode2html($text): string { global $bb_cfg; $text = self::clean_up($text); $text = $this->parse($text); $text = $this->make_clickable($text); $text = $this->smilies_pass($text); $text = $this->new_line2html($text); if ($bb_cfg['tidy_post']) { $text = $this->tidy($text); } return trim($text); } /** * Parse elements in the text * * @param string $text * * @return string */ private function parse($text): string { // Tag parse if (strpos($text, '[') === false) { return $text; } // [code] $text = preg_replace_callback('#(\s*)\[code\](.+?)\[/code\](\s*)#s', [&$this, 'code_callback'], $text); // Escape tags inside titles in [quote="tilte"] $text = preg_replace_callback('#(\[(quote|spoiler)=")(.+?)("\])#', [&$this, 'escape_titles_callback'], $text); // [url] $url_exp = '[\w\#!$%&~/.\-;:=,?@а-яА-Я()\[\]+]+?'; $text = preg_replace_callback("#\[url\]((?:https?://)?$url_exp)\[/url\]#isu", [&$this, 'url_callback'], $text); $text = preg_replace_callback("#\[url\](www\.$url_exp)\[/url\]#isu", [&$this, 'url_callback'], $text); $text = preg_replace_callback("#\[url=((?:https?://)?$url_exp)\]([^?\n\t].*?)\[/url\]#isu", [&$this, 'url_callback'], $text); $text = preg_replace_callback("#\[url=(www\.$url_exp)\]([^?\n\t].*?)\[/url\]#isu", [&$this, 'url_callback'], $text); // Normalize block level tags wrapped with new lines $block_tags = implode('|', $this->block_tags); $text = str_replace("\n\n[hr]\n\n", '[br][hr][br]', $text); $text = preg_replace("#(\s*)(\[/?($block_tags)(.*?)\])(\s*)#", '$2', $text); // Tag replacements $text = preg_replace($this->preg_search, $this->preg_repl, $text); $text = str_replace($this->str_search, $this->str_repl, $text); return $text; } /** * Clean up test from trailing spaces and more * * @param string $text * * @return string */ public static function clean_up($text): string { $text = trim($text); $text = str_replace("\r", '', $text); $text = preg_replace('#[ \t]+$#m', '', $text); $text = preg_replace('#\n{3,}#', "\n\n", $text); return $text; } /** * Callback to [code] * * @param string $m * * @return string */ private function code_callback($m): string { $code = trim($m[2]); $code = str_replace(' ', ' ', $code); $code = str_replace(' ', ' ', $code); $code = str_replace("\t", ' ', $code); $code = str_replace(['[', ']', ':', ')'], ['[', ']', ':', ')'], $code); return $this->tpl['code_open'] . $code . $this->tpl['code_close']; } /** * Callback to [url] * * @param string $m * * @return string */ private function url_callback($m): string { global $bb_cfg; $url = trim($m[1]); $url_name = isset($m[2]) ? trim($m[2]) : $url; if (!preg_match('#^https?://#iu', $url) && !preg_match('/^#/', $url)) { $url = 'http://' . $url; } if (\in_array(parse_url($url, PHP_URL_HOST), $bb_cfg['nofollow']['allowed_url']) || $bb_cfg['nofollow']['disabled']) { $link = "<a href=\"$url\" class=\"postLink\">$url_name</a>"; } else { $link = "<a href=\"$url\" class=\"postLink\" rel=\"nofollow\">$url_name</a>"; } return $link; } /** * Callback to escape titles in block elements * * @param string $m * * @return string */ private function escape_titles_callback($m): string { $tilte = substr($m[3], 0, 250); $tilte = str_replace(['[', ']', ':', ')', '"'], ['[', ']', ':', ')', '"'], $tilte); // еще раз htmlspecialchars, т.к. при извлечении из title происходит обратное преобразование $tilte = htmlspecialchars($tilte, ENT_QUOTES); return $m[1] . $tilte . $m[4]; } /** * Callback to make text clickable * * @param string $text * * @return string */ private function make_clickable($text): string { $url_regexp = "# (?<![\"'=]) \b ( https?://[\w\#!$%&~/.\-;:=?@а-яА-Я()\[\]+]+ ) (?![\"']|\[/url|\[/img|</a) (?=[,!]?\s|[\)<!]) #xiu"; // pad it with a space so we can match things at the start of the 1st line. $ret = " $text "; // hide passkey $ret = hide_passkey($ret); // matches an "xxxx://yyyy" URL at the start of a line, or after a space. $ret = preg_replace_callback($url_regexp, [&$this, 'make_url_clickable_callback'], $ret); // Remove our padding.. $ret = substr(substr($ret, 0, -1), 1); return $ret; } /** * Callback to make URL clickable * * @param string $m * * @return string */ private function make_url_clickable_callback($m): string { global $bb_cfg; $max_len = 70; $href = $m[1]; $name = (mb_strlen($href, 'UTF-8') > $max_len) ? mb_substr($href, 0, $max_len - 19) . '...' . mb_substr($href, -16) : $href; if (\in_array(parse_url($href, PHP_URL_HOST), $bb_cfg['nofollow']['allowed_url']) || $bb_cfg['nofollow']['disabled']) { $link = "<a href=\"$href\" class=\"postLink\">$name</a>"; } else { $link = "<a href=\"$href\" class=\"postLink\" rel=\"nofollow\">$name</a>"; } return $link; } /** * Replace smilies to images in text * * @param string $text * * @return string */ private function smilies_pass($text): string { global $bb_cfg, $datastore; if (null === $this->smilies) { $this->smilies = $datastore->get('smile_replacements'); } if ($this->smilies) { /** @noinspection NestedPositiveIfStatementsInspection */ if ($parsed_text = preg_replace($this->smilies['orig'], $this->smilies['repl'], $text, 101, $smilies_cnt)) { return (($smilies_cnt <= $bb_cfg['max_smilies']) && $bb_cfg['max_smilies'] > 0) ? $parsed_text : $text; } } return $text; } /** * Replace text new line to html * * @param string $text * * @return string */ private function new_line2html($text): string { $text = preg_replace('#\n{2,}#', '<span class="post-br"><br /></span>', $text); $text = str_replace("\n", '<br />', $text); return $text; } /** * Prepare post text with tidy preprocessor * * @param string $text * * @return string */ private function tidy($text): string { $text = tidy_repair_string($text, $this->tidy_cfg, 'utf8'); return $text; } }