Some help hacking phpbb3 bbcode

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Some help hacking phpbb3 bbcode

Post by s.dot »

Here's the scenario..

I've set the board to allow images of any size. However, if the image is greater than 450px wide, I want to add a width="450" attribute to the image tag.

So far here's what I've managed (not much):

Code: Select all

$bbcode_hardtpl = array(
    'b_open'    => '<span style="font-weight: bold">',
    'b_close'   => '</span>',
    'i_open'    => '<span style="font-style: italic">',
    'i_close'   => '</span>',
    'u_open'    => '<span style="text-decoration: underline">',
    'u_close'   => '</span>',
    'img'       => '<a href="$1" target="_blank"><img src="$1" alt="' . $user->lang['IMAGE'] . '" width="450" border="0" /></a>',
    'size'      => '<span style="font-size: $1%; line-height: normal">$2</span>',
    'color'     => '<span style="color: $1">$2</span>',
    'email'     => '<a href="mailto:$1">$2</a>'
);
Notice I changed the image to hardcode the width="450" there and set it as a link in a new window.

However, I realize I need some php like the following to determine whether it should do that or not:

Code: Select all

if ($imgInfo = @getimagesize($imageURL) && ($imgInfo[0] > 450))
{
    //use my specific hardcoded template
} else
{
    //use the default
}
However, that file is so complex.. I have no idea where to put it!

Here's the phpbb3 bbcode file

Code: Select all

<?php
/**
*
* @package phpBB3
* @version $Id: bbcode.php 8479 2008-03-29 00:22:48Z naderman $
* @copyright (c) 2005 phpBB Group
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*
*/
 
/**
* @ignore
*/
if (!defined('IN_PHPBB'))
{
    exit;
}
 
/**
* BBCode class
* @package phpBB3
*/
class bbcode
{
    var $bbcode_uid = '';
    var $bbcode_bitfield = '';
    var $bbcode_cache = array();
    var $bbcode_template = array();
 
    var $bbcodes = array();
 
    var $template_bitfield;
    var $template_filename = '';
 
    /**
    * Constructor
    * Init bbcode cache entries if bitfield is specified
    */
    function bbcode($bitfield = '')
    {
        if ($bitfield)
        {
            $this->bbcode_bitfield = $bitfield;
            $this->bbcode_cache_init();
        }
    }
 
    /**
    * Second pass bbcodes
    */
    function bbcode_second_pass(&$message, $bbcode_uid = '', $bbcode_bitfield = false)
    {
        if ($bbcode_uid)
        {
            $this->bbcode_uid = $bbcode_uid;
        }
 
        if ($bbcode_bitfield !== false)
        {
            $this->bbcode_bitfield = $bbcode_bitfield;
 
            // Init those added with a new bbcode_bitfield (already stored codes will not get parsed again)
            $this->bbcode_cache_init();
        }
 
        if (!$this->bbcode_bitfield)
        {
            // Remove the uid from tags that have not been transformed into HTML
            if ($this->bbcode_uid)
            {
                $message = str_replace(':' . $this->bbcode_uid, '', $message);
            }
 
            return;
        }
 
        $str = array('search' => array(), 'replace' => array());
        $preg = array('search' => array(), 'replace' => array());
 
        $bitfield = new bitfield($this->bbcode_bitfield);
        $bbcodes_set = $bitfield->get_all_set();
 
        $undid_bbcode_specialchars = false;
        foreach ($bbcodes_set as $bbcode_id)
        {
            if (!empty($this->bbcode_cache[$bbcode_id]))
            {
                foreach ($this->bbcode_cache[$bbcode_id] as $type => $array)
                {
                    foreach ($array as $search => $replace)
                    {
                        ${$type}['search'][] = str_replace('$uid', $this->bbcode_uid, $search);
                        ${$type}['replace'][] = $replace;
                    }
 
                    if (sizeof($str['search']))
                    {
                        $message = str_replace($str['search'], $str['replace'], $message);
                        $str = array('search' => array(), 'replace' => array());
                    }
 
                    if (sizeof($preg['search']))
                    {
                        // we need to turn the entities back into their original form to allow the
                        // search patterns to work properly
                        if (!$undid_bbcode_specialchars)
                        {
                            $message = str_replace(array('&#58;', '&#46;'), array(':', '.'), $message);
                            $undid_bbcode_specialchars = true;
                        }
 
                        $message = preg_replace($preg['search'], $preg['replace'], $message);
                        $preg = array('search' => array(), 'replace' => array());
                    }
                }
            }
        }
 
        // Remove the uid from tags that have not been transformed into HTML
        $message = str_replace(':' . $this->bbcode_uid, '', $message);
    }
 
    /**
    * Init bbcode cache
    *
    * requires: $this->bbcode_bitfield
    * sets: $this->bbcode_cache with bbcode templates needed for bbcode_bitfield
    */
    function bbcode_cache_init()
    {
        global $user, $phpbb_root_path;
 
        if (empty($this->template_filename))
        {
            $this->template_bitfield = new bitfield($user->theme['bbcode_bitfield']);
            $this->template_filename = $phpbb_root_path . 'styles/' . $user->theme['template_path'] . '/template/bbcode.html';
 
            if (!@file_exists($this->template_filename))
            {
                trigger_error('The file ' . $this->template_filename . ' is missing.', E_USER_ERROR);
            }
        }
 
        $bbcode_ids = $rowset = $sql = array();
 
        $bitfield = new bitfield($this->bbcode_bitfield);
        $bbcodes_set = $bitfield->get_all_set();
 
        foreach ($bbcodes_set as $bbcode_id)
        {
            if (isset($this->bbcode_cache[$bbcode_id]))
            {
                // do not try to re-cache it if it's already in
                continue;
            }
            $bbcode_ids[] = $bbcode_id;
 
            if ($bbcode_id > NUM_CORE_BBCODES)
            {
                $sql[] = $bbcode_id;
            }
        }
 
        if (sizeof($sql))
        {
            global $db;
 
            $sql = 'SELECT *
                FROM ' . BBCODES_TABLE . '
                WHERE ' . $db->sql_in_set('bbcode_id', $sql);
            $result = $db->sql_query($sql, 3600);
 
            while ($row = $db->sql_fetchrow($result))
            {
                // To circumvent replacing newlines with <br /> for the generated html,
                // we use carriage returns here. They are later changed back to newlines
                $row['bbcode_tpl'] = str_replace("\n", "\r", $row['bbcode_tpl']);
                $row['second_pass_replace'] = str_replace("\n", "\r", $row['second_pass_replace']);
 
                $rowset[$row['bbcode_id']] = $row;
            }
            $db->sql_freeresult($result);
        }
 
        foreach ($bbcode_ids as $bbcode_id)
        {
            switch ($bbcode_id)
            {
                case 0:
                    $this->bbcode_cache[$bbcode_id] = array(
                        'str' => array(
                            '[/quote:$uid]' => $this->bbcode_tpl('quote_close', $bbcode_id)
                        ),
                        'preg' => array(
                            '#\[quote(?:="(.*?)")?:$uid\]((?!\[quote(?:=".*?")?:$uid\]).)?#ise' => "\$this->bbcode_second_pass_quote('\$1', '\$2')"
                        )
                    );
                break;
 
                case 1:
                    $this->bbcode_cache[$bbcode_id] = array(
                        'str' => array(
                            '[b:$uid]'  => $this->bbcode_tpl('b_open', $bbcode_id),
                            '[/b:$uid]' => $this->bbcode_tpl('b_close', $bbcode_id),
                        )
                    );
                break;
 
                case 2:
                    $this->bbcode_cache[$bbcode_id] = array(
                        'str' => array(
                            '[i:$uid]'  => $this->bbcode_tpl('i_open', $bbcode_id),
                            '[/i:$uid]' => $this->bbcode_tpl('i_close', $bbcode_id),
                        )
                    );
                break;
 
                case 3:
                    $this->bbcode_cache[$bbcode_id] = array(
                        'preg' => array(
                            '#\[url:$uid\]((.*?))\[/url:$uid\]#s'           => $this->bbcode_tpl('url', $bbcode_id),
                            '#\[url=([^\[]+?):$uid\](.*?)\[/url:$uid\]#s'   => $this->bbcode_tpl('url', $bbcode_id),
                        )
                    );
                break;
 
                case 4:
                    if ($user->optionget('viewimg'))
                    {
                        $this->bbcode_cache[$bbcode_id] = array(
                            'preg' => array(
                                '#\[img:$uid\](.*?)\[/img:$uid\]#s'     => $this->bbcode_tpl('img', $bbcode_id),
                            )
                        );
                    }
                    else
                    {
                        $this->bbcode_cache[$bbcode_id] = array(
                            'preg' => array(
                                '#\[img:$uid\](.*?)\[/img:$uid\]#s'     => str_replace('$2', '[ img ]', $this->bbcode_tpl('url', $bbcode_id, true)),
                            )
                        );
                    }
                break;
 
                case 5:
                    $this->bbcode_cache[$bbcode_id] = array(
                        'preg' => array(
                            '#\[size=([\-\+]?\d+):$uid\](.*?)\[/size:$uid\]#s'  => $this->bbcode_tpl('size', $bbcode_id),
                        )
                    );
                break;
 
                case 6:
                    $this->bbcode_cache[$bbcode_id] = array(
                        'preg' => array(
                            '!\[color=(#[0-9a-f]{6}|[a-z\-]+):$uid\](.*?)\[/color:$uid\]!is'    => $this->bbcode_tpl('color', $bbcode_id),
                        )
                    );
                break;
 
                case 7:
                    $this->bbcode_cache[$bbcode_id] = array(
                        'str' => array(
                            '[u:$uid]'  => $this->bbcode_tpl('u_open', $bbcode_id),
                            '[/u:$uid]' => $this->bbcode_tpl('u_close', $bbcode_id),
                        )
                    );
                break;
 
                case 8:
                    $this->bbcode_cache[$bbcode_id] = array(
                        'preg' => array(
                            '#\[code(?:=([a-z]+))?:$uid\](.*?)\[/code:$uid\]#ise'   => "\$this->bbcode_second_pass_code('\$1', '\$2')",
                        )
                    );
                break;
 
                case 9:
                    $this->bbcode_cache[$bbcode_id] = array(
                        'preg' => array(
                            '#(\[\/?(list|\*):[mou]?:?$uid\])[\n]{1}#'  => "\$1",
                            '#(\[list=([^\[]+):$uid\])[\n]{1}#'         => "\$1",
                            '#\[list=([^\[]+):$uid\]#e'                 => "\$this->bbcode_list('\$1')",
                        ),
                        'str' => array(
                            '[list:$uid]'       => $this->bbcode_tpl('ulist_open_default', $bbcode_id),
                            '[/list:u:$uid]'    => $this->bbcode_tpl('ulist_close', $bbcode_id),
                            '[/list:o:$uid]'    => $this->bbcode_tpl('olist_close', $bbcode_id),
                            '[*:$uid]'          => $this->bbcode_tpl('listitem', $bbcode_id),
                            '[/*:$uid]'         => $this->bbcode_tpl('listitem_close', $bbcode_id),
                            '[/*:m:$uid]'       => $this->bbcode_tpl('listitem_close', $bbcode_id)
                        ),
                    );
                break;
 
                case 10:
                    $this->bbcode_cache[$bbcode_id] = array(
                        'preg' => array(
                            '#\[email:$uid\]((.*?))\[/email:$uid\]#is'          => $this->bbcode_tpl('email', $bbcode_id),
                            '#\[email=([^\[]+):$uid\](.*?)\[/email:$uid\]#is'   => $this->bbcode_tpl('email', $bbcode_id)
                        )
                    );
                break;
 
                case 11:
                    if ($user->optionget('viewflash'))
                    {
                        $this->bbcode_cache[$bbcode_id] = array(
                            'preg' => array(
                                '#\[flash=([0-9]+),([0-9]+):$uid\](.*?)\[/flash:$uid\]#'    => $this->bbcode_tpl('flash', $bbcode_id),
                            )
                        );
                    }
                    else
                    {
                        $this->bbcode_cache[$bbcode_id] = array(
                            'preg' => array(
                                '#\[flash=([0-9]+),([0-9]+):$uid\](.*?)\[/flash:$uid\]#'    => str_replace('$1', '$3', str_replace('$2', '[ flash ]', $this->bbcode_tpl('url', $bbcode_id, true)))
                            )
                        );
                    }
                break;
 
                case 12:
                    $this->bbcode_cache[$bbcode_id] = array(
                        'str'   => array(
                            '[/attachment:$uid]'    => $this->bbcode_tpl('inline_attachment_close', $bbcode_id)
                        ),
                        'preg'  => array(
                            '#\[attachment=([0-9]+):$uid\]#'    => $this->bbcode_tpl('inline_attachment_open', $bbcode_id)
                        )
                    );
                break;
 
                default:
                    if (isset($rowset[$bbcode_id]))
                    {
                        if ($this->template_bitfield->get($bbcode_id))
                        {
                            // The bbcode requires a custom template to be loaded
                            if (!$bbcode_tpl = $this->bbcode_tpl($rowset[$bbcode_id]['bbcode_tag'], $bbcode_id))
                            {
                                // For some reason, the required template seems not to be available, use the default template
                                $bbcode_tpl = (!empty($rowset[$bbcode_id]['second_pass_replace'])) ? $rowset[$bbcode_id]['second_pass_replace'] : $rowset[$bbcode_id]['bbcode_tpl'];
                            }
                            else
                            {
                                // In order to use templates with custom bbcodes we need
                                // to replace all {VARS} to corresponding backreferences
                                // Note that backreferences are numbered from bbcode_match
                                if (preg_match_all('/\{(URL|LOCAL_URL|EMAIL|TEXT|SIMPLETEXT|IDENTIFIER|COLOR|NUMBER)[0-9]*\}/', $rowset[$bbcode_id]['bbcode_match'], $m))
                                {
                                    foreach ($m[0] as $i => $tok)
                                    {
                                        $bbcode_tpl = str_replace($tok, '$' . ($i + 1), $bbcode_tpl);
                                    }
                                }
                            }
                        }
                        else
                        {
                            // Default template
                            $bbcode_tpl = (!empty($rowset[$bbcode_id]['second_pass_replace'])) ? $rowset[$bbcode_id]['second_pass_replace'] : $rowset[$bbcode_id]['bbcode_tpl'];
                        }
 
                        // Replace {L_*} lang strings
                        $bbcode_tpl = preg_replace('/{L_([A-Z_]+)}/e', "(!empty(\$user->lang['\$1'])) ? \$user->lang['\$1'] : ucwords(strtolower(str_replace('_', ' ', '\$1')))", $bbcode_tpl);
 
                        if (!empty($rowset[$bbcode_id]['second_pass_replace']))
                        {
                            // The custom BBCode requires second-pass pattern replacements
                            $this->bbcode_cache[$bbcode_id] = array(
                                'preg' => array($rowset[$bbcode_id]['second_pass_match'] => $bbcode_tpl)
                            );
                        }
                        else
                        {
                            $this->bbcode_cache[$bbcode_id] = array(
                                'str' => array($rowset[$bbcode_id]['second_pass_match'] => $bbcode_tpl)
                            );
                        }
                    }
                    else
                    {
                        $this->bbcode_cache[$bbcode_id] = false;
                    }
                break;
            }
        }
    }
 
    /**
    * Return bbcode template
    */
    function bbcode_tpl($tpl_name, $bbcode_id = -1, $skip_bitfield_check = false)
    {
        static $bbcode_hardtpl = array();
        if (empty($bbcode_hardtpl))
        {
            global $user;
            
            $bbcode_hardtpl = array(
                'b_open'    => '<span style="font-weight: bold">',
                'b_close'   => '</span>',
                'i_open'    => '<span style="font-style: italic">',
                'i_close'   => '</span>',
                'u_open'    => '<span style="text-decoration: underline">',
                'u_close'   => '</span>',
                'img'       => '<a href="$1" target="_blank"><img src="$1" alt="' . $user->lang['IMAGE'] . '" width="450" border="0" /></a>',
                'size'      => '<span style="font-size: $1%; line-height: normal">$2</span>',
                'color'     => '<span style="color: $1">$2</span>',
                'email'     => '<a href="mailto:$1">$2</a>'
            );
        }
        
        if ($bbcode_id != -1 && !$skip_bitfield_check && !$this->template_bitfield->get($bbcode_id))
        {
            return (isset($bbcode_hardtpl[$tpl_name])) ? $bbcode_hardtpl[$tpl_name] : false;
        }
 
        if (empty($this->bbcode_template))
        {
            if (($tpl = file_get_contents($this->template_filename)) === false)
            {
                trigger_error('Could not load bbcode template', E_USER_ERROR);
            }
 
            // replace \ with \\ and then ' with \'.
            $tpl = str_replace('\\', '\\\\', $tpl);
            $tpl = str_replace("'", "\'", $tpl);
 
            // strip newlines and indent
            $tpl = preg_replace("/\n[\n\r\s\t]*/", '', $tpl);
 
            // Turn template blocks into PHP assignment statements for the values of $bbcode_tpl..
            $this->bbcode_template = array();
 
            $matches = preg_match_all('#<!-- BEGIN (.*?) -->(.*?)<!-- END (?:.*?) -->#', $tpl, $match);
 
            for ($i = 0; $i < $matches; $i++)
            {
                if (empty($match[1][$i]))
                {
                    continue;
                }
 
                $this->bbcode_template[$match[1][$i]] = $this->bbcode_tpl_replace($match[1][$i], $match[2][$i]);
            }
        }
 
        return (isset($this->bbcode_template[$tpl_name])) ? $this->bbcode_template[$tpl_name] : ((isset($bbcode_hardtpl[$tpl_name])) ? $bbcode_hardtpl[$tpl_name] : false);
    }
 
    /**
    * Return bbcode template replacement
    */
    function bbcode_tpl_replace($tpl_name, $tpl)
    {
        global $user;
 
        static $replacements = array(
            'quote_username_open'   => array('{USERNAME}'   => '$1'),
            'color'                 => array('{COLOR}'      => '$1', '{TEXT}'           => '$2'),
            'size'                  => array('{SIZE}'       => '$1', '{TEXT}'           => '$2'),
            'img'                   => array('{URL}'        => '$1'),
            'flash'                 => array('{WIDTH}'      => '$1', '{HEIGHT}'         => '$2', '{URL}'    => '$3'),
            'url'                   => array('{URL}'        => '$1', '{DESCRIPTION}'    => '$2'),
            'email'                 => array('{EMAIL}'      => '$1', '{DESCRIPTION}'    => '$2')
        );
 
        $tpl = preg_replace('/{L_([A-Z_]+)}/e', "(!empty(\$user->lang['\$1'])) ? \$user->lang['\$1'] : ucwords(strtolower(str_replace('_', ' ', '\$1')))", $tpl);
 
        if (!empty($replacements[$tpl_name]))
        {
            $tpl = strtr($tpl, $replacements[$tpl_name]);
        }
 
        return trim($tpl);
    }
 
    /**
    * Second parse list bbcode
    */
    function bbcode_list($type)
    {
        if ($type == '')
        {
            $tpl = 'ulist_open_default';
            $type = 'default';
        }
        else if ($type == 'i')
        {
            $tpl = 'olist_open';
            $type = 'lower-roman';
        }
        else if ($type == 'I')
        {
            $tpl = 'olist_open';
            $type = 'upper-roman';
        }
        else if (preg_match('#^(disc|circle|square)$#i', $type))
        {
            $tpl = 'ulist_open';
            $type = strtolower($type);
        }
        else if (preg_match('#^[a-z]$#', $type))
        {
            $tpl = 'olist_open';
            $type = 'lower-alpha';
        }
        else if (preg_match('#[A-Z]#', $type))
        {
            $tpl = 'olist_open';
            $type = 'upper-alpha';
        }
        else if (is_numeric($type))
        {
            $tpl = 'olist_open';
            $type = 'arabic-numbers';
        }
        else
        {
            $tpl = 'olist_open';
            $type = 'arabic-numbers';
        }
 
        return str_replace('{LIST_TYPE}', $type, $this->bbcode_tpl($tpl));
    }
 
    /**
    * Second parse quote tag
    */
    function bbcode_second_pass_quote($username, $quote)
    {
        // when using the /e modifier, preg_replace slashes double-quotes but does not
        // seem to slash anything else
        $quote = str_replace('\"', '"', $quote);
        $username = str_replace('\"', '"', $username);
 
        // remove newline at the beginning
        if ($quote == "\n")
        {
            $quote = '';
        }
 
        $quote = (($username) ? str_replace('$1', $username, $this->bbcode_tpl('quote_username_open')) : $this->bbcode_tpl('quote_open')) . $quote;
 
        return $quote;
    }
 
    /**
    * Second parse code tag
    */
    function bbcode_second_pass_code($type, $code)
    {
        // when using the /e modifier, preg_replace slashes double-quotes but does not
        // seem to slash anything else
        $code = str_replace('\"', '"', $code);
 
        switch ($type)
        {
            case 'php':
                // Not the english way, but valid because of hardcoded syntax highlighting
                if (strpos($code, '<span class="syntaxdefault"><br /></span>') === 0)
                {
                    $code = substr($code, 41);
                }
 
            // no break;
 
            default:
                $code = str_replace("\t", '&nbsp; &nbsp;', $code);
                $code = str_replace('  ', '&nbsp; ', $code);
                $code = str_replace('  ', ' &nbsp;', $code);
 
                // remove newline at the beginning
                if (!empty($code) && $code[0] == "\n")
                {
                    $code = substr($code, 1);
                }
            break;
        }
 
        $code = $this->bbcode_tpl('code_open') . $code . $this->bbcode_tpl('code_close');
 
        return $code;
    }
}
 
?>
I know a few people (mods) on this board may have played with the bbcode before. So.. any help?
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
Kieran Huggins
DevNet Master
Posts: 3635
Joined: Wed Dec 06, 2006 4:14 pm
Location: Toronto, Canada
Contact:

Re: Some help hacking phpbb3 bbcode

Post by Kieran Huggins »

I'd use the CSS max-width property. Unsupported in IE 6 and lower, but we're up to what, IE 8 now? And this isn't what I'd call a dealbreaker, they can suffer with wide images if they insist on using a seven year old browser with two free, major upgrades. Three if you count FF ;-)

Also, you have successfully killed the layout of this thread - awesome! :drunk:
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Re: Some help hacking phpbb3 bbcode

Post by s.dot »

I'd rather hack it on the PHP level than the css level. But I may resort to that! Thanks!

Yeah, it seems phpbb won't parse their own bbcode.php file.. hmm, perhaps some kind of weird bug with the eval statements they use? That, or I totally posted it wrong.
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
Post Reply