%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;
}
}