<?php
/**
* This package allows one to create their own bb code tags and define the
* replacements for them.
*
* Package: BB
* File: bb.class.php
* Version: 1.0.0
* Author: Scott Martin <sjm.dev1[at]gmail[dot]com>
* Date: October 28, 2010
* License: GNU GPL 3.0
*
* Features:
* - Create your own BB code style tags and define the HTML replacements for
* them.
* - Allows tags with parameters.. eg [ quote="name" ] text [ /quote ]
* - Allows text between tags to be used as a parameter..
* eg [ url ] http://www.example.com [ /url ]
* - Allows for text between tags to not be parsed for bb code style tags,
* useful for tags such as [ code ] text [ /code ]
* - Allows functions to be called on the text between tags
* - Correctly parses nested bb code style tags of the same kind (assuming
* input string is correctly nested, see Todo)
* - Correctly parses nested bb code style tags of any kind (assuming input
* string is correctly nested, see Todo)
*
* Todo:
* - Create a single regex to match all BB code style tags rather than
* recursively calling preg_match_all()
* - Iterate through the string to be parsed and check for (and fix)
* incorrect nesting prior to parsing
* - Cleanse parameters for URLs, or allow a custom cleansing function to be
* called on any parameter.
* - Add more error checking and verbosity
*
<BB creation and definition system>
Copyright (C) <2010> <Scott Martin>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
class BB
{
//string holder
private $str = '';
//bbtags holder
private $tags = array();
/**
* Converts allowed BB code tags to HTML.
*
* @access public
* @param string $str
* @return string
*/
public function make($str)
{
$this->str = '<p>' . str_replace("\n\n", "</p>\n\n<p>", $str) . '</p>';
if ($matches = $this->pregMatchRecursive($str))
{
foreach ($matches AS $match)
{
$this->makeTag($match);
}
}
return $this->str;
}
/**
* Recursively parses $str for bb code tags. This function would be entirely
* unnecessary if I could write a good enough regex.
*
* @access private
* @param string $str
* @return mixed - array of matches or boolean false when no matches are found
*/
private function pregMatchRecursive($str)
{
$ret = array();
if ((strpos($str, '[') !== false) && (strpos($str, ']') !== false))
{
if (preg_match_all('#\[(\w+)(=.+?)?\]((?:[^[]|\[(?!/?\\1(=.+?)?\])|(?R))+)\[/\\1\]#s', $str, $matches, PREG_SET_ORDER))
{
$ret = array_merge($ret, $matches);
foreach ($matches AS $match)
{
$match[1] = strtolower($match[1]);
if (array_key_exists($match[1], $this->tags))
{
if ($this->tags[$match[1]]->parseContents)
{
if ($newMatches = $this->pregMatchRecursive($match[3]))
{
$ret = array_merge($ret, $newMatches);
}
}
}
}
return $ret;
}
}
return false;
}
/**
* Adds a BB code tag to the list of allowed tags.
*
* @access public
* @param object $tag - object of type BB_Tag
* @return void
*/
public function addTag($tag)
{
$this->tags[$tag->tag] = $tag;
}
/**
* Does the replacing of BB code tags to their HTML counterparts.. or
* manipulation of content between BB code tags, depending on the tags'
* parameters.
*
* @access private
* @param array $match
* @return void
*/
private function makeTag($match)
{
//apply function to matched content
if (count($this->tags[$match[1]]->applyFunction))
{
$params = $match[3];
if (!empty($this->tags[$match[1]]->applyFunction[1]))
{
$params = $this->tags[$match[1]]->applyFunction[1];
array_unshift($params, $match[3]);
}
$match[3] = call_user_func_array($this->tags[$match[1]]->applyFunction[0], $params);
}
$inside = array('', '');
$parse = array('', '');
if (isset($this->tags[$match[1]]) && $this->tags[$match[1]]->inside == false)
{
$inside = array("</p>\n\n", '<p>');
if ($this->tags[$match[1]]->parseContents == true)
{
$parse = array('<p>', "</p>\n\n");
}
}
//simple tag (e.g. <span style="font-weight: bold">text</span>)
if (!$this->tags[$match[1]]->parameter)
{
$this->str = str_replace(
$match[0],
$inside[0] . $this->tags[$match[1]]->replacements[0] . $parse[0] . $match[3] . $parse[1] . $this->tags[$match[1]]->replacements[1] . $inside[1],
$this->str
);
return;
}
//tags with parameter (e.g. <blockquote class="uncited"><div>text</div></blockquote> or <blockquote><div><cite>name wrote:</cite>text</div></blockquote>)
if ($this->tags[$match[1]]->parameter == 1)
{
if (empty($match[2]) === true)
{
if (empty($this->tags[$match[1]]->replacements[0]) !== true)
{
if ($this->tags[$match[1]]->useTextAsParameter)
{
$this->str = str_replace(
$match[0],
$inside[0] . str_replace(
'{placeholder}',
$match[3],
$this->tags[$match[1]]->replacements[0][0]
) . $parse[0] . $match[3] . $parse[1] . $this->tags[$match[1]]->replacements[0][1] . $inside[1],
$this->str
);
} else
{
$this->str = str_replace(
$match[0],
$inside[0] . $this->tags[$match[1]]->replacements[0][0] . $parse[0] . $match[3] . $parse[1] . $this->tags[$match[1]]->replacements[0][1] . $inside[1],
$this->str
);
}
}
} else
{
//remove = and "" or '' in parameter supplied
$match[2] = substr($match[2], 1);
if ((substr($match[2], 0, 1) == '"' && substr($match[2], -1) == '"')|| (substr($match[2], 0, 1) == '\'' && substr($match[2], -1) == '\''))
{
$match[2] = substr(substr($match[2], 0, strlen($match[2]) - 1), 1);
}
$this->str = str_replace(
$match[0],
$inside[0] . str_replace(
'{placeholder}',
$match[2],
$this->tags[$match[1]]->replacements[1][0]
) . $parse[0] . $match[3] . $parse[1] . $this->tags[$match[1]]->replacements[1][1] . $inside[1],
$this->str
);
}
return;
}
}
}