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)
{
$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))
{
$oddtext = substr($cont,0,$temp);
$cont = substr($cont,$temp);
}
}
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;
}
}
}
}
// 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'])
{
case 'text' :
$stacktext = $code_stack[0]['code'].$stacktext; // Need to insert text at front
array_shift($code_stack);
break;
case 'bbcode' :
$stacktext = '['.$code_stack[0]['code'].']'.$stacktext; // To discard unmatched codes, delete this line
array_shift($code_stack); // Just discard any unmatched bbcodes
break;
}
}
$result .= $stacktext;
return $result;
}