/**
* 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 .
*
* @category Zend
* @package Zend_Filter
* @copyright Copyright (c) 2007 Grummfy (http://www.grummfy.com)
* @license http://www.gnu.org/licenses/lgpl.html LGPL v2
* @version v0.2 10/08/2007 Grummfy
*/
/**
* @see Zend_Filter_Interface
*/
require_once 'Zend/Filter/Interface.php';
/**
* @category Zend
* @package Zend_Filter
* @copyright Copyright (c) 2007 Grummfy (http://www.grummfy.com)
* @license http://www.gnu.org/licenses/lgpl.html LGPL v2
*/
class Zend_Filter_Bbcode implements Zend_Filter_Interface
{
protected $_config = array(
'url_limit' => 40,
);
public function __construct($config = null)
{
if (!is_null($config) && is_array($config))
foreach ($this->_config as $k => $v)
{
$this->_config[ $k ] = (isset($config[ $k ]))?$config[ $k ]:$this->_config[ $k ];
}
}
/**
* Defined by Zend_Filter_Interface
*
* Returns the string $text, when bbcode are replace by html code
*
* @param string $text
* @return string
*/
public function filter($text)
{
//removing /r because it's bad!
$text = str_replace("\r", '', $text);
// first [nobbcode][/nobbcode] -> don't interpret bbcode
$this->_parseBbcodeNobbcode($text);
// parse strange bbcode, before other bbcode
$this->_parseBbcodeCode($text);
$this->_parseBbcodeQuote($text);
$this->_parseBbcodeList($text);
// easy bbcode replacement
//[br]
$this->_parseBbcodeBr($text);
// [i]txt[/i]
$this->_parseSimpleBbcode('i', '$1', $text);
// [u]txt[/u]
$this->_parseSimpleBbcode('u', '$1', $text);
// [b]txt[/b]
$this->_parseSimpleBbcode('b', '$1', $text);
// [del]txt[/del] & [strike]txt[/strike]
$this->_parseSimpleBbcode('del', '$1', $text);
$this->_parseSimpleBbcode('strike', '$1', $text);
// [color=color]txt[/color]
$this->_parseParamBbcode('color', '([a-zA-Z]*|\#?[0-9a-fA-F]{6})', '$2', $text);
// [bgcolor=color]txt[/bgcolor]
$this->_parseParamBbcode('bgcolor', '([a-zA-Z]*|\#?[0-9a-fA-F]{6})', '$2', $text);
// [align=(center|left|right)][/align]
$this->_parseParamBbcode('align', '(center|left|right|justify){1}', '
$2
', $text);
// [size=$size][/size]
$this->_parseParamBbcode('size', '([0-9].*)', '$2', $text);
$this->_parseBbcodeEmail($text);
$this->_parseBbcodeUrl($text);
$this->_parseBbcodeImg($text);
return $text;
}
/**
* parse bbcode corespondig to $pattern inside $text and replace with $replace
*
* @param string $pattern
* @param string $replace
* @param string $text
* @uses preg_replace
*/
protected function _replaceLoop($pattern, $replace, &$text)
{
while (preg_match($pattern, $text))
{
$text = preg_replace($pattern, $replace, $text);
}
}
protected function _parseSimpleBbcode($tag, $replace, &$text)
{
$this->_replaceLoop('#\[' . $tag . '\](.*?)\[/' . $tag . '\]#si', $replace, $text);
}
protected function _parseParamBbcode($tag, $param, $replace, &$text)
{
$this->_replaceLoop('#\[' . $tag . '=' . $param . '\](.*?)\[/' . $tag . '\]#si', $replace, $text);
}
//
// Function to parse bbcode
//
// [br]
protected function _parseBbcodeBr(&$text)
{
$text = preg_replace('#\[br\]#i', '
', $text);
}
// [img]http://www.site.tld/image.png[/img]
protected function _parseBbcodeImg(&$text)
{
$text = preg_replace('#\[img\](.*?)\[/img\]#sei', '\'
\'', $text);
}
/**
* Execute *before* other bbcode parse!
* [nobbcode]txt[/nobbcode]
* @param unknown_type $text
* @return unknown
*/
protected function _parseBbcodeNobbcode(&$text)
{
$text = preg_replace('#\[nobbcode\](.+?)\[/nobbcode\]#sie', '\'\' . strtr(\'$1\', array(\'[\' => \'[\', \']\' => \']\')) . \'
\'', $text);
}
// [url]url[/url] & [url=url]url txt[/url]
protected function _parseBbcodeUrl(&$text)
{
$text = preg_replace('#\[url\]([^ \"\t\n\r<]*?)\[/url\]#ei', '$this->_encodeUrl(\'$1\', \'\', $this->_config[\'url_limit\'])', $text);
$text = preg_replace('#\[url=([^ \"\t\n\r<]*?)\](.*?)\[/url\]#sei', '$this->_encodeUrl(\'$1\', \'$2\', $this->_config[\'url_limit\'])', $text);
}
// [email]email[/email] & [email=email]email txt[/email]
protected function _parseBbcodeEmail(&$text)
{
$this->_replaceLoop('#\[email\]([^\[]*?)\[/email\]#sei', '$this->_encodeEmail(\'$1\')', $text);
$this->_replaceLoop('#\[email=([^\[]*?)\](.*?)\[/email\]#sei', '$this->_encodeEmail(\'$1\', \'$2\')', $text);
}
// [code]txt[/code] & [code=language]txt[/code]
protected function _parseBbcodeCode(&$text)
{
$text = preg_replace_callback('#\n?\[code(=[a-zA-Z0-9]*?)?\](.+?)\[/code\]\n?#is', array($this, '_cbParseBbcodeCode'), $text);
}
protected function _cbParseBbcodeCode($match)
{
$pattern = array("\n", "\t", ' ', '[', ']', ')', '(', '<', '>');
$replace = array('
', ' ', ' ', '[', ']', ')', '(', '<', '>');
$text = str_replace($pattern, $replace, $match[2]);
$code = '';
if ($match[1] != '') {
$code = '_' . substr($match[1], 1);
}
return '' . $text . '
';
}
protected function _parseBbcodeList(&$text)
{
$pattern = '#\n?\[list=?(greek|square|circle|disc|I|i|A|a|1)?\](.+?)\[/list\]\n?#is';
while (preg_match($pattern, $text))
{
$text = preg_replace_callback($pattern, array($this, '_cbParseBbcodeList') , $text);
}
}
protected function _parseBbcodeQuote(&$text)
{
$this->_replaceLoop('#\n?\[quote\](.*)\[/quote\]\n?#mSi', '$1
', $text);
$this->_replaceLoop('#\n?\[quote=(.*)\](.*)\[/quote\]\n?#mSi', '$1
$2
', $text);
}
protected function _encodeUrl($url, $txt = '', $limit = 40)
{
// @TODO test url and check javascrip and other bad stuf
$url_txt = ($txt != '')?$txt:$url;
if ($limit > 10 && strlen($url_txt) > $limit)
$url_txt = substr($url_txt, 0, $limit - 10) . '…' . substr($url_txt, -10);
return '' . $url_txt . '';
}
protected function _encodeEmail($email, $txt = '')
{
if (preg_match('#^\w([-_.]?\w)*@\w([-_.]?\w)*\.([a-z]{2,4})$#', $email))
{
//mini anti robots
$new = '';
$len = strlen($email);
for ($i = 0; $i < $len; $i++)
{
$new .= '' . bin2hex($email{$i}) . ';';
}
//formating email mailto.
return '' . ($txt!=''?$txt:$new) . '';
}
return $email;
}
protected function _cbParseBbcodeList($match)
{
$text = '';
if ($match[1] != '') {
switch ($match[1])
{
case 'disk':
case 'circle':
case 'square':
$text = '';
break;
case 'i':
case 'I':
case 'A':
case 'a':
case '1':
$text = '';
$text_end = '
';
break;
}
}
$this->_replaceLoop('#\n?(\[\*\](.*))\n?#is', '- $2
', $match[2]);
$text .= $match[2];
return $text . $text_end;
}
}