yf_bb_codes classBB codes handler.
| File | plugins/content/classes/yf_bb_codes.class.php |
|---|---|
| Use | _class('bb_codes') |
A site sets them in its config with $PROJECT_CONF['bb_codes']['NAME'] = ...;
| Property | Default | Description |
|---|---|---|
$CHECK_CODES_IF_CLOSEDbool |
false |
Check for unclosed bb codes every time when parsing |
$CHECK_WORDS_LENGTHbool |
false |
Check for long words 'hacking' or not |
$CSS_CLASSESarray |
|
CSS classes names @conf_skip |
$DEFAULT_SHOW_CODESarray |
|
Default codes on/off |
$ENABLE_BB_CODESbool |
true |
BB codes Enabled or not |
$ENABLE_EXTRA_CODESbool |
false |
Enable extra codes |
$ENABLE_SMILIESbool |
true |
Smilies in bb codes enabled or not |
$FILTER_BAD_WORDSbool |
false |
Filter 'bad words' or not |
$SMILIES_AS_IMAGESbool |
true |
Smilies in bb codes are like images or only with special CSS class |
$SMILIES_DIRstring |
'images/smilies/' |
Smilies folder |
$USE_CUSTOM_BB_CODESbool |
false |
Use or not custom bb codes (from db) |
$USE_HIGHLIGHTbool |
true |
Try to highlight special text (SQL or HTML) |
$USE_NOFOLLOW_TAGbool |
false |
|
$_avail_codesstring |
'(b|i|u|code|quote|color|size|url|img|sql|html|media|swf|e'... |
Available bb codes pattern (for closing codes check) |
$_preg_bb_codes |
null |
|
$_preload_complete |
null |
|
$_smilies_replace |
null |
None without a leading underscore.
_ hooks and helpers; not routable as page actionspublic function __call($name, $args)
Catch missing method call.
public function __call($name, $args)
{
return main()->extend_call($this, $name, $args);
}
public function _cut_bb_codes($body = '')
public function _cut_bb_codes($body = '')
{
return preg_replace('/\[[^\]]+\]/ims', '', $body);
}
public function _display_buttons($input = [])
public function _force_close_bb_codes($text = '')
Force to close bb codes in given text (prevent design bugging).
public function _force_close_bb_codes($text = '')
{
$this->_preload_data();
$add_text = '';
$opened_codes = $closed_codes = [];
// Try to find unclosed codes
if ($num_opening_bb_codes = preg_match_all('/\[' . $this->_avail_codes . '[^\]]*?\]/i', $text, $m_opening)) {
foreach ((array) $m_opening[1] as $cur_code) {
@$opened_codes[strtolower($cur_code)]++;
}
}
if ($num_closing_bb_codes = preg_match_all('/\[\/' . $this->_avail_codes . '\]/i', $text, $m_closing)) {
foreach ((array) $m_closing[1] as $cur_code) {
@$closed_codes[strtolower($cur_code)]++;
}
}
// Process opening codes
$tmp_opened_codes = $opened_codes;
foreach ((array) $tmp_opened_codes as $cur_code => $num_items) {
if ( ! empty($closed_codes[$cur_code])) {
$opened_codes[$cur_code] -= $closed_codes[$cur_code];
}
}
// Do close codes
foreach ((array) $opened_codes as $cur_code => $num_items) {
if ($num_items <= 0) {
continue;
}
$add_text .= str_repeat('[/' . strtoupper($cur_code) . ']', $num_items);
}
$text .= $add_text;
// Fix youtube URL
$text = preg_replace('/(\[youtube\]http:\/\/www.youtube.com\/)watch\?v=(\w+)(\[\/youtube\])/ims', '\1v/\2\3', $text);
return $text;
}
public function _geshi_highlight($text = '', $prog_lang = 'html4strict')
public function _geshi_highlight($text = '', $prog_lang = 'html4strict')
{
require_once dirname(INCLUDE_PATH) . '/yf/__SANDBOX/geshi/geshi.php';
$text = geshi_highlight($text, $prog_lang, '', 1);
return $text;
}
public function _parse_csv_bb_code($text = '')
Try to parse CSV code.
public function _parse_csv_bb_code($text = '')
{
// TODO: user table()->auto()
$output = '';
$c = 0;
$num_cols = 0;
foreach (explode("\n", str_replace(["\r", "<br \/>"], '', $text)) as $cur_line) {
$data = explode(',', $cur_line);
if ($c++ == 0) {
$output .= '<table border="1" cellpadding="2" cellspacing="1" style="font: 11px verdana;border-collapse:collapse;border:1px solid gray;margin:5px;"';
$num_cols = count((array) $data);
}
$output .= '<tr>';
for ($i = 0; $i < $num_cols; $i++) {
$output .= '<td bgcolor="' . ($c == 1 ? '#b9ccdf' : '#ffffff') . '">' . _prepare_html($data[$i]) . '</td>';
}
$output .= '</tr>';
}
$output .= '</table>';
return $output;
}
public function _preload_data()
public function _preload_data()
{
if ($this->_preload_complete) {
return true;
}
if ($this->ENABLE_BB_CODES && $this->ENABLE_SMILIES && ! isset($GLOBALS['_smiles_array'])) {
$GLOBALS['_smiles_array'] = main()->get_data('smilies');
}
$nofollow = $this->USE_NOFOLLOW_TAG ? ' rel="nofollow"' : '';
$this->_preg_bb_codes = [
'/\[url=[\"\']{0,1}([^\]]*?)[\"\']{0,1}\](.*?)\[\/url\]/i' => '<a href="\1" target="blank"' . $nofollow . '>\2</a>',
'/\[url\](.*?)\[\/url\]/i' => '<a href="\1" target="blank"' . $nofollow . '>\1</a>',
'/\[img\]([^\[]*?)\[\/img\]/i' => '<div class="bb_remote_image"><img src="\1"></div>',
'/\[color=[\"\']*([#\w]+)[\"\']*\]/i' => '<span style="color:\1">',
'/\[size=[\"\']*([#\w]+)[\"\']*\]/i' => '<span style="font-size:\1px;">',
'/\[quote[:=\w]*[\"\']*([\w\s&;-]*)[\"\']*\]/i' => '<div>' . t('quote') . ' <b>\1</b> :</div><div class="' . $this->CSS_CLASSES['quote'] . '">',
'/\[code\]/i' => '<pre class="' . $this->CSS_CLASSES['code'] . '">',
'/\[\/(color|size)\]/i' => '</span>',
'/\[\/quote\]/i' => '</div>',
'/\[\/code\]/i' => '</pre>',
'/\[([\/]{0,1})(b|i|u|sub|sup|li)\]/i' => '<\1\2>',
'/\[imgurl=([^\]]*)\]([^\[]*?)\[\/imgurl\]/i' => '<a href="\1" target="blank"' . $nofollow . '><img src="\2" border="0"></a>',
'/\[media\]([^\[]*?)\[\/media\]/i' => '<embed name="RAOCXplayer" src="\1">',
'/\[swf\]([^\[]*?)\[\/swf\]/i' => '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0"><param name="movie" value="\1" /><param name="quality" value="high" /><embed src="\1" quality="high" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" /></object>',
'/\[email\]([^\[]*?)\[\/email\]/i' => '<a href="mailto:\1"' . $nofollow . '>\1</a>',
'/\[hr\]/i' => '<hr />',
'/\[youtube\]([^\[]*?)\[\/youtube\]/i' => '<object width="425" height="350"><param name="movie" value="\1"></param><param name="wmode" value="transparent"></param><embed src="\1" type="application/x-shockwave-flash" wmode="transparent" width="425" height="350"></embed></object>',
'/\[spoiler[=]{0,1}[\"\']*([^\]]*?)[\"\']*\]([^\[]*?)\[\/spoiler\]/i' => '<div class="spoiler_block"><div class="spoiler_head"><input type="button" class="toggle_button" value="+">\1 </div><div class="spoiler_body">\2</div></div>',
];
if ($this->USE_CUSTOM_BB_CODES) {
$custom_codes = main()->get_data('custom_bbcode');
foreach ((array) $custom_codes as $_custom_tag => $_info) {
$_custom_tag = preg_quote($_custom_tag);
$_regex = '/\[' . $_custom_tag . '[=]{0,1}([a-z0-9_-]+)' . ($_info['useoption'] ? '{0,1}' : '{0}') . '\](.*?)\[\/' . $_custom_tag . '\]/ims';
$this->_preg_bb_codes[$_regex] = str_replace(['{option}', '{content}'], ['\1', '\2'], $_info['replace']);
}
}
// Prepare avail codes string (sort them by name desc)
$tmp_codes = [];
foreach (explode('|', substr($this->_avail_codes, 1, -1)) as $_item) {
$tmp_codes[$_item] = $_item;
}
krsort($tmp_codes);
$this->_avail_codes = '(' . implode('|', $tmp_codes) . ')';
$this->_preload_complete = true;
}
public function _process_text($body = '', $no_smilies = false, $smilies_as_image = false)
Process text to show.
public function _process_text($body = '', $no_smilies = false, $smilies_as_image = false)
{
if (empty($body)) {
return '';
}
$this->_preload_data();
// user text (comments, posts) printed into a page that the template engine parses again
$body = _escape_tpl_braces(str_replace(['<', '>'], ['<', '>'], $body));
if ($this->FILTER_BAD_WORDS) {
if ( ! isset($GLOBALS['BAD_WORDS_ARRAY'])) {
$Q = db()->query('SELECT word FROM ' . db('badwords') . '');
while ($A = db()->fetch_assoc($Q)) {
$GLOBALS['BAD_WORDS_ARRAY'] = $A['word'];
}
}
$body = str_replace($GLOBALS['BAD_WORDS_ARRAY'], '', $body);
}
if ($this->CHECK_WORDS_LENGTH) {
$body = _check_words_length($body);
}
if ($this->ENABLE_BB_CODES) {
if (false !== strpos($body, '[')) {
if ($this->CHECK_CODES_IF_CLOSED) {
$body = $this->_force_close_bb_codes($body);
}
$body = preg_replace(array_keys($this->_preg_bb_codes), array_values($this->_preg_bb_codes), $body);
if ($this->USE_HIGHLIGHT) {
$body = preg_replace_callback('/\[sql\](.*?)\[\/sql\]/ims', function ($m) {
return _class_safe('text_highlight', 'classes/common/')->_regex_sql_tag(stripslashes($m[1]));
}, $body);
$body = preg_replace_callback('/\[html\](.*?)\[\/html\]/ims', function ($m) {
return _class_safe('text_highlight', 'classes/common/')->_regex_html_tag(stripslashes($m[1]));
}, $body);
}
$_this = $this;
$body = preg_replace_callback('/\[csv\](.*?)\[\/csv\]/ims', function ($m) use ($_this) {
return $_this->_parse_csv_bb_code($m[1]);
}, $body);
}
if ($this->ENABLE_SMILIES && is_array($GLOBALS['_smiles_array'] ?? null) && empty($no_smilies)) {
if ( ! empty($GLOBALS['_SMILIES_CACHE'])) {
$this->_smilies_replace = &$GLOBALS['_SMILIES_CACHE'];
} else {
$smilies_as_image = 0;
if ($this->SMILIES_AS_IMAGES) {
$smilies_as_image = true;
}
foreach ((array) ($GLOBALS['_smiles_array'] ?? null) as $smile_info) {
$replace = [
'img_src' => WEB_PATH . /*tpl()->TPL_PATH. */$this->SMILIES_DIR . $smile_info['url'],
'img_alt' => _prepare_html($smile_info['emoticon']),
'css_class' => $this->CSS_CLASSES['smile'],
'text' => _prepare_html($smile_info['code']),
'as_image' => (int) $smilies_as_image,
];
$this->_smilies_replace[$smile_info['code']] = tpl()->parse('system/smile_item', $replace);
}
$GLOBALS['_SMILIES_CACHE'] = $this->_smilies_replace;
}
}
if ( ! empty($this->_smilies_replace)) {
$body = str_replace(array_keys($this->_smilies_replace), array_values($this->_smilies_replace), $body);
}
}
$body = nl2br($body);
return $body;
}