mirror of
https://github.com/e107inc/e107.git
synced 2025-04-20 04:32:01 +02:00
Bugtracker #2791 - handle nested bbcodes. Seems to be a bit faster as well, and case insensitive on the bbcode
This commit is contained in:
parent
cba65eb4da
commit
ab9f59cc3d
@ -12,8 +12,8 @@
|
||||
| GNU General Public License (http://gnu.org).
|
||||
|
|
||||
| $Source: /cvs_backup/e107_0.8/e107_handlers/bbcode_handler.php,v $
|
||||
| $Revision: 1.3 $
|
||||
| $Date: 2007-01-02 20:20:37 $
|
||||
| $Revision: 1.4 $
|
||||
| $Date: 2007-02-15 21:37:22 $
|
||||
| $Author: e107steved $
|
||||
+----------------------------------------------------------------------------+
|
||||
*/
|
||||
@ -22,11 +22,8 @@ if (!defined('e107_INIT')) { exit; }
|
||||
|
||||
class e_bbcode
|
||||
{
|
||||
|
||||
var $bbList;
|
||||
var $bbLocation;
|
||||
var $single_bb;
|
||||
var $List;
|
||||
var $bbList; // Caches the file contents for each bbcode processed
|
||||
var $bbLocation; // Location for each file - 'core' or a plugin name
|
||||
|
||||
function e_bbcode()
|
||||
{
|
||||
@ -43,114 +40,194 @@ class e_bbcode
|
||||
|
||||
foreach($core_bb as $c)
|
||||
{
|
||||
$this->bbLocation[$c] = 'core';
|
||||
$this->bbLocation[$c] = 'core';
|
||||
}
|
||||
|
||||
|
||||
// grab list of plugin bbcodes.
|
||||
if(isset($pref['bbcode_list']) && $pref['bbcode_list'] != '')
|
||||
{
|
||||
foreach($pref['bbcode_list'] as $path=>$namearray)
|
||||
foreach($pref['bbcode_list'] as $path=>$namearray)
|
||||
{
|
||||
foreach($namearray as $code=>$uclass)
|
||||
{
|
||||
foreach($namearray as $code=>$uclass)
|
||||
{
|
||||
$this->bbLocation[$code] = $path;
|
||||
}
|
||||
$this->bbLocation[$code] = $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Eliminate duplicates
|
||||
$this->bbLocation = array_diff($this->bbLocation, array(''));
|
||||
krsort($this->bbLocation);
|
||||
$this->List = array_keys($this->bbLocation);
|
||||
while($this->List[count($this->List)-1]{0} == "_")
|
||||
{
|
||||
array_unshift($this->List, array_pop($this->List));
|
||||
}
|
||||
if(($_c = array_search('code', $this->List)) !== FALSE)
|
||||
{
|
||||
unset($this->List[$c]);
|
||||
array_unshift($this->List, "code");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function parseBBCodes($text, $p_ID)
|
||||
|
||||
|
||||
function parseBBCodes($value, $p_ID, $force_lower = 'default')
|
||||
{
|
||||
global $postID;
|
||||
$postID = $p_ID;
|
||||
|
||||
if (strlen($value) <= 6) return $value; // Don't waste time on trivia!
|
||||
if ($force_lower == 'default') $force_lower = TRUE; // Set the default behaviour if not overridden
|
||||
$code_stack = array(); // Stack for unprocessed bbcodes and text
|
||||
$unmatch_stack = array(); // Stack for unmatched bbcodes
|
||||
$result = ''; // Accumulates fully processed text
|
||||
$stacktext = ''; // Accumulates text which might be subject to one or more bbcodes
|
||||
|
||||
$content = preg_split('#(\[(?:\w|/\w).*?\])#mis', $value, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE );
|
||||
|
||||
foreach ($content as $cont)
|
||||
{ // Each chunk is either a bbcode or a piece of text
|
||||
$is_proc = FALSE;
|
||||
while (!$is_proc)
|
||||
{
|
||||
global $code;
|
||||
global $postID;
|
||||
global $single_bb;
|
||||
global $_matches;
|
||||
$postID = $p_ID;
|
||||
$done = false;
|
||||
$single_bb = false;
|
||||
$i=0;
|
||||
|
||||
$tmplist = array();
|
||||
foreach($this->List as $code)
|
||||
$oddtext = '';
|
||||
if ($cont[0] == '[')
|
||||
{ // We've got a bbcode - split it up and process it
|
||||
$pattern = '#^\[(/?)([A-Za-z]+)(\d*)([=:]?)(.*?)]$#i';
|
||||
// $matches[0] - same as the input text
|
||||
// $matches[1] - '/' for a closing tag. Otherwise empty string
|
||||
// $matches[2] - the bbcode word
|
||||
// $matches[3] - any digits immediately following the bbcode word
|
||||
// $matches[4] - '=' or ':' according to the separator used
|
||||
// $matches[5] - any parameter
|
||||
$match_count = preg_match($pattern,$cont,$matches);
|
||||
$bbparam = $matches[5];
|
||||
$bbword = $matches[2];
|
||||
if (($bbword) && ($bbword == trim($bbword)))
|
||||
{ // Got a code to process here
|
||||
if ($force_lower) $bbword = strtolower($bbword);
|
||||
if ($matches[1] == '/')
|
||||
{ // Closing code to process
|
||||
$found = FALSE;
|
||||
$i = 0;
|
||||
while ($i < count($code_stack))
|
||||
{ // See if code is anywhere on the stack.
|
||||
if (($code_stack[$i]['type'] == 'bbcode') && ($code_stack[$i]['code'] == $bbword) && ($code_stack[0]['numbers'] == $matches[3]))
|
||||
{
|
||||
$found = TRUE;
|
||||
break;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
if ($found)
|
||||
{
|
||||
$found = FALSE; // Use as 'done' variable now
|
||||
// Code is on stack - $i has index number. Process text, discard unmatched open codes, process 'our' code
|
||||
while ($i > 0) { $unmatch_stack[] = array_shift($code_stack); $i--; } // Get required code to top of stack
|
||||
|
||||
// Pull it off using array_shift - this keeps it as a zero-based array, newest first.
|
||||
while (!$found && (count($code_stack) != 0))
|
||||
{
|
||||
switch ($code_stack[0]['type'])
|
||||
{
|
||||
case 'text' :
|
||||
$stacktext = $code_stack[0]['code'].$stacktext; // Need to insert text at front
|
||||
array_shift($code_stack);
|
||||
break;
|
||||
case 'bbcode' :
|
||||
if (($code_stack[0]['code'] == $bbword) && ($code_stack[0]['numbers'] == $matches[3]))
|
||||
{
|
||||
$stacktext = $this->proc_bbcode($bbword,$code_stack[0]['param'],$stacktext,$bbparam);
|
||||
array_shift($code_stack);
|
||||
// Intentionally don't terminate here - may be some text we can clean up
|
||||
$bbword=''; // Necessary to make sure we don't double process if several instances on stack
|
||||
while (count($unmatch_stack) != 0) { array_unshift($code_stack,array_pop($unmatch_stack)); }
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
$found = TRUE; // Terminate on unmatched bbcode
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (count($code_stack) == 0)
|
||||
{
|
||||
$result .= $stacktext;
|
||||
$stacktext = '';
|
||||
$found = TRUE;
|
||||
}
|
||||
}
|
||||
$is_proc = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // Opening code to process
|
||||
// If its a single code, we can process it now. Otherwise just stack the value
|
||||
if (array_key_exists('_'.$bbword,$this->bbLocation))
|
||||
{ // Single code to process
|
||||
$stacktext .= $this->proc_bbcode('_'.$bbword);
|
||||
$is_proc = TRUE;
|
||||
}
|
||||
elseif (array_key_exists($bbword,$this->bbLocation))
|
||||
{
|
||||
if ($stacktext != '')
|
||||
{ // Stack the text we've accumulated so far
|
||||
array_unshift($code_stack,array('type' => 'text','code' => $stacktext));
|
||||
$stacktext = '';
|
||||
}
|
||||
array_unshift($code_stack,array('type' => 'bbcode','code' => $bbword, 'numbers'=> $matches[3], 'param'=>$bbparam));
|
||||
$is_proc = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Next lines could be deleted - but gives better rejection of 'stray' opening brackets
|
||||
if ((!$is_proc) && (($temp = strrpos($cont,"[")) !== 0))
|
||||
{
|
||||
if("_" == $code[0])
|
||||
{
|
||||
if(strpos($text, "[".substr($code, 1)) !== FALSE)
|
||||
{
|
||||
$tmplist[] = $code;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(strpos($text, "[{$code}") !== FALSE && strpos($text, "[/{$code}") !== FALSE)
|
||||
{
|
||||
$tmplist[] = $code;
|
||||
}
|
||||
}
|
||||
$oddtext = substr($cont,0,$temp);
|
||||
$cont = substr($cont,$temp);
|
||||
}
|
||||
|
||||
foreach($tmplist as $code)
|
||||
{
|
||||
if("_" == $code{0})
|
||||
{
|
||||
$code = substr($code, 1);
|
||||
$this->single_bb = true;
|
||||
$pattern = "#\[({$code})(\d*)(.*?)\]#s";
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->single_bb = false;
|
||||
$pattern = "#\[({$code})(\d*)(.*?)\](.*?)\[\/{$code}\\2\]#s";
|
||||
}
|
||||
$i=0;
|
||||
while($code && ($pos = strpos($text, "[{$code}")) !== false)
|
||||
{
|
||||
$text = preg_replace_callback($pattern, array($this, 'doCode'), $text);
|
||||
$leftover_code = $_matches[1].$_matches[2];
|
||||
$text = str_replace("[{$leftover_code}", "[{$leftover_code}", $text);
|
||||
if ($i == strpos($text, "[{$code}")) { break; }
|
||||
|
||||
if ($pos == ($i = strpos($text,"[{$code}")))
|
||||
{
|
||||
$pattern2 = "#\[({$code})(\d*)(.*?)\]#s";
|
||||
$text = preg_replace_callback($pattern2, array($this, 'doCode'), $text);
|
||||
$leftover_code = $_matches[1].$_matches[2];
|
||||
$text = str_replace("[{$leftover_code}", "[{$leftover_code}", $text);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
if (!$is_proc)
|
||||
{ // We've got some text between bbcodes (or possibly text in front of a bbcode)
|
||||
if ($oddtext == '') { $oddtext = $cont; $is_proc = TRUE; }
|
||||
if (count($code_stack) == 0)
|
||||
{ // Can just add text to answer
|
||||
$result .= $oddtext;
|
||||
}
|
||||
else
|
||||
{ // Add to accumulator at this level
|
||||
$stacktext .= $oddtext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function doCode($matches)
|
||||
// Basically done - just tidy up now
|
||||
// If there's still anything on the stack, we need to process it
|
||||
while (count($code_stack) != 0)
|
||||
{
|
||||
switch ($code_stack[0]['type'])
|
||||
{
|
||||
global $tp, $postID, $full_text, $code_text, $parm, $_matches;
|
||||
$_matches = $matches;
|
||||
$full_text = $tp->replaceConstants($matches[0]);
|
||||
$code = $matches[1];
|
||||
$parm = substr($matches[3], 1);
|
||||
$code_text = '';
|
||||
if (isset($matches[4])) $code_text = $tp->replaceConstants($matches[4]);
|
||||
if($this->single_bb == true)
|
||||
{
|
||||
$code = '_'.$code;
|
||||
}
|
||||
case 'text' :
|
||||
$stacktext .= $code_stack[0]['code'].$stacktext; // Need to insert text at front
|
||||
array_shift($code_stack);
|
||||
break;
|
||||
case 'bbcode' :
|
||||
array_shift($code_stack); // Just discard any unmatched bbcodes
|
||||
break;
|
||||
}
|
||||
}
|
||||
$result .= $stacktext;
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function proc_bbcode($code, $param1='',$code_text_par='', $param2='')
|
||||
// Invoke an actual bbcode handler
|
||||
// $code - textual value of the bbcode (already begins with '_' if a single code)
|
||||
// $param1 - any text after '=' in the opening code
|
||||
// $code_text_par - text between the opening and closing codes
|
||||
// $param2 - any text after '=' for the closing code
|
||||
{
|
||||
global $tp, $postID, $code_text, $parm;
|
||||
$parm = $param1;
|
||||
$code_text = $tp->replaceConstants($code_text_par);
|
||||
|
||||
if (E107_DEBUG_LEVEL)
|
||||
{
|
||||
global $db_debug;
|
||||
@ -158,18 +235,17 @@ class e_bbcode
|
||||
}
|
||||
|
||||
if (is_array($this->bbList) && array_key_exists($code, $this->bbList))
|
||||
{
|
||||
{ // Check the bbcode 'cache'
|
||||
$bbcode = $this->bbList[$code];
|
||||
}
|
||||
else
|
||||
{
|
||||
{ // Find the file
|
||||
if ($this->bbLocation[$code] == 'core')
|
||||
{
|
||||
$bbFile = e_FILE.'bbcode/'.strtolower(str_replace('_', '', $code)).'.bb';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add code to check for plugin bbcode addition
|
||||
{ // Add code to check for plugin bbcode addition
|
||||
$bbFile = e_PLUGIN.$this->bbLocation[$code].'/'.strtolower($code).'.bb';
|
||||
}
|
||||
if (file_exists($bbFile))
|
||||
|
Loading…
x
Reference in New Issue
Block a user