yf_bb_codes class

BB codes handler.

Fileplugins/content/classes/yf_bb_codes.class.php
Use_class('bb_codes')

Public properties

A site sets them in its config with $PROJECT_CONF['bb_codes']['NAME'] = ...;

PropertyDefaultDescription
$CHECK_CODES_IF_CLOSED
bool
false Check for unclosed bb codes every time when parsing
$CHECK_WORDS_LENGTH
bool
false Check for long words 'hacking' or not
$CSS_CLASSES
array
['show1' => 'forum1', 'show2' => 'forum2', 'quote' => 'forum_quote', 'code' => 'forum_code', 'smile' => 'forum_smile', 'topic_a_1' => 'row1', ... (11 items)]
array (
  'show1' => 'forum1',
  'show2' => 'forum2',
  'quote' => 'forum_quote',
  'code' => 'forum_code',
  'smile' => 'forum_smile',
  'topic_a_1' => 'row1',
  'topic_a_2' => 'row2',
  'topic_u_1' => 'row2shaded',
  'topic_u_2' => 'row4shaded',
  'post_a_1' => 'post2',
  'post_u_1' => 'post2shaded',
)
CSS classes names @conf_skip
$DEFAULT_SHOW_CODES
array
['font_family' => 0, 'font_size' => 1, 'font_color' => 1, 'extra_fields' => 0, 'help_box' => 0, 'open_tags' => 0, ... (7 items)]
array (
  'font_family' => 0,
  'font_size' => 1,
  'font_color' => 1,
  'extra_fields' => 0,
  'help_box' => 0,
  'open_tags' => 0,
  'youtube' => 0,
)
Default codes on/off
$ENABLE_BB_CODES
bool
true BB codes Enabled or not
$ENABLE_EXTRA_CODES
bool
false Enable extra codes
$ENABLE_SMILIES
bool
true Smilies in bb codes enabled or not
$FILTER_BAD_WORDS
bool
false Filter 'bad words' or not
$SMILIES_AS_IMAGES
bool
true Smilies in bb codes are like images or only with special CSS class
$SMILIES_DIR
string
'images/smilies/' Smilies folder
$USE_CUSTOM_BB_CODES
bool
false Use or not custom bb codes (from db)
$USE_HIGHLIGHT
bool
true Try to highlight special text (SQL or HTML)
$USE_NOFOLLOW_TAG
bool
false
$_avail_codes
string
'(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

Public methods 8

None without a leading underscore.

Methods starting with _ hooks and helpers; not routable as page actions

__call

public function __call($name, $args)

Catch missing method call.

    public function __call($name, $args)
    {
        return main()->extend_call($this, $name, $args);
    }

_cut_bb_codes

public function _cut_bb_codes($body = '')
    public function _cut_bb_codes($body = '')
    {
        return preg_replace('/\[[^\]]+\]/ims', '', $body);
    }
public function _display_buttons($input = [])
    public function _display_buttons($input = [])
    {
        $this->_preload_data();
        $STPL_NAME = isset($input['stpl_name']) ? $input['stpl_name'] : __CLASS__ . '/buttons';
        $js_vars_code = '';
        if ( ! @$GLOBALS['_bb_codes_calls']++) {
            $js_vars_code = tpl()->parse(__CLASS__ . '/js_vars', [
                'max_length' => isset($input['max_length']) ? (int) ($input['max_length']) : 0,
                'bb_codes_js_src' => ! ($GLOBALS['_bb_codes_calls'] ?? null) ? WEB_PATH . 'js/yf_bb_codes.js' : '',
                'display_i18n_js_vars' => ! ($GLOBALS['_bb_codes_calls'] ?? null) ? 1 : 0,
                'emo_pop_link' => './?object=help&action=display_emo_pop',
                'bb_pop_link' => './?object=help&action=display_bb_pop',
            ]);
        }
        return tpl()->parse($STPL_NAME, [
            'display_font_family' => isset($input['font_family']) ? (int) ((bool) $input['font_family']) : $this->DEFAULT_SHOW_CODES['font_family'],
            'display_font_size' => isset($input['font_size']) ? (int) ((bool) $input['font_size']) : $this->DEFAULT_SHOW_CODES['font_size'],
            'display_font_color' => isset($input['font_color']) ? (int) ((bool) $input['font_color']) : $this->DEFAULT_SHOW_CODES['font_color'],
            'display_extra_fields' => isset($input['extra_fields']) ? (int) ((bool) $input['extra_fields']) : $this->DEFAULT_SHOW_CODES['extra_fields'],
            'display_youtube' => isset($input['youtube']) ? (int) ((bool) $input['youtube']) : $this->DEFAULT_SHOW_CODES['youtube'],
            'display_help_box' => isset($input['help_box']) ? (int) ((bool) $input['help_box']) : $this->DEFAULT_SHOW_CODES['help_box'],
            'display_open_tags' => isset($input['open_tags']) ? (int) ((bool) $input['open_tags']) : $this->DEFAULT_SHOW_CODES['open_tags'],
            'unique_id' => isset($input['unique_id']) ? _prepare_html($input['unique_id']) : substr(md5(microtime(true) . rand()), 0, 8),
            'js_vars_code' => $js_vars_code,
        ]);
    }
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.

@example [CSV]DocID,ParentID,RefCount,RefDocID,DocCode,DocName 2,0,1,0,,Text1 3,2,1,0,NULL,Text2 4,3,1,0,NULL,Text3[/CSV]
    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;
    }

_preload_data

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

_process_text

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