diff --git a/phpBB/adm/admin_bbcodes.php b/phpBB/adm/admin_bbcodes.php new file mode 100644 index 0000000000..b123d4862c --- /dev/null +++ b/phpBB/adm/admin_bbcodes.php @@ -0,0 +1,416 @@ +acl_get('a_bbcode')) + { + return; + } + + $filename = basename(__FILE__); + $module['POST']['BBCODES'] = $filename . $SID; + + return; +} + +define('IN_PHPBB', 1); + +// Include files +$phpbb_root_path = '../'; +$phpEx = substr(strrchr(__FILE__, '.'), 1); +require('pagestart.' . $phpEx); + +// Do we have general permissions? +if (!$auth->acl_get('a_bbcode')) +{ + trigger_error($user->lang['NO_ADMIN']); +} + +// Set up general vars +$mode = (!empty($_REQUEST['mode'])) ? $_REQUEST['mode'] : ''; +$bbcode_id = (!empty($_REQUEST['bbcode'])) ? intval($_REQUEST['bbcode']) : 0; + +// Set up mode-specific vars +switch ($mode) +{ + case 'add': + $bbcode_match = $bbcode_tpl = ''; + break; + + case 'edit': + $sql = 'SELECT bbcode_match, bbcode_tpl + FROM ' . BBCODES_TABLE . ' + WHERE bbcode_id = ' . $bbcode_id; + $result = $db->sql_query($sql); + if (!$row = $db->sql_fetchrow($result)) + { + trigger_error('BBCODE_NOT_EXIST'); + } + + $bbcode_match = $row['bbcode_match']; + $bbcode_tpl = htmlspecialchars($row['bbcode_tpl']); + break; + + case 'modify': + $sql = 'SELECT bbcode_id + FROM ' . BBCODES_TABLE . ' + WHERE bbcode_id = ' . $bbcode_id; + $result = $db->sql_query($sql); + if (!$row = $db->sql_fetchrow($result)) + { + trigger_error('BBCODE_NOT_EXIST'); + } + + // No break here + + case 'create': + $bbcode_match = htmlspecialchars(stripslashes($_POST['bbcode_match'])); + $bbcode_tpl = stripslashes($_POST['bbcode_tpl']); + break; +} + +// Do major work +switch ($mode) +{ + case 'edit': + case 'add': + adm_page_header($user->lang['BBCODES']); + +?> + +

lang['BBCODES'] ?>

+ +

lang['BBCODES_EXPLAIN'] ?>

+ +
"> + + + + +
+ + + + + + + + + + +
lang['BBCODE_USAGE'] ?>
lang['BBCODE_USAGE_EXPLAIN'] ?>
lang['EXAMPLES'] ?>

lang['BBCODE_USAGE_EXAMPLE'] ?>
+ +
+ + + + + +
+ + + + + + + + + + + + + +
lang['HTML_REPLACEMENT'] ?>
lang['HTML_REPLACEMENT_EXPLAIN'] ?>
lang['EXAMPLES'] ?>

lang['HTML_REPLACEMENT_EXAMPLE'] ?>
+ +
+ + + + + +
+ + + + + + + + + + +lang['tokens'] as $token => $token_explain) + { + ?> + + + +
lang['TOKENS'] ?>
lang['TOKENS_EXPLAIN'] ?>
lang['TOKEN'] ?>lang['TOKEN_DEFINITION'] ?>
{}
+
+ +lang['BBCODES']); + + $data = build_regexp($bbcode_match, $bbcode_tpl); + + $sql_ary = array( + 'bbcode_tag' => $data['bbcode_tag'], + 'bbcode_match' => $bbcode_match, + 'bbcode_tpl' => $bbcode_tpl, + 'first_pass_match' => $data['first_pass_match'], + 'first_pass_replace' => $data['first_pass_replace'], + 'second_pass_match' => $data['second_pass_match'], + 'second_pass_replace' => $data['second_pass_replace'] + ); + + if ($mode == 'create') + { + // TODO: look for SQL incompatibilities + // NOTE: I'm sure there was another simpler (and obvious) way of finding a suitable bbcode_id + $sql = 'SELECT b1.bbcode_id + FROM ' . BBCODES_TABLE . ' b1, ' . BBCODES_TABLE . ' b2 + WHERE b2.bbcode_id > b1.bbcode_id + GROUP BY b1.bbcode_id + HAVING MIN(b2.bbcode_id) > b1.bbcode_id + 1 + ORDER BY b1.bbcode_id ASC'; + $result = $db->sql_query_limit($sql, 1); + + if ($row = $db->sql_fetchrow($result)) + { + $bbcode_id = $row['bbcode_id'] + 1; + } + else + { + $sql = 'SELECT MIN(bbcode_id) AS min_id, MAX(bbcode_id) AS max_id + FROM ' . BBCODES_TABLE; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + + if (empty($row['min_id']) || $row['min_id'] > 12) + { + $bbcode_id = 12; + } + else + { + $bbcode_id = $row['max_id'] + 1; + } + } + + if ($bbcode_id > 31) + { + trigger_error('TOO_MANY_BBCODES'); + } + + $sql_ary['bbcode_id'] = (int) $bbcode_id; + + $db->sql_query('INSERT INTO ' . BBCODES_TABLE . $db->sql_build_array('INSERT', $sql_ary)); + $lang = 'BBCODE_ADDED'; + } + else + { + $db->sql_query('UPDATE ' . BBCODES_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' WHERE bbcode_id = ' . $bbcode_id); + $lang = 'BBCODE_EDITED'; + } + + trigger_error($lang); + break; + + case 'delete': + $db->sql_query('DELETE FROM ' . BBCODES_TABLE . " WHERE bbcode_id = $bbcode_id"); + + // No break here + + default: + + adm_page_header($user->lang['BBCODES']); + +?> + +

lang['BBCODES'] ?>

+ +

lang['BBCODES_EXPLAIN'] ?>

+ + +
+ + + +
+ + + + sql_query($sql); + + $row_class = ''; + while ($row = $db->sql_fetchrow($result)) + { + $row_class = ($row_class == 'row1') ? 'row2' : 'row1'; +?> + + + + + + + + + +
lang['BBCODE_TAG'] ?>lang['ACTION'] ?>
lang['EDIT'] ?> | lang['DELETE'] ?>
+ + array( + '!([a-z0-9]+://)?(.*?[^ \t\n\r<"]*)!ise' => "(('\$1') ? '\$1\$2' : 'http://\$2')" + ), + 'LOCAL_URL' => array( + '!([^:]+/[^ \t\n\r<"]*)!' => '$1' + ), + 'EMAIL' => array( + '!([a-z0-9]+[a-z0-9\-\._]*@(?:(?:[0-9]{1,3}\.){3,5}[0-9]{1,3}|[a-z0-9]+[a-z0-9\-\._]*\.[a-z]+))!i' => '$1' + ), + 'TEXT' => array( + '!(.*?)!es' => "str_replace('\\\"', '"', str_replace('\\'', ''', '\$1'))" + ), + 'COLOR' => array( + '!([a-z]+|#[0-9abcdef]+!i' => '$1' + ), + 'NUMBER' => array( + '!([0-9]+)!' => '$1' + ) + ); + + if (preg_match_all('/\{(' . implode('|', array_keys($tokens)) . ')[0-9]*\}/i', $msg_bbcode, $m)) + { + $pad = 0; + $modifiers = 'i'; + + foreach ($m[0] as $n => $token) + { + $token_type = $m[1][$n]; + + reset($tokens[$token_type]); + list($match, $replace) = each($tokens[$token_type]); + + // Pad backreference numbers from tokens + if (preg_match_all('/(? $bbcode_tag, + 'first_pass_match' => $fp_match, + 'first_pass_replace' => $fp_replace, + 'second_pass_match' => $sp_match, + 'second_pass_replace' => $sp_replace + ); +} +// End Functions +// ----------------------------- +?> \ No newline at end of file diff --git a/phpBB/includes/bbcode.php b/phpBB/includes/bbcode.php index 673513fd41..7ce2f59ec5 100644 --- a/phpBB/includes/bbcode.php +++ b/phpBB/includes/bbcode.php @@ -1,23 +1,15 @@ bbcode_bitfield & (1 << $bbcode_id)) { - foreach ($this->bbcode_cache[$bbcode_id] as $type => $array) + if (!empty($this->bbcode_cache[$bbcode_id])) { - foreach ($array as $search => $replace) + foreach ($this->bbcode_cache[$bbcode_id] as $type => $array) { - ${$type}['search'][] = str_replace('$uid', $this->bbcode_uid, $search); - ${$type}['replace'][] = $replace; - + foreach ($array as $search => $replace) + { + ${$type}['search'][] = str_replace('$uid', $this->bbcode_uid, $search); + ${$type}['replace'][] = $replace; + } } } } @@ -88,7 +82,8 @@ class bbcode $message = preg_replace($preg['search'], $preg['replace'], $message); } - return $message; + // Remove the uid from tags that have not been transformed into HTML + $message = str_replace(':' . $this->bbcode_uid, '', $message); } // @@ -99,19 +94,17 @@ class bbcode // function bbcode_cache_init() { + global $user, $phpbb_root_path; + if (empty($this->template_filename)) { - global $user, $phpbb_root_path; - $style = 'primary'; if (!empty($user->theme['secondary'])) { - $merged_bitfield = $user->theme['primary']['bbcode_bitfield'] | $user->theme['secondary']['bbcode_bitfield']; + // If the primary style has custom templates for BBCodes then we'll make sure + // the bbcode.html file is present, otherwise we'll use the secondary style - // If any of styles has a specific template for any of applicable - // bbcodes then load the primary bbcode.html if present, otherwise - // load the secondary bbcode.html file - if ($this->bbcode_bitfield & $merged_bitfield) + if ($this->bbcode_bitfield & $user->theme['primary']['bbcode_bitfield']) { $style = (file_exists($phpbb_root_path . 'styles/templates/' . $user->theme['primary']['template_path'] . '/bbcode.html')) ? 'primary' : 'secondary'; } @@ -134,21 +127,20 @@ class bbcode } $bbcode_ids[$bbcode_id] = $bbcode_id; - // WARNING: hardcoded values. it assumes that bbcodes with bbcode_id > 11 are user-defined bbcodes if ($bbcode_id > 11) { - $sql .= (($sql) ? ',' : '') . $bbcode_id . ','; + $sql .= (($sql) ? ',' : '') . $bbcode_id; } } -/* + if ($sql) { global $db; $rowset = array(); - $sql = 'SELECT bbcode_id, second_pass_regexp, second_pass_replacement + $sql = 'SELECT * FROM ' . BBCODES_TABLE . " - WHERE bbcode_id IN ($sql); + WHERE bbcode_id IN ($sql)"; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) @@ -157,7 +149,6 @@ class bbcode } $db->sql_freeresult($result); } -*/ foreach ($bbcode_ids as $bbcode_id) { @@ -202,7 +193,7 @@ class bbcode else { $this->bbcode_cache[$bbcode_id] = array('preg' => array( - '#\[img:$uid\](.*?)\[/img:$uid\]#s' => str_replace('\\2', '[ img ]', $this->bbcode_tpl('url', $bbcode_id)) + '#\[img:$uid\](.*?)\[/img:$uid\]#s' => str_replace('$2', '[ img ]', $this->bbcode_tpl('url', $bbcode_id)) )); } break; @@ -224,7 +215,7 @@ class bbcode 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')" + '#\[code(?:=([a-z]+))?:$uid\](.*?)\[/code:$uid\]#ise' => "\$this->bbcode_second_pass_code('\$1', '\$2')" )); break; case 9: @@ -238,13 +229,13 @@ class bbcode '[/*:m:$uid]' => $this->bbcode_tpl('listitem_close', $bbcode_id) ), 'preg' => array( - '#\[list=([^\[]+):$uid\]#e' => "\$this->bbcode_list('\\1')", + '#\[list=([^\[]+):$uid\]#e' => "\$this->bbcode_list('\$1')", ) ); 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), '#\[email=([^\[]+):$uid\](.*?)\[/email:$uid\]#is' => $this->bbcode_tpl('email', $bbcode_id) )); break; @@ -258,20 +249,67 @@ class bbcode 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))) + '#\[flash=([0-9]+),([0-9]+):$uid\](.*?)\[/flash:$uid\]#' => str_replace('$1', '$3', str_replace('$2', '[ flash ]', $this->bbcode_tpl('url', $bbcode_id))) )); } break; default: if (isset($rowset[$bbcode_id])) { - $this->bbcode_cache[$bbcode_id] = array( - 'preg' => array($rowset[$bbcode_id]['second_pass_regexp'], $rowset[$bbcode_id]['second_pass_replacement']) - ); + if ($this->template_bitfield & (1 << $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|EMAIL|TEXT|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] = array(); + $this->bbcode_cache[$bbcode_id] = FALSE; } } } @@ -284,21 +322,21 @@ class bbcode static $bbcode_hardtpl = array( 'b_open' => '', 'b_close' => '', - 'i_open' => '', - 'i_close' => '', + 'i_open' => '', + 'i_close' => '', 'u_open' => '', 'u_close' => '', - 'url' => '\2', - 'img' => '', - 'size' => '\2', - 'color' => '\2', - 'email' => '\2' + 'url' => '$2', + 'img' => '', + 'size' => '$2', + 'color' => '$2', + 'email' => '$2' ); } if ($bbcode_id != -1 && !($this->template_bitfield & (1 << $bbcode_id))) { - return $bbcode_hardtpl[$tpl_name]; + return (isset($bbcode_hardtpl[$tpl_name])) ? $bbcode_hardtpl[$tpl_name] : FALSE; } if (empty($this->bbcode_template)) @@ -318,28 +356,28 @@ class bbcode $tpl = preg_replace("/\n[\n\r\s\t]*/", '', $tpl); // Turn template blocks into PHP assignment statements for the values of $bbcode_tpl.. - $tpl = preg_replace('#(.*?)#', "\n" . "\$this->bbcode_template['\\1'] = \$this->bbcode_tpl_replace('\\1','\\2');", $tpl); + $tpl = preg_replace('#(.*?)#', "\n" . "\$this->bbcode_template['\$1'] = \$this->bbcode_tpl_replace('\$1','\$2');", $tpl); $this->bbcode_template = array(); eval($tpl); } - return $this->bbcode_template[$tpl_name]; + return (isset($this->bbcode_template[$tpl_name])) ? $this->bbcode_template[$tpl_name] : ((isset($bbcode_hardtpl[$tpl_name])) ? $bbcode_hardtpl[$tpl_name] : FALSE); } function bbcode_tpl_replace($tpl_name, $tpl) { 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') + '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('\\1'))", $tpl); + $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])) { @@ -405,7 +443,9 @@ class bbcode function bbcode_second_pass_code($type, $code) { - $code = stripslashes($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) { diff --git a/phpBB/includes/message_parser.php b/phpBB/includes/message_parser.php index 16b6208975..450656d8e7 100644 --- a/phpBB/includes/message_parser.php +++ b/phpBB/includes/message_parser.php @@ -1,31 +1,21 @@ message_mode = $message_type; @@ -116,7 +108,7 @@ class parse_message if (sizeof($allowed_tags)) { - $this->message = preg_replace('#<(\/?)(' . str_replace('*', '.*?', implode('|', $allowed_tags)) . ')>#is', '<\1\2>', $this->message); + $this->message = preg_replace('#<(\/?)(' . str_replace('*', '.*?', implode('|', $allowed_tags)) . ')>#is', '<$1$2>', $this->message); } } } @@ -170,27 +162,29 @@ class parse_message // This array holds all bbcode data. BBCodes will be processed in this order, so it is important to // keep [code] in first position and [quote] in second position. $this->bbcodes = array( - 'code' => array('bbcode_id' => 8, 'regexp' => array('#\[code(?:=([a-z]+))?\](.+\[/code\])#ise' => "\$this->bbcode_code('\\1', '\\2')")), - 'quote' => array('bbcode_id' => 0, 'regexp' => array('#\[quote(?:="(.*?)")?\](.+)\[/quote\]#ise' => "\$this->bbcode_quote('\\0')")), - 'b' => array('bbcode_id' => 1, 'regexp' => array('#\[b\](.*?)\[/b\]#is' => '[b:' . $this->bbcode_uid . ']\1[/b:' . $this->bbcode_uid . ']')), - 'i' => array('bbcode_id' => 2, 'regexp' => array('#\[i\](.*?)\[/i\]#is' => '[i:' . $this->bbcode_uid . ']\1[/i:' . $this->bbcode_uid . ']')), - 'url' => array('bbcode_id' => 3, 'regexp' => array('#\[url=?(.*?)?\](.*?)\[/url\]#ise' => "\$this->validate_url('\\1', '\\2')")), - 'img' => array('bbcode_id' => 4, 'regexp' => array('#\[img\](https?://)([a-z0-9\-\.,\?!%\*_:;~\\&$@/=\+]+)\[/img\]#i' => '[img:' . $this->bbcode_uid . ']\1\2[/img:' . $this->bbcode_uid . ']')), - 'size' => array('bbcode_id' => 5, 'regexp' => array('#\[size=([\-\+]?[1-2]?[0-9])\](.*?)\[/size\]#is' => '[size=\1:' . $this->bbcode_uid . ']\2[/size:' . $this->bbcode_uid . ']')), - 'color' => array('bbcode_id' => 6, 'regexp' => array('!\[color=(#[0-9A-F]{6}|[a-z\-]+)\](.*?)\[/color\]!is' => '[color=\1:' . $this->bbcode_uid . ']\2[/color:' . $this->bbcode_uid . ']')), - 'u' => array('bbcode_id' => 7, 'regexp' => array('#\[u\](.*?)\[/u\]#is' => '[u:' . $this->bbcode_uid . ']\1[/u:' . $this->bbcode_uid . ']')), - 'list' => array('bbcode_id' => 9, 'regexp' => array('#\[list(=[a-z|0-9|(?:disc|circle|square))]+)?\].*\[/list\]#ise' => "\$this->bbcode_list('\\0')")), - 'email' => array('bbcode_id' => 10, 'regexp' => array('#\[email=?(.*?)?\](.*?)\[/email\]#ise' => "\$this->validate_email('\\1', '\\2')")), - 'flash' => array('bbcode_id' => 11, 'regexp' => array('#\[flash=([0-9]+),([0-9]+)\](.*?)\[/flash\]#i' => '[flash=\1,\2:' . $this->bbcode_uid . ']\3[/flash:' . $this->bbcode_uid . ']')) + 'code' => array('bbcode_id' => 8, 'regexp' => array('#\[code(?:=([a-z]+))?\](.+\[/code\])#ise' => "\$this->bbcode_code('\$1', '\$2')")), + 'quote' => array('bbcode_id' => 0, 'regexp' => array('#\[quote(?:="(.*?)")?\](.+)\[/quote\]#ise' => "\$this->bbcode_quote('\$0')")), + 'b' => array('bbcode_id' => 1, 'regexp' => array('#\[b\](.*?)\[/b\]#is' => '[b:' . $this->bbcode_uid . ']$1[/b:' . $this->bbcode_uid . ']')), + 'i' => array('bbcode_id' => 2, 'regexp' => array('#\[i\](.*?)\[/i\]#is' => '[i:' . $this->bbcode_uid . ']$1[/i:' . $this->bbcode_uid . ']')), + 'url' => array('bbcode_id' => 3, 'regexp' => array('#\[url=?(.*?)?\](.*?)\[/url\]#ise' => "\$this->validate_url('\$1', '\$2')")), + 'img' => array('bbcode_id' => 4, 'regexp' => array('#\[img\](https?://)([a-z0-9\-\.,\?!%\*_:;~\\&$@/=\+]+)\[/img\]#i' => '[img:' . $this->bbcode_uid . ']$1$2[/img:' . $this->bbcode_uid . ']')), + 'size' => array('bbcode_id' => 5, 'regexp' => array('#\[size=([\-\+]?[1-2]?[0-9])\](.*?)\[/size\]#is' => '[size=$1:' . $this->bbcode_uid . ']$2[/size:' . $this->bbcode_uid . ']')), + 'color' => array('bbcode_id' => 6, 'regexp' => array('!\[color=(#[0-9A-F]{6}|[a-z\-]+)\](.*?)\[/color\]!is' => '[color=$1:' . $this->bbcode_uid . ']$2[/color:' . $this->bbcode_uid . ']')), + 'u' => array('bbcode_id' => 7, 'regexp' => array('#\[u\](.*?)\[/u\]#is' => '[u:' . $this->bbcode_uid . ']$1[/u:' . $this->bbcode_uid . ']')), + 'list' => array('bbcode_id' => 9, 'regexp' => array('#\[list(=[a-z|0-9|(?:disc|circle|square))]+)?\].*\[/list\]#ise' => "\$this->bbcode_list('\$0')")), + 'email' => array('bbcode_id' => 10, 'regexp' => array('#\[email=?(.*?)?\](.*?)\[/email\]#ise' => "\$this->validate_email('\$1', '\$2')")), + 'flash' => array('bbcode_id' => 11, 'regexp' => array('#\[flash=([0-9]+),([0-9]+)\](.*?)\[/flash\]#i' => '[flash=$1,$2:' . $this->bbcode_uid . ']$3[/flash:' . $this->bbcode_uid . ']')) ); -/************** if (!isset($rowset)) { global $db; $rowset = array(); - $result = $db->sql_query('SELECT * FROM ' . BBCODES_TABLE); + $sql = 'SELECT bbcode_id, bbcode_tag, first_pass_match, first_pass_replace + FROM ' . BBCODES_TABLE; + + $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { $rowset[] = $row; @@ -198,19 +192,19 @@ class parse_message } foreach ($rowset as $row) { - $this->bbcodes[$row['bbcode_name']] = array( - 'bbcode_id' => $row['bbcode_id'], - 'regexp' => array($row['first_pass_regexp'] => str_replace('$uid', $this->bbcode_uid, $row['first_pass_replacement'])) + $this->bbcodes[$row['bbcode_tag']] = array( + 'bbcode_id' => intval($row['bbcode_id']), + 'regexp' => array($row['first_pass_match'] => str_replace('$uid', $this->bbcode_uid, $row['first_pass_replace'])) ); } -**************/ } // Expects the argument to start right after the opening [code] tag and to end with [/code] function bbcode_code($stx, $in) { - // if I remember correctly, preg_replace() will slash passed vars - $in = str_replace("\r\n", "\n", stripslashes($in)); + // when using the /e modifier, preg_replace slashes double-quotes but does not + // seem to slash anything else + $in = str_replace("\r\n", "\n", str_replace('\"', '"', $in)); $out = ''; do @@ -237,7 +231,7 @@ class parse_message } $code = substr($code, 0, -7); - $code = preg_replace('#^[\r\n]*(.*?)[\n\r\s\t]*$#s', '\1', $code); + $code = preg_replace('#^[\r\n]*(.*?)[\n\r\s\t]*$#s', '$1', $code); switch (strtolower($stx)) { @@ -273,12 +267,18 @@ class parse_message $str_to[] = ''; $str_from[] = '<?php '; $str_to[] = ''; - $str_from[] = '?>'; - $str_to[] = ''; } $code = str_replace($str_from, $str_to, $code); - $code = preg_replace('#^()\n?(.*?)\n?()$#is', '\1\2\3', $code); + $code = preg_replace('#^()\n?(.*?)\n?()$#is', '$1$2$3', $code); + + if ($remove_tags) + { + $code = preg_replace('#()?\?>#', '', $code); + } + + $code = preg_replace('#^(.*)#s', '$2', $code); + $code = preg_replace('#(?:[\n\r\s\t]| )*$#', '', $code); $out .= "[code=$stx:" . $this->bbcode_uid . ']' . trim($code) . '[/code:' . $this->bbcode_uid . ']'; break; @@ -308,7 +308,8 @@ class parse_message $tok = ']'; $out = '['; - $in = substr(stripslashes($in), 1); + + $in = substr(str_replace('\"', '"', $in), 1); $list_end_tags = $item_end_tags = array(); do @@ -423,7 +424,7 @@ class parse_message $tok = ']'; $out = '['; - $in = substr(stripslashes($in), 1); + $in = substr(str_replace('\"', '"', $in), 1); $close_tags = $error_ary = array(); $buffer = ''; @@ -472,7 +473,7 @@ class parse_message if (!empty($m[1])) { - $username = preg_replace('#\[(?!b|i|u|color|url|email|/b|/i|/u|/color|/url|/email)#iU', '[\1', $m[1]); + $username = preg_replace('#\[(?!b|i|u|color|url|email|/b|/i|/u|/color|/url|/email)#iU', '[$1', $m[1]); $end_tags = array(); $error = FALSE; @@ -547,10 +548,29 @@ class parse_message function validate_email($var1, $var2) { - $var1 = stripslashes($var1); - $var2 = stripslashes($var2); + $txt = stripslashes($var2); + $email = ($var1 != '') ? stripslashes($var1) : stripslashes($var2); - $retval = '[email' . $var1 . ':' . $this->bbcode_uid . ']' . $var2 . '[/email:' . $this->bbcode_uid . ']'; + $validated = TRUE; + + if (!preg_match('!([a-z0-9]+[a-z0-9\-\._]*@(?:(?:[0-9]{1,3}\.){3,5}[0-9]{1,3}|[a-z0-9]+[a-z0-9\-\._]*\.[a-z]+))!i', $email)) + { + $validated = FALSE; + } + + if (!$validated) + { + return '[email' . (($var1) ? "=$var1" : '') . ']' . $var2 . '[/email]'; + } + + if ($var1) + { + $retval = '[email=' . $email . ':' . $this->bbcode_uid . ']' . $txt . '[/email:' . $this->bbcode_uid . ']'; + } + else + { + $retval = '[email:' . $this->bbcode_uid . ']' . $email . '[/email:' . $this->bbcode_uid . ']'; + } return $retval; } @@ -587,20 +607,20 @@ class parse_message $replace = array(); // relative urls for this board - $match[] = '#(^|[\n ])' . $server_protocol . trim($config['server_name']) . $server_port . preg_replace('/^\/?(.*?)(\/)?$/', '\1', trim($config['script_path'])) . '/([^ \t\n\r <"\']+)#i'; - $replace[] = '\1'; + $match[] = '#(^|[\n ])' . $server_protocol . trim($config['server_name']) . $server_port . preg_replace('/^\/?(.*?)(\/)?$/', '$1', trim($config['script_path'])) . '/([^ \t\n\r <"\']+)#i'; + $replace[] = '$1'; // matches a xxxx://aaaaa.bbb.cccc. ... $match[] = '#(^|[\n ])([\w]+?://.*?[^ \t\n\r<"]*)#ie'; - $replace[] = "'\\1' . ((strlen('\\2') > 55) ? substr('\\2', 0, 39) . ' ... ' . substr('\\2', -10) : '\\2') . ''"; + $replace[] = "'\$1' . ((strlen('\$2') > 55) ? substr('\$2', 0, 39) . ' ... ' . substr('\$2', -10) : '\$2') . ''"; // matches a "www.xxxx.yyyy[/zzzz]" kinda lazy URL thing $match[] = '#(^|[\n ])(www\.[\w\-]+\.[\w\-.\~]+(?:/[^ \t\n\r<"]*)?)#ie'; - $replace[] = "'\\1' . ((strlen('\\2') > 55) ? substr(str_replace(' ', '%20', '\\2'), 0, 39) . ' ... ' . substr('\\2', -10) : '\\2') . ''"; + $replace[] = "'\$1' . ((strlen('\$2') > 55) ? substr(str_replace(' ', '%20', '\$2'), 0, 39) . ' ... ' . substr('\$2', -10) : '\$2') . ''"; // matches an email@domain type address at the start of a line, or after a space. $match[] = '#(^|[\n ])([a-z0-9&\-_.]+?@[\w\-]+\.([\w\-\.]+\.)?[\w]+)#ie'; - $replace[] = "'\\1' . ((strlen('\\2') > 55) ? substr('\\2', 0, 39) . ' ... ' . substr('\\2', -10) : '\\2') . ''"; + $replace[] = "'\$1' . ((strlen('\$2') > 55) ? substr('\$2', 0, 39) . ' ... ' . substr('\$2', -10) : '\$2') . ''"; $this->message = preg_replace($match, $replace, $this->message); } @@ -622,6 +642,7 @@ class parse_message if ($row = $db->sql_fetchrow($result)) { $match = $replace = array(); + do { $match[] = '#(' . preg_quote($row['code'], '#') . ')#'; @@ -643,7 +664,6 @@ class parse_message $this->message = preg_replace($match, $replace, ' ' . $this->message . ' '); } - $db->sql_freeresult($result); } function parse_attachments($mode, $post_id, $submit, $preview, $refresh) @@ -956,7 +976,7 @@ class fulltext_search { $sql = 'SELECT word_id, word_text FROM ' . SEARCH_WORD_TABLE . ' - WHERE word_text IN (' . implode(', ', preg_replace('#^(.*)$#', '\'\1\'', $unique_add_words)) . ")"; + WHERE word_text IN (' . implode(', ', preg_replace('#^(.*)$#', '\'$1\'', $unique_add_words)) . ")"; $result = $db->sql_query($sql); $word_ids = array(); @@ -976,13 +996,13 @@ class fulltext_search case 'mysql': case 'mysql4': $sql = 'INSERT INTO ' . SEARCH_WORD_TABLE . ' (word_text) - VALUES ' . implode(', ', preg_replace('#^(.*)$#', '(\'\1\')', $new_words)); + VALUES ' . implode(', ', preg_replace('#^(.*)$#', '(\'$1\')', $new_words)); $db->sql_query($sql); break; case 'mssql': case 'sqlite': - $sql = 'INSERT INTO ' . SEARCH_WORD_TABLE . ' (word_text) ' . implode(' UNION ALL ', preg_replace('#^(.*)$#', "SELECT '\\1'", $new_words)); + $sql = 'INSERT INTO ' . SEARCH_WORD_TABLE . ' (word_text) ' . implode(' UNION ALL ', preg_replace('#^(.*)$#', "SELECT '\$1'", $new_words)); $db->sql_query($sql); break; @@ -1029,7 +1049,7 @@ class fulltext_search $sql = 'INSERT INTO ' . SEARCH_MATCH_TABLE . " (post_id, word_id, title_match) SELECT $post_id, word_id, $title_match FROM " . SEARCH_WORD_TABLE . ' - WHERE word_text IN (' . implode(', ', preg_replace('#^(.*)$#', '\'\1\'', $word_ary)) . ')'; + WHERE word_text IN (' . implode(', ', preg_replace('#^(.*)$#', '\'$1\'', $word_ary)) . ')'; $db->sql_query($sql); } }