mirror of
https://github.com/e107inc/e107.git
synced 2025-08-01 12:20:44 +02:00
Bugtracker #4403, #4080, #3626, #4332, possibly #4190 and probably #3808 and #3625 - restructure parser to resolve various bbcode decoding problems
This commit is contained in:
@@ -11,8 +11,8 @@
|
|||||||
| GNU General Public License (http://gnu.org).
|
| GNU General Public License (http://gnu.org).
|
||||||
|
|
|
|
||||||
| $Source: /cvs_backup/e107_0.8/e107_handlers/e_parse_class.php,v $
|
| $Source: /cvs_backup/e107_0.8/e107_handlers/e_parse_class.php,v $
|
||||||
| $Revision: 1.33 $
|
| $Revision: 1.34 $
|
||||||
| $Date: 2008-05-26 17:58:29 $
|
| $Date: 2008-06-14 21:01:04 $
|
||||||
| $Author: e107steved $
|
| $Author: e107steved $
|
||||||
+----------------------------------------------------------------------------+
|
+----------------------------------------------------------------------------+
|
||||||
*/
|
*/
|
||||||
@@ -33,72 +33,72 @@ class e_parse
|
|||||||
|
|
||||||
// toHTML Action defaults. For now these match existing convention.
|
// toHTML Action defaults. For now these match existing convention.
|
||||||
// Let's reverse the logic on the first set ASAP; too confusing!
|
// Let's reverse the logic on the first set ASAP; too confusing!
|
||||||
var $e_modSet = array();
|
|
||||||
var $e_optDefault = array(
|
var $e_optDefault = array(
|
||||||
'context' => 'olddefault', // default context: all "opt-out" conversions :(
|
'context' => 'olddefault', // default context: all "opt-out" conversions :(
|
||||||
'fromadmin' => FALSE,
|
'fromadmin' => FALSE,
|
||||||
|
|
||||||
// Enabled by Default
|
// Enabled by Default
|
||||||
'value' => FALSE, // Restore entity form of quotes and such to single characters - TRUE disables
|
'value' => FALSE, // Restore entity form of quotes and such to single characters - TRUE disables
|
||||||
|
|
||||||
'nobreak' => FALSE, // Line break compression - TRUE removes multiple line breaks
|
'nobreak' => FALSE, // Line break compression - TRUE removes multiple line breaks
|
||||||
'retain_nl' => FALSE, // Retain newlines - wraps to \n instead of <br /> if TRUE
|
'retain_nl' => FALSE, // Retain newlines - wraps to \n instead of <br /> if TRUE
|
||||||
|
|
||||||
'no_make_clickable' => FALSE, // URLs etc are clickable - TRUE disables
|
'no_make_clickable' => FALSE, // URLs etc are clickable - TRUE disables
|
||||||
'no_replace' => FALSE, // Replace clickable links - TRUE disables (only if no_make_clickable not set)
|
'no_replace' => FALSE, // Replace clickable links - TRUE disables (only if no_make_clickable not set)
|
||||||
|
|
||||||
'emotes_off' => FALSE, // Convert emoticons to graphical icons - TRUE disables conversion
|
'emotes_off' => FALSE, // Convert emoticons to graphical icons - TRUE disables conversion
|
||||||
'emotes_on' => FALSE, // FORCE conversion to emotes, even if syspref is disabled
|
'emotes_on' => FALSE, // FORCE conversion to emotes, even if syspref is disabled
|
||||||
|
|
||||||
'no_hook' => FALSE, // Hooked parsers (TRUE disables completely)
|
'no_hook' => FALSE, // Hooked parsers (TRUE disables completely) (deprecated)
|
||||||
|
|
||||||
// Disabled by Default
|
// Disabled by Default
|
||||||
'defs' => FALSE, // Convert defines(constants) within text.
|
'defs' => FALSE, // Convert defines(constants) within text.
|
||||||
'constants' => FALSE, // replace all {e_XXX} constants with their e107 value
|
'constants' => FALSE, // replace all {e_XXX} constants with their e107 value
|
||||||
'parse_sc' => FALSE, // Parse shortcodes - TRUE enables parsing
|
'abs_links' => FALSE, // Convert constants to absolute paths if TRUE
|
||||||
'no_tags' => FALSE // remove HTML tags.
|
'parse_sc' => FALSE, // Parse shortcodes - TRUE enables parsing
|
||||||
|
'no_tags' => FALSE // remove HTML tags.
|
||||||
);
|
);
|
||||||
|
|
||||||
// Super modifiers adjust default option values
|
// Super modifiers adjust default option values
|
||||||
// First line of adjustments change default-ON options
|
// First line of adjustments change default-ON options
|
||||||
// Second line changes default-OFF options
|
// Second line changes default-OFF options
|
||||||
var $e_SuperMods = array(
|
var $e_SuperMods = array(
|
||||||
'title' => //text is part of a title (e.g. news title)
|
'TITLE' => //text is part of a title (e.g. news title)
|
||||||
array(
|
array(
|
||||||
'nobreak'=>TRUE, 'retain_nl'=>TRUE, 'no_make_clickable'=>TRUE,'emotes_off'=>TRUE,
|
'nobreak'=>TRUE, 'retain_nl'=>TRUE, 'no_make_clickable'=>TRUE,'emotes_off'=>TRUE,
|
||||||
'defs'=>TRUE,'parse_sc'=>TRUE),
|
'defs'=>TRUE,'parse_sc'=>TRUE),
|
||||||
|
|
||||||
'user_title' => //text is user-entered (i.e. untrusted) and part of a title (e.g. forum title)
|
'USER_TITLE' => //text is user-entered (i.e. untrusted) and part of a title (e.g. forum title)
|
||||||
array(
|
array(
|
||||||
'nobreak'=>TRUE, 'retain_nl'=>TRUE, 'no_make_clickable'=>TRUE,'emotes_off'=>TRUE,'no_hook'=>TRUE
|
'nobreak'=>TRUE, 'retain_nl'=>TRUE, 'no_make_clickable'=>TRUE,'emotes_off'=>TRUE,'no_hook'=>TRUE
|
||||||
),
|
),
|
||||||
|
|
||||||
'summary' => // text is part of the summary of a longer item (e.g. content summary)
|
'SUMMARY' => // text is part of the summary of a longer item (e.g. content summary)
|
||||||
array(
|
array(
|
||||||
// no changes to default-on items
|
// no changes to default-on items
|
||||||
'defs'=>TRUE, 'constants'=>TRUE, 'parse_sc'=>TRUE),
|
'defs'=>TRUE, 'constants'=>TRUE, 'parse_sc'=>TRUE),
|
||||||
|
|
||||||
'description' => // text is the description of an item (e.g. download, link)
|
'DESCRIPTION' => // text is the description of an item (e.g. download, link)
|
||||||
array(
|
array(
|
||||||
// no changes to default-on items
|
// no changes to default-on items
|
||||||
'defs'=>TRUE, 'constants'=>TRUE, 'parse_sc'=>TRUE),
|
'defs'=>TRUE, 'constants'=>TRUE, 'parse_sc'=>TRUE),
|
||||||
|
|
||||||
'body' => // text is 'body' or 'bulk' text (e.g. custom page body, content body)
|
'BODY' => // text is 'body' or 'bulk' text (e.g. custom page body, content body)
|
||||||
array(
|
array(
|
||||||
// no changes to default-on items
|
// no changes to default-on items
|
||||||
'defs'=>TRUE, 'constants'=>TRUE, 'parse_sc'=>TRUE),
|
'defs'=>TRUE, 'constants'=>TRUE, 'parse_sc'=>TRUE),
|
||||||
|
|
||||||
'user_body' => // text is user-entered (i.e. untrusted)'body' or 'bulk' text (e.g. custom page body, content body)
|
'USER_BODY' => // text is user-entered (i.e. untrusted)'body' or 'bulk' text (e.g. custom page body, content body)
|
||||||
array(
|
array(
|
||||||
'constants'=>TRUE
|
'constants'=>TRUE
|
||||||
),
|
),
|
||||||
|
|
||||||
'linktext' => // text is the 'content' of a link (A tag, etc)
|
'LINKTEXT' => // text is the 'content' of a link (A tag, etc)
|
||||||
array(
|
array(
|
||||||
'nobreak'=>TRUE, 'retain_nl'=>TRUE, 'no_make_clickable'=>TRUE,'emotes_off'=>TRUE,'no_hook'=>TRUE,
|
'nobreak'=>TRUE, 'retain_nl'=>TRUE, 'no_make_clickable'=>TRUE,'emotes_off'=>TRUE,'no_hook'=>TRUE,
|
||||||
'defs'=>TRUE,'parse_sc'=>TRUE),
|
'defs'=>TRUE,'parse_sc'=>TRUE),
|
||||||
|
|
||||||
'rawtext' => // text is used (for admin edit) without fancy conversions or html.
|
'RAWTEXT' => // text is used (for admin edit) without fancy conversions or html.
|
||||||
array(
|
array(
|
||||||
'nobreak'=>TRUE, 'retain_nl'=>TRUE, 'no_make_clickable'=>TRUE,'emotes_off'=>TRUE,'no_hook'=>TRUE,'no_tags'=>TRUE
|
'nobreak'=>TRUE, 'retain_nl'=>TRUE, 'no_make_clickable'=>TRUE,'emotes_off'=>TRUE,'no_hook'=>TRUE,'no_tags'=>TRUE
|
||||||
// leave opt-in options off
|
// leave opt-in options off
|
||||||
@@ -107,16 +107,12 @@ class e_parse
|
|||||||
|
|
||||||
function e_parse()
|
function e_parse()
|
||||||
{
|
{
|
||||||
// Preprocess the supermods to be useful default arrays with all values
|
// Preprocess the supermods to be useful default arrays with all values
|
||||||
foreach ($this->e_SuperMods as $key=>$val)
|
foreach ($this->e_SuperMods as $key=>$val)
|
||||||
{
|
{
|
||||||
$this->e_SuperMods[$key] = array_merge($this->e_optDefault,$this->e_SuperMods[$key]); // precalculate super defaults
|
$this->e_SuperMods[$key] = array_merge($this->e_optDefault,$this->e_SuperMods[$key]); // precalculate super defaults
|
||||||
$this->e_SuperMods[$key]['context']=$key;
|
$this->e_SuperMods[$key]['context']=$key;
|
||||||
}
|
}
|
||||||
foreach ($this->e_optDefault as $key=>$val)
|
|
||||||
{
|
|
||||||
$this->e_modSet[$key] = TRUE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -483,268 +479,376 @@ class e_parse
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function toHTML($text, $parseBB = FALSE, $modifiers = "", $postID = "", $wrap=FALSE) {
|
function toHTML($text, $parseBB = FALSE, $modifiers = "", $postID = "", $wrap=FALSE)
|
||||||
if ($text == '')
|
{
|
||||||
{
|
if ($text == '') return $text;
|
||||||
return $text;
|
|
||||||
}
|
global $pref, $fromadmin;
|
||||||
global $pref, $fromadmin;
|
|
||||||
|
|
||||||
//
|
// Set default modifiers to start
|
||||||
// SET MODIFIERS
|
$opts = $this->e_optDefault;
|
||||||
//
|
|
||||||
|
// Now process any modifiers that are specified
|
||||||
|
if (strlen($modifiers))
|
||||||
|
{
|
||||||
|
$aMods = explode( ',',$modifiers);
|
||||||
|
|
||||||
// Get modifier strings for toHTML
|
// If there's a supermodifier, it must be first, and in uppercase
|
||||||
// "super" modifiers set a baseline. Recommend entering in UPPER CASE to highlight
|
$psm = trim($aMods[0]);
|
||||||
// other modifiers override
|
if (isset($this->e_SuperMods[$psm]))
|
||||||
// modifiers SHOULD be delimited with commas (eventually this will be 'MUST')
|
|
||||||
// modifiers MAY have spaces in between as desired
|
|
||||||
|
|
||||||
$opts = $this->e_optDefault;
|
|
||||||
if (strlen($modifiers))
|
|
||||||
{
|
{
|
||||||
//
|
$opts = array_merge($this->e_optDefault,$this->e_SuperMods[$psm]);
|
||||||
// Yes, the following code is strangely-written. It is one of the MOST used bits in
|
$opts['context'] = $psm;
|
||||||
// all of e107. We "inlined" the assignments to optimize speed through
|
unset($aMods[0]);
|
||||||
// some careful testing (19 Jan 2007).
|
|
||||||
//
|
|
||||||
// Some alternatives that do NOT speed things up (they make it slower)
|
|
||||||
// - use of array_intersect, array_walk, preg_replace, intermediate variables, etc etc etc.
|
|
||||||
//
|
|
||||||
|
|
||||||
if (1) // php 4 code
|
|
||||||
{
|
|
||||||
$opts = $this->e_optDefault;
|
|
||||||
$aMods = explode( ',',
|
|
||||||
// convert blanks to comma, then comma-comma (from blank-comma) to single comma
|
|
||||||
str_replace(array(' ', ',,'), array(',', ',' ),
|
|
||||||
// work with all lower case
|
|
||||||
strtolower($modifiers)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($aMods as $mod)
|
|
||||||
{
|
|
||||||
if (isset($this->e_SuperMods[$mod]))
|
|
||||||
{
|
|
||||||
$opts = $this->e_SuperMods[$mod];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find any regular mods
|
|
||||||
foreach ($aMods as $mod)
|
|
||||||
{
|
|
||||||
$opts[$mod] = TRUE; // Change mods as spec'd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0) // php 5 code - not tested, and may not be faster anyway
|
|
||||||
{
|
|
||||||
$aMods = array_flip(
|
|
||||||
explode( ',',
|
|
||||||
// convert blanks to comma, then comma-comma (from blank-comma) to single comma
|
|
||||||
str_replace(array(' ', ',,'), array(',', ',' ),
|
|
||||||
// work with all lower case
|
|
||||||
strtolower($modifiers)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$opts = array_merge($opts, array_intersect_key($this->e_SuperMods,$aMods)); // merge in any supermods found
|
|
||||||
$opts = array_merge($opts, array_intersect_key($this->modSet, $aMods)); // merge in any other mods found
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$fromadmin = $opts['fromadmin'];
|
|
||||||
|
|
||||||
// Convert defines(constants) within text. eg. Lan_XXXX - must be the entire text string (i.e. not embedded)
|
|
||||||
// The check for '::' is a workaround for a bug in the Zend Optimiser 3.3.0 and PHP 5.2.4 combination - causes crashes if '::' in site name
|
|
||||||
if ($opts['defs'] && (strlen($text) < 25) && ((strpos($text,'::') === FALSE) && defined(trim($text))))
|
|
||||||
{
|
|
||||||
return constant(trim($text));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if ($opts['no_tags'])
|
|
||||||
{
|
|
||||||
$text = strip_tags($text);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(!$wrap && $pref['main_wordwrap']) $wrap = $pref['main_wordwrap'];
|
|
||||||
$text = " ".$text;
|
|
||||||
|
|
||||||
|
|
||||||
// Prepare for line-break compression. Avoid compressing newlines in embedded scripts and CSS
|
|
||||||
if (!$opts['nobreak'])
|
|
||||||
{
|
|
||||||
$text = preg_replace("#>\s*[\r]*\n[\r]*#", ">", $text);
|
|
||||||
preg_match_all("#<(script|style)[^>]+>.*?</(script|style)>#is", $text, $embeds);
|
|
||||||
$text = preg_replace("#<(script|style)[^>]+>.*?</(script|style)>#is", "<|>", $text);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Convert URL's to clickable links, unless modifiers or prefs override
|
|
||||||
if ($pref['make_clickable'] && !$opts['no_make_clickable'])
|
|
||||||
{
|
|
||||||
if ($pref['link_replace'] && !$opts['no_replace'])
|
|
||||||
{
|
|
||||||
$_ext = ($pref['links_new_window'] ? " rel=\"external\"" : "");
|
|
||||||
$text = preg_replace("#(^|[\n ])([\w]+?://[^ \"\n\r\t<,]*)#is", "\\1<a href=\"\\2\" {$_ext}>".$pref['link_text']."</a>", $text);
|
|
||||||
$text = preg_replace("#(^|[\n \]])((www|ftp)\.[\w+-]+?\.[\w+\-.]*(?(?=/)(/.+?(?=\s|,\s))|(?=\W)))#is", "\\1<a href=\"http://\\2\" {$_ext}>".$pref['link_text']."</a>", $text);
|
|
||||||
if(CHARSET != "utf-8" && CHARSET != "UTF-8")
|
|
||||||
{
|
|
||||||
$email_text = ($pref['email_text']) ? $this->replaceConstants($pref['email_text']) : "\\1\\2©\\3";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$email_text = ($pref['email_text']) ? $this->replaceConstants($pref['email_text']) : "\\1\\2©\\3";
|
|
||||||
}
|
|
||||||
$text = preg_replace("#([\n ])([a-z0-9\-_.]+?)@([\w\-]+\.([\w\-\.]+\.)*[\w]+)#i", "\\1<a rel='external' href='javascript:window.location=\"mai\"+\"lto:\"+\"\\2\"+\"@\"+\"\\3\";self.close();' onmouseover='window.status=\"mai\"+\"lto:\"+\"\\2\"+\"@\"+\"\\3\"; return true;' onmouseout='window.status=\"\";return true;'>".$email_text."</a>", $text);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$text = preg_replace("#(^|[\n ])([\w]+?://[^ \"\n\r\t<,]*)#is", "\\1<a href=\"\\2\" rel=\"external\">\\2</a>", $text);
|
|
||||||
$text = preg_replace("#(^|[\n \]])((www|ftp)\.[\w+-]+?\.[\w+\-.]*(?(?=/)(/.+?(?=\s|,\s))|(?=\W)))#is", "\\1<a href=\"http://\\2\" rel=\"external\">\\2</a>", $text);
|
|
||||||
$text = preg_replace("#([\n ])([a-z0-9\-_.]+?)@([\w\-]+\.([\w\-\.]+\.)*[\w]+)#i", "\\1<a rel='external' href='javascript:window.location=\"mai\"+\"lto:\"+\"\\2\"+\"@\"+\"\\3\";self.close();' onmouseover='window.status=\"mai\"+\"lto:\"+\"\\2\"+\"@\"+\"\\3\"; return true;' onmouseout='window.status=\"\";return true;'>".LAN_EMAIL_SUBS."</a>", $text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Convert emoticons to graphical icons, unless modifiers override
|
|
||||||
if (!$opts['emotes_off'])
|
|
||||||
{
|
|
||||||
if ($pref['smiley_activate'] || $opts['emotes_on'])
|
|
||||||
{
|
|
||||||
if (!is_object($this->e_emote)) {
|
|
||||||
require_once(e_HANDLER.'emote_filter.php');
|
|
||||||
$this->e_emote = new e_emoteFilter;
|
|
||||||
}
|
|
||||||
$text = $this->e_emote->filterEmotes($text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Reduce multiple newlines in all forms to a single newline character, except for embedded scripts and CSS
|
|
||||||
if (!$opts['nobreak'])
|
|
||||||
{
|
|
||||||
$text = preg_replace("#[\r]*\n[\r]*#", E_NL, $text);
|
|
||||||
foreach ($embeds[0] as $embed) {
|
|
||||||
$text = preg_replace("#<\|>#", $embed, $text, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Restore entity form of quotes and such to single characters, except for text destined for tag attributes or JS.
|
|
||||||
if (!$opts['value'])
|
|
||||||
{ // output not used for attribute values.
|
|
||||||
$text = str_replace($this -> search, $this -> replace, $text);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{ // output used for attribute values.
|
{
|
||||||
$text = str_replace($this -> replace, $this -> search, $text);
|
// Set default modifiers
|
||||||
|
$opts = $this->e_optDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now find any regular mods (could check each exists, but unnecessary processing really)
|
||||||
|
foreach ($aMods as $mod)
|
||||||
|
|
||||||
// Start parse [bb][/bb] codes
|
|
||||||
if ($parseBB === TRUE)
|
|
||||||
{
|
{
|
||||||
if (!is_object($this->e_bb)) {
|
$opts[trim($mod)] = TRUE; // Change mods as spec'd
|
||||||
require_once(e_HANDLER.'bbcode_handler.php');
|
|
||||||
$this->e_bb = new e_bbcode;
|
|
||||||
}
|
|
||||||
$text = $this->e_bb->parseBBCodes($text, $postID);
|
|
||||||
}
|
|
||||||
// End parse [bb][/bb] codes
|
|
||||||
|
|
||||||
|
|
||||||
// replace all {e_XXX} constants with their e107 value AFTER the bbcodes have been parsed.
|
|
||||||
if ($opts['constants'])
|
|
||||||
{
|
|
||||||
$text = $this->replaceConstants($text);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// profanity filter
|
$fromadmin = $opts['fromadmin'];
|
||||||
if ($pref['profanity_filter']) {
|
|
||||||
if (!is_object($this->e_pf)) {
|
// Convert defines(constants) within text. eg. Lan_XXXX - must be the entire text string (i.e. not embedded)
|
||||||
require_once(e_HANDLER."profanity_filter.php");
|
// The check for '::' is a workaround for a bug in the Zend Optimiser 3.3.0 and PHP 5.2.4 combination - causes crashes if '::' in site name
|
||||||
$this->e_pf = new e_profanityFilter;
|
if ($opts['defs'] && (strlen($text) < 25) && ((strpos($text,'::') === FALSE) && defined(trim($text))))
|
||||||
}
|
{
|
||||||
$text = $this->e_pf->filterProfanities($text);
|
return constant(trim($text));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Optional short-code conversion
|
if ($opts['no_tags'])
|
||||||
if ($opts['parse_sc'])
|
{
|
||||||
{
|
$text = strip_tags($text);
|
||||||
$text = $this->parseTemplate($text, TRUE);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//Run any hooked in parsers
|
// Make sure we have a valid count for word wrapping
|
||||||
if (!$opts['no_hook'] && varset($pref['tohtml_hook']))
|
if(!$wrap && $pref['main_wordwrap']) $wrap = $pref['main_wordwrap'];
|
||||||
{
|
$text = " ".$text;
|
||||||
//Process the older tohtml_hook pref (depricated)
|
|
||||||
foreach(explode(",",$pref['tohtml_hook']) as $hook)
|
|
||||||
{
|
|
||||||
if (!is_object($this->e_hook[$hook]))
|
|
||||||
{
|
|
||||||
require_once(e_PLUGIN.$hook."/".$hook.".php");
|
|
||||||
$hook_class = "e_".$hook;
|
|
||||||
$this->e_hook[$hook] = new $hook_class;
|
|
||||||
}
|
|
||||||
$text = $this->e_hook[$hook]->$hook($text,$opts['context']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isset($pref['e_tohtml_list']) && is_array($pref['e_tohtml_list']))
|
|
||||||
{
|
|
||||||
foreach($pref['e_tohtml_list'] as $hook)
|
|
||||||
{
|
|
||||||
if (!is_object($this->e_hook[$hook]))
|
|
||||||
{
|
|
||||||
require_once(e_PLUGIN.$hook."/e_tohtml.php");
|
|
||||||
$hook_class = "e_tohtml_".$hook;
|
|
||||||
$this->e_hook[$hook] = new $hook_class;
|
|
||||||
}
|
|
||||||
$text = $this->e_hook[$hook]->to_html($text, $opts['context']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!$opts['nobreak'])
|
|
||||||
|
// Now get on with the parsing
|
||||||
|
$ret_parser = '';
|
||||||
|
$last_bbcode = '';
|
||||||
|
if ($parseBB == FALSE)
|
||||||
|
{
|
||||||
|
$content = array($text);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Split each text block into bits which are either within one of the 'key' bbcodes, or outside them
|
||||||
|
// (Because we have to match end words, the 'extra' capturing subpattern gets added to output array. We strip it later)
|
||||||
|
$content = preg_split('#(\[(php|code|scode|hide).*?\[/(?:\\2)\])#mis', $text, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Use $full_text variable so its available to special bbcodes if required
|
||||||
|
foreach ($content as $full_text)
|
||||||
|
{
|
||||||
|
$proc_funcs = TRUE;
|
||||||
|
|
||||||
|
// We may have 'captured' a bbcode word - strip it if so
|
||||||
|
if ($last_bbcode == $full_text)
|
||||||
{
|
{
|
||||||
$text = $this -> textclean($text, $wrap);
|
$last_bbcode = '';
|
||||||
}
|
$proc_funcs = FALSE;
|
||||||
|
$full_text = '';
|
||||||
|
}
|
||||||
// Search Highlight
|
else
|
||||||
if (!$opts['emotes_off'])
|
|
||||||
{
|
{
|
||||||
if ($this->checkHighlighting())
|
// (Have to have a good test in case a 'non-key' bbcode starts the block - so pull out the bbcode parameters while we're there
|
||||||
{
|
if (($parseBB !== FALSE) && preg_match('#(^\[(php|code|scode|hide)(.*?)\])(.*?)(\[/\\2\]$)#is', $full_text, $matches ))
|
||||||
$text = $this -> e_highlight($text, $this -> e_query);
|
{ // It's one of the 'key' bbcodes
|
||||||
|
$proc_funcs = FALSE; // Usually don't want 'normal' processing if its a 'special' bbcode
|
||||||
|
// $matches[0] - complete block from opening bracket of opening tag to closing bracket of closing tag
|
||||||
|
// $matches[1] - complete opening tag (inclusive of brackets)
|
||||||
|
// $matches[2] - bbcode word
|
||||||
|
// $matches[3] - parameter, including '='
|
||||||
|
// $matches[4] - bit between the tags (i.e. text to process)
|
||||||
|
// $matches[5] - closing tag
|
||||||
|
$bbFile = e_FILE.'bbcode/'.strtolower(str_replace('_', '', $matches[2])).'.bb'; // In case we decide to load a file
|
||||||
|
$bbcode = '';
|
||||||
|
$code_text = $matches[4];
|
||||||
|
$parm = $matches[3] ? substr($matches[3],1) : '';
|
||||||
|
$last_bbcode = $matches[2];
|
||||||
|
switch ($matches[2])
|
||||||
|
{
|
||||||
|
case 'php' :
|
||||||
|
if (DB_INF_SHOW) echo "PHP decode: ".htmlentities($matches[4])."<br /><br />";
|
||||||
|
$proc_funcs = TRUE; // Probably run the output through the normal processing functions - but put here so the PHP code can disable if desired
|
||||||
|
// This is just the contents of the php.bb file pulled in - its short, so will be quicker
|
||||||
|
// $search = array(""", "'", "$", '<br />', E_NL, "->", "<br />");
|
||||||
|
// $replace = array('"', "'", "$", "\n", "\n", "->", "<br />");
|
||||||
|
// Shouldn't have any parameter on this bbcode
|
||||||
|
// if (!$matches[3]) $bbcode = str_replace($search, $replace, $matches[4]); // Not sure whether checks are necessary now we've reorganised
|
||||||
|
// Because we're bypassing most of the initial parser processing, we should be able to just reverse the effects of toDB() and execute the code
|
||||||
|
if (!$matches[3]) $bbcode = html_entity_decode($matches[4], ENT_QUOTES, CHARSET);
|
||||||
|
if (DB_INF_SHOW) echo "PHP after decode: ".htmlentities($bbcode)."<br /><br />";
|
||||||
|
break;
|
||||||
|
case 'hide' :
|
||||||
|
$proc_funcs = TRUE;
|
||||||
|
default : // Most bbcodes will just execute their normal file
|
||||||
|
$bbcode = file_get_contents($bbFile); // Just read in the code file and execute it
|
||||||
|
} // end - switch ($matches[2])
|
||||||
|
if ($bbcode)
|
||||||
|
{ // Execute the file
|
||||||
|
ob_start();
|
||||||
|
$bbcode_return = eval($bbcode);
|
||||||
|
$bbcode_output = ob_get_contents();
|
||||||
|
ob_end_clean();
|
||||||
|
// added to remove possibility of nested bbcode exploits ...
|
||||||
|
// (same as in bbcode_handler - is it right that it just operates on $bbcode_return and not on $bbcode_output? - QUERY XXX-02
|
||||||
|
if(strpos($bbcode_return, "[") !== FALSE)
|
||||||
|
{
|
||||||
|
$exp_search = array("eval", "expression");
|
||||||
|
$exp_replace = array("ev<b></b>al", "expres<b></b>sion");
|
||||||
|
$bbcode_return = str_replace($exp_search, $exp_replace, $bbcode_return);
|
||||||
|
}
|
||||||
|
$full_text = $bbcode_output.$bbcode_return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$nl_replace = "<br />";
|
|
||||||
if ($opts['nobreak'])
|
|
||||||
{
|
|
||||||
$nl_replace = '';
|
|
||||||
}
|
|
||||||
elseif ($opts['retain_nl'])
|
|
||||||
{
|
|
||||||
$nl_replace = "\n";
|
|
||||||
}
|
|
||||||
$text = str_replace(E_NL, $nl_replace, $text);
|
|
||||||
|
|
||||||
return trim($text);
|
if ($proc_funcs)
|
||||||
|
{ // Do the 'normal' processing - in principle, as previously - but think about the order.
|
||||||
|
|
||||||
|
// Split out and ignore any scripts and style blocks. With just two choices we can match the closing tag in the regex
|
||||||
|
$subcon = preg_split('#((?:<s)(?:cript[^>]+>.*?</script>|tyle[^>]+>.*?</style>))#mis', $full_text, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE );
|
||||||
|
foreach ($subcon as $sub_blk)
|
||||||
|
{
|
||||||
|
// if (preg_match('#^<(script|style)[^>]+>#',$sub_blk)) //
|
||||||
|
if ((substr($sub_blk,0,7) == '<script') || (substr($sub_blk,0,6) == '<style'))
|
||||||
|
{ // Its a script/style block - just pass it through unaltered - except, do we need the line break stuff? - QUERY XXX-01
|
||||||
|
if (DB_INF_SHOW) echo "Processing script: {$sub_blk}<br />";
|
||||||
|
if (!$opts['nobreak'])
|
||||||
|
{
|
||||||
|
$sub_blk = preg_replace("#>\s*[\r]*\n[\r]*#", ">", $sub_blk);
|
||||||
|
}
|
||||||
|
$ret_parser .= $sub_blk;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Do 'normal' processing on a chunk
|
||||||
|
|
||||||
|
|
||||||
|
// Could put tag stripping in here
|
||||||
|
|
||||||
|
|
||||||
|
// Line break compression (why?)
|
||||||
|
// Prepare for line-break compression. Avoid compressing newlines in embedded scripts and CSS
|
||||||
|
if (!$opts['nobreak'])
|
||||||
|
{
|
||||||
|
$sub_blk = preg_replace("#>\s*[\r]*\n[\r]*#", ">", $sub_blk);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Link substitution
|
||||||
|
// Convert URL's to clickable links, unless modifiers or prefs override
|
||||||
|
if ($pref['make_clickable'] && !$opts['no_make_clickable'])
|
||||||
|
{
|
||||||
|
if ($pref['link_replace'] && !$opts['no_replace'])
|
||||||
|
{
|
||||||
|
$_ext = ($pref['links_new_window'] ? " rel=\"external\"" : "");
|
||||||
|
$sub_blk = preg_replace("#(^|[\n ])([\w]+?://[^ \"\n\r\t<,]*)#is", "\\1<a href=\"\\2\" {$_ext}>".$pref['link_text']."</a>", $sub_blk);
|
||||||
|
$sub_blk = preg_replace("#(^|[\n \]])((www|ftp)\.[\w+-]+?\.[\w+\-.]*(?(?=/)(/.+?(?=\s|,\s))|(?=\W)))#is", "\\1<a href=\"http://\\2\" {$_ext}>".$pref['link_text']."</a>", $sub_blk);
|
||||||
|
if(CHARSET != "utf-8" && CHARSET != "UTF-8")
|
||||||
|
{
|
||||||
|
$email_text = ($pref['email_text']) ? $this->replaceConstants($pref['email_text']) : "\\1\\2©\\3";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$email_text = ($pref['email_text']) ? $this->replaceConstants($pref['email_text']) : "\\1\\2©\\3";
|
||||||
|
}
|
||||||
|
$sub_blk = preg_replace("#([\n ])([a-z0-9\-_.]+?)@([\w\-]+\.([\w\-\.]+\.)*[\w]+)#i", "\\1<a rel='external' href='javascript:window.location=\"mai\"+\"lto:\"+\"\\2\"+\"@\"+\"\\3\";self.close();' onmouseover='window.status=\"mai\"+\"lto:\"+\"\\2\"+\"@\"+\"\\3\"; return true;' onmouseout='window.status=\"\";return true;'>".$email_text."</a>", $sub_blk);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$sub_blk = preg_replace("#(^|[\n ])([\w]+?://[^ \"\n\r\t<,]*)#is", "\\1<a href=\"\\2\" rel=\"external\">\\2</a>", $sub_blk);
|
||||||
|
$sub_blk = preg_replace("#(^|[\n \]])((www|ftp)\.[\w+-]+?\.[\w+\-.]*(?(?=/)(/.+?(?=\s|,\s))|(?=\W)))#is", "\\1<a href=\"http://\\2\" rel=\"external\">\\2</a>", $sub_blk);
|
||||||
|
$sub_blk = preg_replace("#([\n ])([a-z0-9\-_.]+?)@([\w\-]+\.([\w\-\.]+\.)*[\w]+)#i", "\\1<a rel='external' href='javascript:window.location=\"mai\"+\"lto:\"+\"\\2\"+\"@\"+\"\\3\";self.close();' onmouseover='window.status=\"mai\"+\"lto:\"+\"\\2\"+\"@\"+\"\\3\"; return true;' onmouseout='window.status=\"\";return true;'>".LAN_EMAIL_SUBS."</a>", $sub_blk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Emoticons
|
||||||
|
// Convert emoticons to graphical icons, unless modifiers override
|
||||||
|
if (!$opts['emotes_off'] && ($pref['smiley_activate'] || $opts['emotes_on']))
|
||||||
|
{
|
||||||
|
if (!is_object($this->e_emote))
|
||||||
|
{
|
||||||
|
require_once(e_HANDLER.'emote_filter.php');
|
||||||
|
$this->e_emote = new e_emoteFilter;
|
||||||
|
}
|
||||||
|
$sub_blk = $this->e_emote->filterEmotes($sub_blk);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Newline processing (more)
|
||||||
|
// Reduce multiple newlines in all forms to a single newline character, except for embedded scripts and CSS
|
||||||
|
if (!$opts['nobreak'])
|
||||||
|
{
|
||||||
|
$sub_blk = preg_replace("#[\r]*\n[\r]*#", E_NL, $sub_blk);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Entity conversion
|
||||||
|
// Restore entity form of quotes and such to single characters, except for text destined for tag attributes or JS.
|
||||||
|
if (!$opts['value'])
|
||||||
|
{ // output not used for attribute values.
|
||||||
|
$sub_blk = str_replace($this -> search, $this -> replace, $sub_blk);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // output used for attribute values.
|
||||||
|
$sub_blk = str_replace($this -> replace, $this -> search, $sub_blk);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// BBCode processing (other than the four already done, which shouldn't appear at all in the text)
|
||||||
|
// Start parse [bb][/bb] codes
|
||||||
|
if ($parseBB !== FALSE)
|
||||||
|
{
|
||||||
|
if (!is_object($this->e_bb))
|
||||||
|
{
|
||||||
|
require_once(e_HANDLER.'bbcode_handler.php');
|
||||||
|
$this->e_bb = new e_bbcode;
|
||||||
|
}
|
||||||
|
if ($parseBB === TRUE)
|
||||||
|
{
|
||||||
|
$sub_blk = $this->e_bb->parseBBCodes($sub_blk, $postID); // 'Normal' or 'legacy' processing
|
||||||
|
}
|
||||||
|
elseif ($parseBB === 'STRIP')
|
||||||
|
{
|
||||||
|
$sub_blk = $this->e_bb->parseBBCodes($sub_blk, $postID, 'default', TRUE); // Need to strip all BBCodes
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$sub_blk = $this->e_bb->parseBBCodes($sub_blk, $postID, 'default', $parseBB); // Need to strip just some BBCodes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End parse [bb][/bb] codes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// replace all {e_XXX} constants with their e107 value. modifier determines relative/absolute conversion
|
||||||
|
// (Moved to after bbcode processing by Cameron)
|
||||||
|
if ($opts['constants'])
|
||||||
|
{
|
||||||
|
$sub_blk = $this->replaceConstants($sub_blk, ($opts['abs_links'] ? 'full' : ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// profanity filter
|
||||||
|
if ($pref['profanity_filter'])
|
||||||
|
{
|
||||||
|
if (!is_object($this->e_pf))
|
||||||
|
{
|
||||||
|
require_once(e_HANDLER."profanity_filter.php");
|
||||||
|
$this->e_pf = new e_profanityFilter;
|
||||||
|
}
|
||||||
|
$sub_blk = $this->e_pf->filterProfanities($sub_blk);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Shortcodes
|
||||||
|
// Optional short-code conversion
|
||||||
|
if ($opts['parse_sc'])
|
||||||
|
{
|
||||||
|
$sub_blk = $this->parseTemplate($sub_blk, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Run any hooked in parsers
|
||||||
|
if (!$opts['no_hook'] && varset($pref['tohtml_hook']))
|
||||||
|
{
|
||||||
|
//Process the older tohtml_hook pref (deprecated)
|
||||||
|
foreach(explode(",",$pref['tohtml_hook']) as $hook)
|
||||||
|
{
|
||||||
|
if (!is_object($this->e_hook[$hook]))
|
||||||
|
{
|
||||||
|
require_once(e_PLUGIN.$hook."/".$hook.".php");
|
||||||
|
$hook_class = "e_".$hook;
|
||||||
|
$this->e_hook[$hook] = new $hook_class;
|
||||||
|
}
|
||||||
|
$sub_blk = $this->e_hook[$hook]->$hook($sub_blk,$opts['context']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($pref['e_tohtml_list']) && is_array($pref['e_tohtml_list']))
|
||||||
|
{
|
||||||
|
foreach($pref['e_tohtml_list'] as $hook)
|
||||||
|
{
|
||||||
|
if (!is_object($this->e_hook[$hook]))
|
||||||
|
{
|
||||||
|
require_once(e_PLUGIN.$hook."/e_tohtml.php");
|
||||||
|
$hook_class = "e_tohtml_".$hook;
|
||||||
|
$this->e_hook[$hook] = new $hook_class;
|
||||||
|
}
|
||||||
|
$sub_blk = $this->e_hook[$hook]->to_html($sub_blk, $opts['context']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Word wrap
|
||||||
|
if (!$opts['nobreak'])
|
||||||
|
{
|
||||||
|
$sub_blk = $this -> textclean($sub_blk, $wrap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Search highlighting
|
||||||
|
// Search Highlight
|
||||||
|
if (!$opts['emotes_off'])
|
||||||
|
{
|
||||||
|
if ($this->checkHighlighting())
|
||||||
|
{
|
||||||
|
$sub_blk = $this -> e_highlight($sub_blk, $this -> e_query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Purpose of this block?
|
||||||
|
$nl_replace = "<br />";
|
||||||
|
if ($opts['nobreak'])
|
||||||
|
{
|
||||||
|
$nl_replace = '';
|
||||||
|
}
|
||||||
|
elseif ($opts['retain_nl'])
|
||||||
|
{
|
||||||
|
$nl_replace = "\n";
|
||||||
|
}
|
||||||
|
$sub_blk = str_replace(E_NL, $nl_replace, $sub_blk);
|
||||||
|
|
||||||
|
|
||||||
|
$ret_parser .= $sub_blk;
|
||||||
|
} // End of 'normal' processing for a block of text
|
||||||
|
|
||||||
|
} // End of 'foreach() on each block of non-script text
|
||||||
|
|
||||||
|
|
||||||
|
} // End of 'normal' parsing (non-script text)
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$ret_parser .= $full_text; // Text block that needed no processing at all
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return trim($ret_parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user