ocPortal Developer's Guide: Comcode
» Return to Contents
Although there aren't many functions for processing Comcode, there is a lot of code…we advise you NOT to tweak sources/comcode.php!
Comcode gets compiled to tempcode upon submission, and is stored in the database as 'serialised tempcode'.
sources/comcode.php
Global_functions_comcode.php
Function summary
|
void
|
init__comcode ()
|
|
string
|
comcode_escape (string in)
|
|
LONG_TEXT
|
html_to_comcode (LONG_TEXT html)
|
|
string
|
apply_emoticons (string text)
|
|
mixed
|
do_emoticon (array imgcode)
|
|
tempcode
|
comcode_to_tempcode (LONG_TEXT comcode, ?MEMBER source_member, boolean as_admin, ?integer wrap_pos, ?string pass_id, ?object connection, boolean semiparse_mode, boolean preparse_mode, boolean is_all_semihtml, boolean structure_sweep, boolean check_only, ?array highlight_bits, ?MEMBER on_behalf_of_member)
|
|
string
|
strip_comcode (string text)
|
void init__comcode()
Standard code module initialisation function.
Parameters…
(No return value)
function init__comcode()
{
global $VALID_COMCODE_TAGS;
$VALID_COMCODE_TAGS=array( 'samp'=>1,'q'=>1,'var'=>1,'overlay'=>1,'tooltip'=>1,'section'=>1,'section_controller'=>1,'big_tab'=>1,'big_tab_controller'=>1,'tabs'=>1,'tab'=>1,'carousel'=>1,'cite'=>1,'ins'=>1,'del'=>1,'dfn'=>1,'address'=>1,'acronym'=>1,'abbr'=>1,'contents'=>1,'concepts'=>1,'list'=>1,'flash'=>1,'indent'=>1,'staff_note'=>1,'menu'=>1,'b'=>1,'i'=>1,'u'=>1,'s'=>1,'sup'=>1,'sub'=>1,
'if_in_group'=>1,'title'=>1,'size'=>1,'color'=>1,'highlight'=>1,'font'=>1,'tt'=>1,'box'=>1,'internal_table'=>1,'external_table'=>1,'img'=>1,
'url'=>1,'email'=>1,'reference'=>1,'upload'=>1,'page'=>1,'php'=>1,'codebox'=>1,'sql'=>1,'no_parse'=>1,'code'=>1,'hide'=>1,
'quote'=>1,'block'=>1,'semihtml'=>1,'html'=>1,'exp_thumb'=>1,'exp_ref'=>1,'concept'=>1,'thumb'=>1,'attachment'=>1,'attachment2'=>1,'attachment_safe'=>1,'align'=>1,'left'=>1,'center'=>1,'right'=>1,
'snapback'=>1,'post'=>1,'thread'=>1,'topic'=>1,'include'=>1,'random'=>1,'ticker'=>1,'jumping'=>1,'surround'=>1,'pulse'=>1,'shocker'=>1);
//if (addon_installed('ecommerce'))
{
$VALID_COMCODE_TAGS['currency']=1;
}
global $IMPORTED_CUSTOM_COMCODE,$REPLACE_TARGETS;
$IMPORTED_CUSTOM_COMCODE=false;
$REPLACE_TARGETS=array();
global $COMCODE_ATTACHMENTS,$ATTACHMENTS_ALREADY_REFERENCED;
$COMCODE_ATTACHMENTS=array();
$ATTACHMENTS_ALREADY_REFERENCED=array();
global $COMCODE_PARSE_URLS_CHECKED;
$COMCODE_PARSE_URLS_CHECKED=0;
if (!defined('MAX_URLS_TO_READ')) define('MAX_URLS_TO_READ',5);
global $OVERRIDE_SELF_ZONE;
$OVERRIDE_SELF_ZONE=NULL; // This is not pretty, but needed to properly scope links for search results.
global $LAX_COMCODE;
$LAX_COMCODE=false;
}
string comcode_escape(string in)
Make text usable inside a string inside comcode
Parameters…
| Name |
in |
| Description |
Raw text |
| Type |
string |
Returns…
| Description |
Escaped text |
| Type |
string |
function comcode_escape($in)
{
return str_replace('{','\\{',str_replace('[','\\[',str_replace('"','\\"',str_replace('\\','\\\\',$in))));
}
LONG_TEXT html_to_comcode(LONG_TEXT html)
Convert (X)HTML into comcode
Parameters…
| Name |
html |
| Description |
The HTML to converted |
| Type |
LONG_TEXT |
Returns…
| Description |
The equivalent comcode |
| Type |
LONG_TEXT |
function html_to_comcode($html)
{
// First we allow this to be semi-html
$html=str_replace('[','[',$html);
require_code('comcode_from_html');
return semihtml_to_comcode($html);
}
string apply_emoticons(string text)
Get the text with all the smilie codes replaced with the correct XHTML. Smiles are determined by your forum system.This is not used in the normal comcode chain - it's for non-comcode things that require smilies (actually in reality it is used in the Comcode chain if the optimiser sees that a full parse is not needed)
Parameters…
| Name |
text |
| Description |
The text to add smilies to (assumption: that this is XHTML) |
| Type |
string |
Returns…
| Description |
The XHTML with the image-substitution of smilies |
| Type |
string |
function apply_emoticons($text)
{
$_smilies=$GLOBALS['FORUM_DRIVER']->find_emoticons(); // Sorted in descending length order
if ($GLOBALS['XSS_DETECT']) $orig_escaped=ocp_is_escaped($text);
// Pre-check, optimisation
$smilies=array();
foreach ($_smilies as $code=>$imgcode)
{
if (strpos($text,$code)!==false)
$smilies[$code]=$imgcode;
}
if (count($smilies)!=0)
{
$len=strlen($text);
for ($i=0;$i<$len;++$i) // Has to go through in byte order so double application cannot happen (i.e. smiley contains [all or portion of] smiley code somehow)
{
$char=$text[$i];
if ($char=='"') // This can cause severe HTML corruption so is a disallowed character
{
$i++;
continue;
}
foreach ($smilies as $code=>$imgcode)
{
$code_len=strlen($code);
if (($char==$code[0]) && (substr($text,$i,$code_len)==$code))
{
$eval=do_emoticon($imgcode);
$_eval=$eval->evaluate();
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($_eval);
$before=substr($text,0,$i);
$after=substr($text,$i+$code_len);
if (($before=='') && ($after=='')) $text=$_eval; else $text=$before.$_eval.$after;
$len=strlen($text);
$i+=strlen($_eval)-1;
break;
}
}
}
if (($GLOBALS['XSS_DETECT']) && ($orig_escaped)) ocp_mark_as_escaped($text);
}
return $text;
}
mixed do_emoticon(array imgcode)
Turn a triple of emoticon parameters into some actual tempcode.
Parameters…
| Name |
imgcode |
| Description |
Parameter triple(template,src,code) |
| Type |
array |
Returns…
| Description |
Either a tempcode result, or a string result, depending on $evaluate |
| Type |
mixed |
function do_emoticon($imgcode)
{
$tpl=do_template($imgcode[0],array('UNIQID'=>uniqid(''),'SRC'=>$imgcode[1],'EMOTICON'=>$imgcode[2]));
return $tpl;
}
tempcode comcode_to_tempcode(LONG_TEXT comcode, ?MEMBER source_member, boolean as_admin, ?integer wrap_pos, ?string pass_id, ?object connection, boolean semiparse_mode, boolean preparse_mode, boolean is_all_semihtml, boolean structure_sweep, boolean check_only, ?array highlight_bits, ?MEMBER on_behalf_of_member)
Convert the specified comcode (unknown format) into a tempcode tree. You shouldn't output the tempcode tree to the browser, as it looks really horrible. If you are in a rare case where you need to output directly (not through templates), you should call the evaluate method on the tempcode object, to convert it into a string.
Parameters…
| Name |
comcode |
| Description |
The comcode to convert |
| Type |
LONG_TEXT |
| Name |
source_member |
| Description |
The member the evaluation is running as. This is a security issue, and you should only run as an administrator if you have considered where the comcode came from carefully (NULL: current member) |
| Default value |
|
| Type |
?MEMBER |
| Name |
as_admin |
| Description |
Whether to explicitly execute this with admin rights. There are a few rare situations where this should be done, for data you know didn't come from a member, but is being evaluated by one. Note that if this is passed false, and $source_member is an admin, it will be parsed using admin privileges anyway. |
| Default value |
boolean-false |
| Type |
boolean |
| Name |
wrap_pos |
| Description |
The position to conduct wordwrapping at (NULL: do not conduct word-wrapping) |
| Default value |
60 |
| Type |
?integer |
| Name |
pass_id |
| Description |
A special identifier that can identify this resource in a sea of our resources of this class; usually this can be ignored, but may be used to provide a binding between Javascript in evaluated comcode, and the surrounding environment (NULL: no explicit binding) |
| Default value |
|
| Type |
?string |
| Name |
connection |
| Description |
The database connection to use (NULL: standard site connection) |
| Default value |
|
| Type |
?object |
| Name |
semiparse_mode |
| Description |
Whether to parse so as to create something that would fit inside a semihtml tag. It means we generate HTML, with Comcode written into it where the tag could never be reverse-converted (e.g. a block). |
| Default value |
boolean-false |
| Type |
boolean |
| Name |
preparse_mode |
| Description |
Whether this is being pre-parsed, to pick up errors before row insertion. |
| Default value |
boolean-false |
| Type |
boolean |
| Name |
is_all_semihtml |
| Description |
Whether to treat this whole thing as being wrapped in semihtml, but apply normal security otherwise. |
| Default value |
boolean-false |
| Type |
boolean |
| Name |
structure_sweep |
| Description |
Whether we are only doing this parse to find the title structure |
| Default value |
boolean-false |
| Type |
boolean |
| Name |
check_only |
| Description |
Whether to only check the Comcode. It's best to use the check_comcode function which will in turn use this parameter. |
| Default value |
boolean-false |
| Type |
boolean |
| Name |
highlight_bits |
| Description |
A list of words to highlight (NULL: none) |
| Default value |
|
| Type |
?array |
| Name |
on_behalf_of_member |
| Description |
The member we are running on behalf of, with respect to how attachments are handled; we may use this members attachments that are already within this post, and our new attachments will be handed to this member (NULL: member evaluating) |
| Default value |
|
| Type |
?MEMBER |
Returns…
| Description |
The tempcode generated |
| Type |
tempcode |
function comcode_to_tempcode($comcode,$source_member=NULL,$as_admin=false,$wrap_pos=60,$pass_id=NULL,$connection=NULL,$semiparse_mode=false,$preparse_mode=false,$is_all_semihtml=false,$structure_sweep=false,$check_only=false,$highlight_bits=NULL,$on_behalf_of_member=NULL)
{
$matches=array();
if (preg_match('#^\{\!([A-Z\_]+)\}$#',$comcode,$matches)!=0) return do_lang_tempcode($matches[1]);
if ($semiparse_mode) $wrap_pos=100000;
$attachments=(count($_FILES)!=0);
foreach($_POST as $key=>$value)
{
if (preg_match('#^hidFileID\_#i',$key)!=0) $attachments=true;
}
if ((!$attachments || ($GLOBALS['IN_MINIKERNEL_VERSION']==1)) && (preg_match('#^[\w\d\-\_\(\) \.,:;/"\!\?]*$#'/*NB: No apostophes allowed in here, as they get changed by escape_html and can interfere then with apply_emoticons*/,$comcode)!=0) && (strpos($comcode,' ')===false) && (strpos($comcode,'://')===false))
{
if (running_script('stress_test_loader')) return make_string_tempcode(escape_html($comcode));
return make_string_tempcode(apply_emoticons(escape_html($comcode)));
}
require_code('comcode_renderer');
return _comcode_to_tempcode($comcode,$source_member,$as_admin,$wrap_pos,$pass_id,$connection,$semiparse_mode,$preparse_mode,$is_all_semihtml,$structure_sweep,$check_only,$highlight_bits,$on_behalf_of_member);
}
string strip_comcode(string text)
Strip out any Comcode from this "plain text". Useful for semantic text is wanted but where Comcode is used as "the next best thing" we have.
Parameters…
| Name |
text |
| Description |
Plain-text/Comcode |
| Type |
string |
Returns…
| Description |
Purified plain-text |
| Type |
string |
function strip_comcode($text)
{
require_code('mail');
if (function_exists('comcode_to_clean_text')) // For benefit of installer, which disables mail.php
$text=comcode_to_clean_text($text);
global $VALID_COMCODE_TAGS;
foreach (array_keys($VALID_COMCODE_TAGS) as $tag)
{
if ($tag=='i')
{
$text=preg_replace('#\[/?'.$tag.'\]#','',$text);
} else
{
$text=preg_replace('#\[/?'.$tag.'[^\]]*\]#','',$text);
}
}
return $text;
}
sources/comcode_text.php
Global_functions_comcode_text.php
Function summary
|
void
|
init__comcode_text ()
|
|
tempcode
|
comcode_text_to_tempcode (LONG_TEXT comcode, MEMBER source_member, boolean as_admin, ?integer wrap_pos, ?string pass_id, object connection, boolean semiparse_mode, boolean preparse_mode, boolean is_all_semihtml, boolean structure_sweep, boolean check_only, ?array highlight_bits, ?MEMBER on_behalf_of_member)
|
|
boolean
|
in_tag_stack (array tag_stack, array tags)
|
|
array
|
detect_link (string comcode, integer pos)
|
|
array
|
_opened_tag (boolean mindless_mode, boolean as_admin, MEMBER source_member, array attribute_map, string current_tag, integer pos, boolean comcode_dangerous, boolean comcode_dangerous_html, boolean in_separate_parse_section, boolean in_html, boolean in_semihtml, boolean close, integer len, LONG_TEXT comcode)
|
|
void
|
filter_html (boolean as_admin, MEMBER source_member, integer pos, integer len, LONG_TEXT comcode, boolean in_html, boolean in_semihtml)
|
|
array
|
_close_open_lists (integer list_indent, string list_type)
|
|
array
|
parse_single_comcode_tag (string data, string tag)
|
void init__comcode_text()
Standard code module initialisation function.
Parameters…
(No return value)
function init__comcode_text()
{
if (!defined('CCP_NO_MANS_LAND'))
{
define('CCP_NO_MANS_LAND',0);
define('CCP_IN_TAG_NAME',1);
define('CCP_STARTING_TAG',2);
define('CCP_IN_TAG_BETWEEN_ATTRIBUTES',3);
define('CCP_IN_TAG_ATTRIBUTE_NAME',4);
define('CCP_IN_TAG_BETWEEN_ATTRIBUTE_NAME_VALUE_LEFT',5);
define('CCP_IN_TAG_BETWEEN_ATTRIBUTE_NAME_VALUE_RIGHT',6);
define('CCP_IN_TAG_ATTRIBUTE_VALUE',7);
define('CCP_IN_TAG_ATTRIBUTE_VALUE_NO_QUOTE',8);
define('MAX_COMCODE_TAG_LOOK_AHEAD_LENGTH',30);
}
/*
Note: Certain tags are included for compatibility with bbcode only...
sql
codebox
php
color
size
right
left
center
list
* (this is a psuedo tag because it is actually exploded seperately -- because it is very non-standard)
snapback
topic
post
thread
highlight
flash
Some of threse add features, but they don't really fit in IMHO.
Also for compatibility, tags are case-insensitive, email/url parameter and embed can be switched, and quotes can be missed out.
*/
// In theory, almost any tag is reversable. However these tags can be converted ROBUSTLY and hence the WYSIWYG editor can manipulate them as HTML rather than having to display as Comcode
// If the tag is mapped to a string that provides a regexp to say when it is NOT reversible. Usually this is done for certain parameters.
global $REVERSABLE_TAGS;
$REVERSABLE_TAGS=array('surround'=>1,'attachment_safe'=>1,'attachment2'=>1,'cite'=>1,'ins'=>1,'del'=>1,'dfn'=>1,'address'=>1,'abbr'=>1,'acronym'=>1,'list'=>1,'highlight'=>1,'indent'=>1,'b'=>1,'i'=>1,'u'=>1,'s'=>1,'sup'=>1,'sub'=>1,
'title'=>1,'size'=>1,'color'=>1,'font'=>1,'tt'=>1,'img'=>'#\s(rollover|refresh\_time)=#','url'=>1,'email'=>1,'upload'=>1,
'semihtml'=>1,'html'=>1,'align'=>1,'left'=>1,'center'=>1,'right'=>1,
/*Handled in special way*/
'block'=>1,'contents'=>1,'concepts'=>1,'attachment'=>1,'flash'=>1,'menu'=>1,'reference'=>1,'page'=>1,'exp_thumb'=>1,'exp_ref'=>1,'thumb'=>1,'snapback'=>1,'post'=>1,'thread'=>1,'topic'=>1,'include'=>1,'random'=>1,'jumping'=>1,'shocker'=>1,);
// These are not reversable, but we want them WYSIWYGABLE
global $PUREHTML_TAGS;
$PUREHTML_TAGS=array(/*'attachment2'=>1,'attachment_safe'=>'1*/); // Actually: there is some dynamicness even in this ($KEEP and $SESSION in particular -- and we couldn't even have them preserved inside a WYSIWYG-edit)
// The following could conceivably not need to be reversed, as they're pure HTML. However, it's better not to let the WYSIWYG'd HTML get too complex.
// 'tooltip'=>1,'section'=>1,'section_controller'=>1,'big_tab'=>1,'big_tab_controller'=>1,'tabs'=>1,'tab'=>1,'carousel'=>1,'flash'=>1,'hide'=>1,'quote'=>1,'ticker'=>1,'jumping'=>1
// Any of these will cause free-for-all blacklist-filtered HTML to be disallowed, even if enabled via the hidden option
global $POTENTIALLY_EMPTY_TAGS;
$POTENTIALLY_EMPTY_TAGS=array('concepts'=>1,'staff_note'=>1,'if_in_group'=>1,'no_parse'=>1,'concept'=>1,'include'=>1,'random'=>1,'jumping'=>1);
// The contents of these tags is human readable text. It may be altered for reasons of bork, or word-wrapping, or textcode; they have hard white space
global $TEXTUAL_TAGS;
$TEXTUAL_TAGS=array('overlay'=>1,'tooltip'=>1,'section'=>1,'surround'=>1,'if_in_group'=>1,'cite'=>1,'ins'=>1,'del'=>1,'dfn'=>1,'address'=>1,'abbr'=>1,'acronym'=>1,'list'=>1,'indent'=>1,'align'=>1,'left'=>1,'center'=>1,'right'=>1,'b'=>1,'i'=>1,'u'=>1,'s'=>1,'sup'=>1,'sub'=>1,'title'=>1,'size'=>1,'color'=>1,'highlight'=>1,'font'=>1,'box'=>1,'internal_table'=>1,'external_table'=>1,'hide'=>1,'quote'=>1,'tab'=>1,'big_tab'=>1);
// These tags don't have <br />'s done right after them because they are their own block-end (like a paragraph). They may contain textcode lists and rules
global $BLOCK_TAGS;
$BLOCK_TAGS=array('section'=>1,'section_controller'=>1,'tabs'=>1,'tab'=>1,'big_tab'=>1,'big_tab_controller'=>1,'carousel'=>1,'surround'=>1,'if_in_group'=>1,'exp_thumb'=>1,'contents'=>1,'concepts'=>1,'php'=>1,'codebox'=>1,'sql'=>1,'code'=>1,'list'=>1,'indent'=>1,'align'=>1,'left'=>1,'center'=>1,'right'=>1,'staff_note'=>1,'reference'=>1,'menu'=>1,'title'=>1,'box'=>1,'internal_table'=>1,'external_table'=>1,'quote'=>1,'block'=>1,'hide'=>1);
// These tags can only be used by privileged members
global $DANGEROUS_TAGS;
$DANGEROUS_TAGS=array('overlay'=>1,'if_in_group'=>1,'concepts'=>1,'random'=>1,'include'=>1,'block'=>1,'menu'=>1); // Don't want people putting menus around, plus the captions aren't escaped
// These tags have contents that are not interpreted as Comcode (so no HTML tags either), but are formatted for white-space
global $CODE_TAGS;
$CODE_TAGS=array(/*'img'=>1 - no, can be a symbol for legacy reasons,*/'flash'=>1,'thumb'=>1,'menu'=>1,'no_parse'=>1,'code'=>1,'sql'=>1,'php'=>1,'tt'=>1,'samp'=>1,'codebox'=>1);
// ALSO:
// See $non_text_tags list in comcode_renderer.php
// See non_text_tags in JAVASCRIPT_EDITING.tpl
// See _get_details_comcode_tags function in comcode_add.php
// We're not allowed to specify any of these as entities
global $POTENTIAL_JS_NAUGHTY_ARRAY;
$POTENTIAL_JS_NAUGHTY_ARRAY=array('d'=>1,/*'a'=>1,'t'=>1,'a'=>1,*/'j'=>1,'a'=>1,'v'=>1,'s'=>1,'c'=>1,'r'=>1,'i'=>1,'p'=>1,'t'=>1,'J'=>1,'A'=>1,'V'=>1,'S'=>1,'C'=>1,'R'=>1,'I'=>1,'P'=>1,'T'=>1,' '=>1,"\t"=>1,"\n"=>1,"\r"=>1,':'=>1,'/'=>1,'*'=>1,'\\'=>1);
$POTENTIAL_JS_NAUGHTY_ARRAY[chr(0)]=1;
// Hehe
global $LEET_FILTER;
$LEET_FILTER=NULL;
global $ALLOWED_ENTITIES;
// $ALLOWED_ENTITIES=array('raquo'=>1,'frac14'=>1,'frac12'=>1,'frac34'=>1,'ndash'=>1,'mdash'=>1,'ldquo'=>1,'rdquo'=>1);
$ALLOWED_ENTITIES=array('OElig'=>1,'oelig'=>1,'Scaron'=>1,'scaron'=>1,'Yuml'=>1,'circ'=>1,'tilde'=>1,'ensp'=>1,'emsp'=>1,'thinsp'=>1,'zwnj'=>1,'zwj'=>1,'lrm'=>1,'rlm'=>1,'ndash'=>1,'mdash'=>1,'lsquo'=>1,'rsquo'=>1,'sbquo'=>1,'ldquo'=>1,'rdquo'=>1,'bdquo'=>1,'dagger'=>1,'Dagger'=>1,'hellip'=>1,'permil'=>1,'lsaquo'=>1,'rsaquo'=>1,'euro'=>1,'Agrave'=>1,'Aacute'=>1,'Acirc'=>1,'Atilde'=>1,'Auml'=>1,'Aring'=>1,'AElig'=>1,'Ccedil'=>1,'Egrave'=>1,'Eacute'=>1,'Ecirc'=>1,'Euml'=>1,'Igrave'=>1,'Iacute'=>1,'Icirc'=>1,'Iuml'=>1,'ETH'=>1,'Ntilde'=>1,'Ograve'=>1,'Oacute'=>1,'Ocirc'=>1,'Otilde'=>1,'Ouml'=>1,'Oslash'=>1,'Ugrave'=>1,'Uacute'=>1,'Ucirc'=>1,'Uuml'=>1,'Yacute'=>1,'THORN'=>1,'szlig'=>1,'agrave'=>1,'aacute'=>1,'acirc'=>1,'atilde'=>1,'auml'=>1,'aring'=>1,'aelig'=>1,'ccedil'=>1,'egrave'=>1,'eacute'=>1,'ecirc'=>1,'euml'=>1,'igrave'=>1,'iacute'=>1,'icirc'=>1,'iuml'=>1,'eth'=>1,'ntilde'=>1,'ograve'=>1,'oacute'=>1,'ocirc'=>1,'otilde'=>1,'ouml'=>1,'oslash'=>1,'ugrave'=>1,'uacute'=>1,'ucirc'=>1,'uuml'=>1,'yacute'=>1,'thorn'=>1,'yuml'=>1,'nbsp'=>1,'iexcl'=>1,'curren'=>1,'cent'=>1,'pound'=>1,'yen'=>1,'brvbar'=>1,'sect'=>1,'uml'=>1,'copy'=>1,'ordf'=>1,'laquo'=>1,'not'=>1,'shy'=>1,'reg'=>1,'trade'=>1,'macr'=>1,'deg'=>1,'plusmn'=>1,'sup2'=>1,'sup3'=>1,'acute'=>1,'micro'=>1,'para'=>1,'middot'=>1,'cedil'=>1,'sup1'=>1,'ordm'=>1,'raquo'=>1,'frac14'=>1,'frac12'=>1,'frac34'=>1,'iquest'=>1,'times'=>1,'divide'=>1,'amp'=>1,'lt'=>1,'gt'=>1,'quot'=>1);
global $ADVERTISING_BANNERS;
$ADVERTISING_BANNERS=NULL;
global $NO_LINK_TITLES;
$NO_LINK_TITLES=false;
}
tempcode comcode_text_to_tempcode(LONG_TEXT comcode, MEMBER source_member, boolean as_admin, ?integer wrap_pos, ?string pass_id, object connection, boolean semiparse_mode, boolean preparse_mode, boolean is_all_semihtml, boolean structure_sweep, boolean check_only, ?array highlight_bits, ?MEMBER on_behalf_of_member)
Convert the specified comcode (text format) into a tempcode tree. You shouldn't output the tempcode tree to the browser, as it looks really horrible. If you are in a rare case where you need to output directly (not through templates), you should call the evaluate method on the tempcode object, to convert it into a string.
Parameters…
| Name |
comcode |
| Description |
The comcode to convert |
| Type |
LONG_TEXT |
| Name |
source_member |
| Description |
The member the evaluation is running as. This is a security issue, and you should only run as an administrator if you have considered where the comcode came from carefully |
| Type |
MEMBER |
| Name |
as_admin |
| Description |
Whether to explicitly execute this with admin rights. There are a few rare situations where this should be done, for data you know didn't come from a member, but is being evaluated by one. |
| Type |
boolean |
| Name |
wrap_pos |
| Description |
The position to conduct wordwrapping at (NULL: do not conduct word-wrapping) |
| Type |
?integer |
| Name |
pass_id |
| Description |
A special identifier that can identify this resource in a sea of our resources of this class; usually this can be ignored, but may be used to provide a binding between Javascript in evaluated comcode, and the surrounding environment (NULL: no explicit binding) |
| Type |
?string |
| Name |
connection |
| Description |
The database connection to use |
| Type |
object |
| Name |
semiparse_mode |
| Description |
Whether to parse so as to create something that would fit inside a semihtml tag. It means we generate HTML, with Comcode written into it where the tag could never be reverse-converted (e.g. a block). |
| Type |
boolean |
| Name |
preparse_mode |
| Description |
Whether this is being pre-parsed, to pick up errors before row insertion. |
| Type |
boolean |
| Name |
is_all_semihtml |
| Description |
Whether to treat this whole thing as being wrapped in semihtml, but apply normal security otherwise. |
| Type |
boolean |
| Name |
structure_sweep |
| Description |
Whether we are only doing this parse to find the title structure |
| Type |
boolean |
| Name |
check_only |
| Description |
Whether to only check the Comcode. It's best to use the check_comcode function which will in turn use this parameter. |
| Type |
boolean |
| Name |
highlight_bits |
| Description |
A list of words to highlight (NULL: none) |
| Default value |
|
| Type |
?array |
| Name |
on_behalf_of_member |
| Description |
The member we are running on behalf of, with respect to how attachments are handled; we may use this members attachments that are already within this post, and our new attachments will be handed to this member (NULL: member evaluating) |
| Default value |
|
| Type |
?MEMBER |
Returns…
| Description |
The tempcode generated |
| Type |
tempcode |
function comcode_text_to_tempcode($comcode,$source_member,$as_admin,$wrap_pos,$pass_id,$connection,$semiparse_mode,$preparse_mode,$is_all_semihtml,$structure_sweep,$check_only,$highlight_bits=NULL,$on_behalf_of_member=NULL)
{
global $ADVERTISING_BANNERS,$ALLOWED_ENTITIES,$POTENTIALLY_EMPTY_TAGS,$CODE_TAGS,$REVERSABLE_TAGS,$PUREHTML_TAGS,$DANGEROUS_TAGS,$VALID_COMCODE_TAGS,$BLOCK_TAGS,$POTENTIAL_JS_NAUGHTY_ARRAY,$TEXTUAL_TAGS,$LEET_FILTER,$IMPORTED_CUSTOM_COMCODE,$REPLACE_TARGETS;
$wml=false; // removed feature from ocPortal now
$print_mode=get_param_integer('wide_print',0)==1;
$len=strlen($comcode);
if ((function_exists('set_time_limit')) && (ini_get('max_execution_time')!='0')) @set_time_limit(300);
$allowed_html_seqs=array('<table>','<table class="[^"]*">','<table class="[^"]*" summary="[^"]*">','<table summary="[^"]*">','</table>','<tr>','</tr>','<td>','</td>','<th>','</th>','<pre>','</pre>','<br />','<br/>','<br >','<br>','<p>','</p>','<p />','<b>','</b>','<u>','</u>','<i>','</i>','<em>','</em>','<strong>','</strong>','<ul>','</ul>','<ol>','</ol>','<del>','</del>','<dir>','</dir>','<s>','</s>','</a>','</font>','<!--','<h1 id="main_page_title">','<h1 class="main_page_title">','<h1 id="main_page_title" class="main_page_title">','</h1>','<img (class="inline_image" )?alt="[^"]*" src="[^"]*" (complete="true" )*/>','<img src=["\'][^"\'<>]*["\']( border=["\'][^"\'<>]*["\'])?( alt=["\'][^"\'<>]*["\'])?( )?(/)?'.'>','<a href=["\'][^"\'<>]*["\']( target=["\'][^"\'<>]*["\'])?'.'>'); // HTML tag may actually be used in very limited conditions: only the following HTML seqs will come out as HTML. This is, unless the blacklist filter is used instead.
if ($as_admin)
{
$comcode_dangerous=true;
$comcode_dangerous_html=true;
} else
{
$comcode_dangerous=($GLOBALS['MICRO_BOOTUP']==0) && (has_specific_permission($source_member,'comcode_dangerous'));
$comcode_dangerous_html=false;
if ((has_specific_permission($source_member,'allow_html')) && (($is_all_semihtml) || (strpos($comcode,'[html')!==false) || (strpos($comcode,'[semihtml')!==false)))
{
$comcode_dangerous_html=true;
/*foreach (array_keys($POTENTIALLY_EMPTY_TAGS) as $tag) // Find whether we really need to enable the computational-expensive filtering. Code disabled, not sure why this would have ever worked!
{
if (($tag!='html') && ($tag!='semihtml') && (strpos($comcode,'['.$tag)!==false))
{
$comcode_dangerous_html=false;
break;
}
}*/
}
}
if (is_null($pass_id)) $pass_id=strval(mt_rand(0,32000)); // This is a unique ID that refers to this specific piece of comcode
global $COMCODE_ATTACHMENTS;
if (!array_key_exists($pass_id,$COMCODE_ATTACHMENTS)) $COMCODE_ATTACHMENTS[$pass_id]=array();
// Tag level
$current_tag='';
$attribute_map=array();
$tag_output=new ocp_tempcode();
$continuation='';
$close=mixed();
// Properties that come from our tag
$white_space_area=true;
$textual_area=true;
$formatting_allowed=true;
$in_html=false;
$in_semihtml=$is_all_semihtml;
$in_separate_parse_section=false; // Not escaped because it has to be passed to a secondary filter
$in_code_tag=false;
$code_nest_stack=0;
// Our state
$status=CCP_NO_MANS_LAND;
$lax=$GLOBALS['LAX_COMCODE']; // if we don't want to produce errors for technically invalid Comcode
$tag_stack=array();
$pos=0;
$line_starting=true;
$just_ended=false;
$none_wrap_length=0;
$just_new_line=true; // So we can detect lists starting right away
$just_title=false;
global $NUM_LINES;
$NUM_LINES=0;
$queued_tempcode=new ocp_tempcode();
$mindless_mode=false; // If we're doing a semi parse mode and going over a tag we don't actually process
$tag_raw='';
$stupidity_mode=get_value('stupidity_mode'); // bork or leet
if ($comcode_dangerous) $stupidity_mode=get_param('stupidity_mode','');
if ($stupidity_mode=='leet')
{
$LEET_FILTER=array(
'B'=>'8',
'C'=>'(',
'E'=>'3',
'G'=>'9',
'I'=>'1',
'L'=>'1',
'O'=>'0',
'P'=>'9',
'S'=>'5',
'U'=>'0',
'V'=>'\/',
'Z'=>'2'
);
}
$smilies=$GLOBALS['FORUM_DRIVER']->find_emoticons(); // We'll be needing the smiley array
$shortcuts=array('(EUR-)'=>'€','{f.}'=>'ƒ','-|-'=>'†','=|='=>'‡','{%o}'=>'‰','{~S}'=>'Š','{~Z}'=>'Ž','(TM)'=>'™','{~s}'=>'š','{~z}'=>'ž','{.Y.}'=>'Ÿ','(c)'=>'©','(r)'=>'®','---'=>'—','--'=>'–','...'=>'…','-->'=>'→','<--'=>'←');
// Text syntax possibilities, that get maintained as our cursor moves through the text block
$list_indent=0;
$list_type='ul';
if ($is_all_semihtml) filter_html($as_admin,$source_member,$pos,$len,$comcode,false,false); // Pre-filter the whole lot (note that this means during general output we do no additional filtering)
while ($pos<$len)
{
$next=$comcode[$pos];
++$pos;
// State machine
switch ($status)
{
case CCP_NO_MANS_LAND:
if ($next=='[')
{
// Look ahead to make sure it's a valid tag. If it's not then it's considered normal user input, not a tag at all
$dif=(($pos<$len) && ($comcode[$pos]=='/'))?1:0;
$ahead=substr($comcode,$pos+$dif,MAX_COMCODE_TAG_LOOK_AHEAD_LENGTH);
$equal_pos=strpos($ahead,'=');
$space_pos=strpos($ahead,' ');
$end_pos=strpos($ahead,']');
$lax_end_pos=strpos($ahead,'[');
$cl_pos=strpos($ahead,chr(10));
if ($equal_pos===false) $equal_pos=MAX_COMCODE_TAG_LOOK_AHEAD_LENGTH+3;
if ($space_pos===false) $space_pos=MAX_COMCODE_TAG_LOOK_AHEAD_LENGTH+3;
if ($end_pos===false) $end_pos=MAX_COMCODE_TAG_LOOK_AHEAD_LENGTH+3;
if ($lax_end_pos===false) $lax_end_pos=MAX_COMCODE_TAG_LOOK_AHEAD_LENGTH+3;
if ($cl_pos===false) $cl_pos=MAX_COMCODE_TAG_LOOK_AHEAD_LENGTH+3;
$use_pos=min($equal_pos,$space_pos,$end_pos,$lax_end_pos,$cl_pos);
$potential_tag=strtolower(substr($ahead,0,$use_pos));
if (($use_pos!=22) && ((!$in_semihtml) || ($dif==1) || (($potential_tag!='html') && ($potential_tag!='semihtml'))) && ((!$in_html) || (($dif==1) && ($potential_tag=='html'))) && ((!$in_code_tag) || ((isset($CODE_TAGS[$potential_tag])) && ($potential_tag==$current_tag))) && ((!$structure_sweep) || ($potential_tag!='contents')))
{
if ($in_code_tag)
{
if ($dif==1)
{
$code_nest_stack--;
} else
{
$code_nest_stack++;
}
$ok=($code_nest_stack==-1);
} else $ok=true;
if ($ok)
{
if (!isset($VALID_COMCODE_TAGS[$potential_tag]))
{
if (!$IMPORTED_CUSTOM_COMCODE)
_custom_comcode_import($connection);
}
if ((isset($VALID_COMCODE_TAGS[$potential_tag])) && (strtolower(substr($ahead,0,2))!='i ')) // The "i" bit is just there to block a common annoyance: [i] doesn't take parameters and we don't want "[i think]" (for example) being parsed.
{
if (($comcode[$pos]!='/') || (count($tag_stack)==0))
$mindless_mode=($semiparse_mode) && /*(!isset($CODE_TAGS[$potential_tag])) && */((!isset($REVERSABLE_TAGS[$potential_tag])) || ((is_string($REVERSABLE_TAGS[$potential_tag])) && (preg_match($REVERSABLE_TAGS[$potential_tag],substr($comcode,$pos,100))!=0))) && (!isset($PUREHTML_TAGS[$potential_tag]));
else $mindless_mode=$tag_stack[count($tag_stack)-1][7];
$close=false;
$current_tag='';
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($continuation);
$tag_output->attach($continuation);
$continuation='';
if ((/*(($potential_tag=='html') || ($potential_tag=='semihtml')) && */($just_new_line)) || (isset($BLOCK_TAGS[$potential_tag])))
{
list($close_list,$list_indent)=_close_open_lists($list_indent,$list_type);
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($close_list);
$tag_output->attach($close_list);
}
$status=CCP_STARTING_TAG;
if ($mindless_mode)
{
if ($comcode[$pos]!='/')
{
if (array_key_exists($potential_tag,$BLOCK_TAGS))
{
$tag_raw='​<kbd title="'.escape_html($potential_tag).'" class="ocp_keep_block">[';
} else
{
$tag_raw='​<kbd title="'.escape_html($potential_tag).'" class="ocp_keep">[';
}
} else
{
$tag_raw='[';
}
} else
{
$tag_raw='';
}
continue;
}
}
} else
{
if (($use_pos!=22) && ((($in_semihtml) || ($in_html)) && (($potential_tag=='html') || ($potential_tag=='semihtml'))) && (!$in_code_tag))
{
$ahc=strpos($ahead,']');
if ($ahc!==false)
{
$pos+=$ahc+1;
continue;
}
}
}
}
if ((($in_html) || ((($in_semihtml) && (!$in_code_tag)) && (($next=='<') || ($next=='>') || ($next=='"')))))
{
if ($next==chr(10)) ++$NUM_LINES;
if ((!$comcode_dangerous_html) && ($next=='<')) // Special filtering required
{
$close=strpos($comcode,'>',$pos-1);
$portion=substr($comcode,$pos-1,$close-$pos+2);
$seq_ok=false;
foreach ($allowed_html_seqs as $allowed_html_seq)
{
if (preg_match('#^'.$allowed_html_seq.'$#',$portion)!=0) $seq_ok=true;
}
if (!$seq_ok)
{
// $next='<'; //OLD STYLE
if ($close!==false) $pos=$close+1; // NEW STYLE
continue;
}
}
if (substr($comcode,$pos-1,4)=='<!--') // To stop shortcut interpretation
{
$continuation.='<!--';
$pos+=3;
} else
{
$continuation.=($mindless_mode && $in_code_tag)?escape_html($next):$next;
}
}
else // Not in HTML
{
// Text-format possibilities
if (($just_new_line) && ($formatting_allowed) && (!$wml))
{
if ($continuation!='')
{
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($continuation);
$tag_output->attach($continuation);
$continuation='';
}
// List
$found_list=false;
$old_list_indent=$list_indent;
if (($pos+2<$len) && (is_numeric($next)) && (((is_numeric($comcode[$pos])) && ($comcode[$pos+1]==')') && ($comcode[$pos+2]==' ')) || (($comcode[$pos]==')') && ($comcode[$pos+1]==' '))) && ((($list_type=='1') && ($list_indent!=0)) || (preg_match('#^[^\n]*\n\d+\) #',substr($comcode,$pos+1))!=0)))
{
if (($list_indent!=0) && ($list_type!='1'))
{
list($temp_tpl,$old_list_indent)=_close_open_lists($list_indent,$list_type);
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($temp_tpl);
$tag_output->attach($temp_tpl);
}
$list_indent=1;
$found_list=true;
$scan_pos=$pos;
$list_type='1';
}
elseif (($pos+2<$len) && (ord($next)>=ord('a')) && (ord($next)<=ord('z')) && ($comcode[$pos]==')') && ($comcode[$pos+1]==' ') && ((($list_type=='a') && ($list_indent!=0)) || (preg_match('#^[^\n]*\n\d+\) #',substr($comcode,$pos+1))!=0)))
{
if (($list_indent!=0) && ($list_type!='a'))
{
list($temp_tpl,$old_list_indent)=_close_open_lists($list_indent,$list_type);
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($temp_tpl);
$tag_output->attach($temp_tpl);
}
$list_indent=1;
$found_list=true;
$scan_pos=$pos;
$list_type='a';
}
elseif ($next==' ')
{
if (($old_list_indent!=0) && ($list_type!='ul'))
{
list($temp_tpl,$old_list_indent)=_close_open_lists($list_indent,$list_type);
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($temp_tpl);
$tag_output->attach($temp_tpl);
}
$scan_pos=$pos-1;
$list_indent=0;
while ($scan_pos<$len)
{
$scan_next=$comcode[$scan_pos];
if (($scan_next=='-') && ($scan_pos+1<$len) && ($comcode[$scan_pos+1]==' '))
{
$found_list=true;
break;
} else
{
if ($scan_next==' ') ++$list_indent; else break;
}
++$scan_pos;
}
if (!$found_list) $list_indent=0; else $list_type='ul';
}
// Rule?
else
{
list($close_list,$list_indent)=_close_open_lists($list_indent,$list_type);
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($close_list);
$tag_output->attach($close_list);
$old_list_indent=0;
if (($next=='-') && (!$just_title))
{
$scan_pos=$pos;
$found_rule=true;
while ($scan_pos<$len)
{
$scan_next=$comcode[$scan_pos];
if ($scan_next!='-')
{
if ($scan_next==chr(10))
{
++$NUM_LINES;
break;
} else $found_rule=false;
}
++$scan_pos;
}
if ($found_rule)
{
$_temp_tpl=do_template('COMCODE_TEXTCODE_LINE');
$tag_output->attach($_temp_tpl);
$pos=$scan_pos+1;
$just_ended=true;
$none_wrap_length=0;
continue;
}
}
}
// List handling
if (($list_indent==$old_list_indent) && ($old_list_indent!=0))
{
$temp_tpl='</li>';
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($temp_tpl);
$tag_output->attach($temp_tpl);
}
for ($i=$list_indent;$i<$old_list_indent;++$i) // Close any ended
{
$temp_tpl='</li>';
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($temp_tpl);
$tag_output->attach($temp_tpl);
$temp_tpl=($list_type=='ul')?'</ul>':'</ol>';
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($temp_tpl);
$tag_output->attach($temp_tpl);
}
if (($list_indent<$old_list_indent) && ($list_indent!=0)) // Go down one final level, because the list tag must have been nested within an li tag (we closed open li tags recursively except for the final one)
{
$temp_tpl='</li>';
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($temp_tpl);
$tag_output->attach($temp_tpl);
}
if ($found_list)
{
if ((($list_indent-$old_list_indent)>1) && (!$lax))
{
return comcode_parse_error($preparse_mode,array('CCP_LIST_JUMPYNESS'),$pos,$comcode,$check_only);
}
for ($i=$old_list_indent;$i<$list_indent;++$i) // Or open any started
{
switch ($list_type)
{
case 'ul':
if ($i<$list_indent-1) $temp_tpl='<ul><li>'; else $temp_tpl='<ul>';
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($temp_tpl);
$tag_output->attach($temp_tpl);
break;
case '1':
if ($i<$list_indent-1) $temp_tpl='<ol type="1"><li>'; else $temp_tpl='<ol type="1">';
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($temp_tpl);
$tag_output->attach($temp_tpl);
break;
case 'a':
if ($i<$list_indent-1) $temp_tpl='<ol type="a"><li>'; else $temp_tpl='<ol type="a">';
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($temp_tpl);
$tag_output->attach($temp_tpl);
break;
}
}
$temp_tpl='<li>';
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($temp_tpl);
$tag_output->attach($temp_tpl);
$just_ended=true;
$none_wrap_length=0;
$next='';
$pos=$scan_pos+2;
}
}
if (($next==chr(10)) && ($white_space_area) && ($print_mode) && ($list_indent==0)) // We might need to put some queued up stuff here: when we print, we can't float thumbnails
{
$tag_output->attach($queued_tempcode);
$queued_tempcode=new ocp_tempcode();
}
if (($next==chr(10)) && ($white_space_area) && (!$in_semihtml) && ((!$just_ended) || ($semiparse_mode) || (substr($comcode,$pos,3)==' - '))) // Hard-new-lines
{
++$NUM_LINES;
$line_starting=true;
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($continuation);
$tag_output->attach($continuation);
$continuation='';
$just_new_line=true;
$none_wrap_length=0;
if (($list_indent==0) && (!$just_ended))
{
$temp_tpl='<br />';
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($temp_tpl);
$tag_output->attach($temp_tpl);
}
}
else
{
$just_new_line=false;
if (($next==' ') && ($white_space_area) && (!$in_semihtml))
{
if (($line_starting) || (($pos>1) && ($comcode[$pos-2]==' '))) // Hard spaces
{
$next=' ';
++$none_wrap_length;
} else $none_wrap_length=0;
$continuation.=($mindless_mode && $in_code_tag)?escape_html($next):$next;
}
elseif (($next=="\t") && ($white_space_area) && (!$in_semihtml))
{
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($continuation);
$tag_output->attach($continuation);
$continuation='';
$tab_tpl=do_template('COMCODE_TEXTCODE_TAB');
$_tab_tpl=$tab_tpl->evaluate();
$none_wrap_length+=strlen($_tab_tpl);
$tag_output->attach($tab_tpl);
} else
{
if (($next==' ') || ($next=="\t") || ($just_ended)) $none_wrap_length=0; else
{
if ((!is_null($wrap_pos)) && ($none_wrap_length>=$wrap_pos) && ($textual_area) && (!$in_semihtml))
{
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($continuation);
$tag_output->attach($continuation);
$continuation='';
$temp_tpl='<br />';
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($temp_tpl);
$tag_output->attach($temp_tpl);
$none_wrap_length=0;
} elseif ($textual_area) ++$none_wrap_length;
}
$line_starting=false;
$just_ended=false;
$differented=false; // If somehow via lookahead we've changed this to HTML and thus won't use it in raw form
// Variable lookahead
if ((!$in_code_tag) && (($next=='{') && (isset($comcode[$pos])) && (($comcode[$pos]=='$') || ($comcode[$pos]=='+') || ($comcode[$pos]=='!'))))
{
if ($comcode_dangerous)
{
if ((!$in_code_tag) && ((!$semiparse_mode) || (in_tag_stack($tag_stack,array('url','img','flash')))))
{
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($continuation);
$tag_output->attach($continuation);
$continuation='';
if ($comcode[$pos]=='+')
{
$p_end=$pos+5;
while ($p_end<$len)
{
$p_portion=substr($comcode,$pos-1,$p_end-($pos-1)+5);
if (substr_count($p_portion,'{+START')==substr_count($p_portion,'{+END')) break;
$p_end++;
}
$p_len=1;
while ($pos+$p_len<$len)
{
$p_portion=substr($comcode,$pos-1,$p_len);
if (substr_count(str_replace('{',' { ',$p_portion),'{')==substr_count(str_replace('}',' } ',$p_portion),'}')) break; // str_replace is to workaround a Quercus bug #4494
$p_len++;
}
$p_len--;
$p_portion=substr($comcode,$pos+$p_len,$p_end-($pos+$p_len));
require_code('tempcode_compiler');
$ret=template_to_tempcode(substr($comcode,$pos-1,$p_len+1).'{DIRECTIVE_EMBEDMENT}'.substr($comcode,$p_end,6));
$attaches_before=count($COMCODE_ATTACHMENTS[$pass_id]);
$ret->singular_bind('DIRECTIVE_EMBEDMENT',comcode_text_to_tempcode($p_portion,$source_member,$as_admin,$wrap_pos,$pass_id,$connection,$semiparse_mode,$preparse_mode,$in_semihtml,$structure_sweep,$check_only,$highlight_bits,$on_behalf_of_member));
for ($attach_inspect=$attaches_before;$attach_inspect<count($COMCODE_ATTACHMENTS[$pass_id]);$attach_inspect++)
{
$COMCODE_ATTACHMENTS[$pass_id][$attach_inspect]['marker']+=$pos+$p_len;
}
$pos=$p_end+6;
}
elseif ($comcode[$pos]=='!')
{
$p_len=$pos;
$balance=1;
while (($p_len<$len) && ($balance!=0))
{
if ($comcode[$p_len]=='{') $balance++; elseif ($comcode[$p_len]=='}') $balance--;
$p_len++;
}
$ret=new ocp_tempcode();
$less_pos=$pos-1;
$ret->parse_from($comcode,$less_pos,$p_len);
$pos=$p_len;
if (($ret->parameterless(0)) && ($pos<$len)) // We want to take the lang string reference as Comcode if it's a simple lang string reference with no parameters
{
$matches=array();
if (preg_match('#\{\!([\w\d\_\:]+)(\}|$)#U',substr($comcode,$less_pos),$matches)!=0) // Hacky code to extract the lang string name
{
$temp_lang_string=$matches[1];
$ret=comcode_lang_string($temp_lang_string); // Recreate as a Comcode lang string
}
}
} else
{
$p_len=$pos;
$balance=1;
while (($p_len<$len) && ($balance!=0))
{
if ($comcode[$p_len]=='{') $balance++; elseif ($comcode[$p_len]=='}') $balance--;
$p_len++;
}
$ret=new ocp_tempcode();
$less_pos=$pos-1;
$ret->parse_from($comcode,$less_pos,$p_len);
$pos=$p_len;
}
$differented=true;
if (($pos<=$len) || (!$lax))
{
$tag_output->attach($ret);
}
}
} else
{
if (($comcode[$pos]=='$') && ($pos<$len-2) && ($comcode[$pos+1]==',') && (strpos($comcode,'}',$pos)!==false))
{
$pos=strpos($comcode,'}',$pos)+1;
$differented=true;
}
}
}
// Escaping of comcode tag starts lookahead
if (($next=='\\') && (!$in_code_tag)) // We are changing \[ to [ with the side-effect of blocking a tag start. To get \[ literal, we need the symbols \\[... and add extra \-pairs as needed. We are only dealing with \ and [ (update: and now {) here, it's not a further extended means of escaping.
{
if (($pos!=$len) && (($comcode[$pos]=='"') || (substr($comcode,$pos-1,6)=='"')))
{
if ($semiparse_mode) $continuation.='\\';
if ($comcode[$pos]=='"')
{
$continuation.=$mindless_mode?'"':'"';
++$pos;
} else
{
$continuation.='"';
$pos+=6;
}
$differented=true;
}
elseif (($pos!=$len) && ($comcode[$pos]=='['))
{
if ($semiparse_mode) $continuation.='\\';
$continuation.='[';
++$pos;
$differented=true;
}
elseif (($pos!=$len) && ($comcode[$pos]=='{'))
{
if ($semiparse_mode) $continuation.='\\';
$continuation.='{';
++$pos;
$differented=true;
}
elseif (($pos==$len) || ($comcode[$pos]=='\\'))
{
if ($semiparse_mode) $continuation.='\\';
$continuation.='\\';
++$pos;
$differented=true;
}
}
if (!$differented)
{
if ((($textual_area) || ($in_semihtml)) && (trim($next)!='') && (!$wml))
{
// Emoticon lookahead
foreach ($smilies as $smiley=>$imgcode)
{
if ($in_semihtml) $smiley=' '.$smiley.' ';
if ($next==$smiley[0]) // optimisation
{
if (substr($comcode,$pos-1,strlen($smiley))==$smiley)
{
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($continuation);
$tag_output->attach($continuation);
$continuation='';
$pos+=strlen($smiley)-1;
$differented=true;
$tag_output->attach(do_emoticon($imgcode));
break;
}
}
}
}
}
if ((trim($next)!='') && (!$in_code_tag) && (!$differented))
{
// CEDI pages
if (($pos<$len) && ($next=='[') && ($pos+1<$len) && ($comcode[$pos]=='[') && (!$semiparse_mode) && (addon_installed('cedi')))
{
$matches=array();
if (preg_match('#^\[([^\[\]]*)\]\]#',substr($comcode,$pos,200),$matches)!=0)
{
$cedi_page_name=$matches[1];
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($continuation);
$tag_output->attach($continuation);
$continuation='';
$hash_pos=strpos($cedi_page_name,'#');
if ($hash_pos!==false)
{
$jump_to=substr($cedi_page_name,$hash_pos+1);
$cedi_page_name=substr($cedi_page_name,0,$hash_pos);
} else $jump_to='';
$cedi_page_url=build_url(array('page'=>'cedi','type'=>'misc','find'=>$cedi_page_name),get_module_zone('cedi'));
if ($jump_to!='')
{
$cedi_page_url->attach('#'.$jump_to);
}
$tag_output->attach(do_template('COMCODE_CEDI_LINK',array('_GUID'=>'ebcd7ba5290c5b2513272a53b4d666e5','URL'=>$cedi_page_url,'TEXT'=>$cedi_page_name)));
$pos+=strlen($matches[1])+3;
$differented=true;
}
}
// Usernames
if (($pos<$len) && ($next=='{') && ($pos+1<$len) && ($comcode[$pos]=='{') && (!$in_code_tag) && (!$semiparse_mode))
{
$matches=array();
if (preg_match('#^\{([^"{}&\'\$<>]+)\}\}#',substr($comcode,$pos,80),$matches)!=0)
{
$username=$matches[1];
if ($username[0]=='?')
{
$username_info=true;
$username=substr($username,1);
} else $username_info=false;
$this_member_id=$GLOBALS['FORUM_DRIVER']->get_member_from_username($username);
if ((!is_null($this_member_id)) && (!is_guest($this_member_id)))
{
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($continuation);
$tag_output->attach($continuation);
$continuation='';
$poster_url=$GLOBALS['FORUM_DRIVER']->member_profile_url($this_member_id,false,true);
if ((get_forum_type()=='ocf') && ($username_info))
{
require_lang('ocf');
require_code('ocf_members2');
$details=ocf_show_member_box($this_member_id);
$tag_output->attach(do_template('HYPERLINK_TOOLTIP',array('_GUID'=>'d8f4f4ac70bd52b3ef9ee74ae9c5e085','TOOLTIP'=>$details,'CAPTION'=>$username,'URL'=>$poster_url,'NEW_WINDOW'=>false)));
} else
{
$tag_output->attach(hyperlink($poster_url,$username));
}
$pos+=strlen($matches[1])+3;
$differented=true;
}
}
}
}
if (($textual_area) && (!$in_code_tag) && (trim($next)!='') && (!$differented))
{
// Shortcut lookahead
if (!$differented)
{
if (($in_semihtml) && (substr($comcode,$pos-1,3)=='-->')) // To stop shortcut interpretation
{
$continuation.='-->';
$pos+=2;
break;
}
foreach ($shortcuts as $code=>$replacement)
{
if (($next==$code[0]) && (substr($comcode,$pos-1,strlen($code))==$code))
{
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($continuation);
$tag_output->attach($continuation);
$continuation='';
$pos+=strlen($code)-1;
$differented=true;
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($replacement);
$tag_output->attach($replacement);
break;
}
}
}
}
if (($textual_area) && (!$in_code_tag) && (trim($next)!='') && (!$differented))
{
// Table syntax
if (!$differented)
{
if (($pos<$len) && ($comcode[$pos]=='|'))
{
$end_tbl=strpos($comcode,chr(10).'|}',$pos);
if ($end_tbl!==false)
{
$end_fst_line_pos=strpos($comcode,chr(10),$pos);
$caption=substr($comcode,$pos+2,max($end_fst_line_pos-$pos-2,0));
$pos+=strlen($caption)+1;
$rows=preg_split('#(\|-|\|\})#Um',substr($comcode,$pos,$end_tbl-$pos));
if (preg_match('#(^|\s)floats($|\s)#',$caption)!=0)
{
$caption=preg_replace('#(^|\s)floats($|\s)#','',$caption);
$ratios=array();
$ratios_matches=array();
if (preg_match('#(^|\s)([\d\.]+%(:[\d\.]+%)*)($|\s)#',$caption,$ratios_matches)!=0)
{
$ratios=explode(':',$ratios_matches[2]);
$caption=str_replace($ratios_matches[0],'',$caption);
}
foreach ($rows as $i=>$row)
{
if ($i!=0) $tag_output->attach(do_template('BLOCK_SEPARATOR'));
$cells=preg_split('/(\n\! | \!\! |\n\| | \|\| )/',$row,-1,PREG_SPLIT_DELIM_CAPTURE);
array_shift($cells); // First one is non-existant empty
$spec=true;
// Find which to float
$to_float=NULL;
foreach ($cells as $i=>$cell)
{
if (!$spec)
{
if ((strpos($cell,'!')!==false) || (is_null($to_float))) $to_float=$i;
}
$spec=!$spec;
}
$tag_output->attach(do_template('COMCODE_FAKE_TABLE_WRAP_START'));
// Do floated one
$i_dir_1=(($to_float==1)?'left':'right');
$i_dir_2=(($to_float!=1)?'left':'right');
if (preg_match('#(^|\s)wide($|\s)#',$caption)!=0)
{
$tag_output->attach(do_template('COMCODE_FAKE_TABLE_WIDE_START',array('_GUID'=>'ced8c3a142f74296a464b085ba6891c9','WIDTH'=>array_key_exists(($to_float==1)?0:(count($cells)-1),$ratios)?$ratios[($to_float==1)?0:(count($cells)-1)]:((count($cells)==2)?'0':float_to_raw_string(97.0/(floatval(count($cells))/2.0-1.0),2).'%'),'FLOAT'=>$i_dir_1,'PADDING'=>($to_float==1)?'':'-left','PADDING_AMOUNT'=>(count($cells)==2)?'0':float_to_raw_string(3.0/(floatval(count($cells)-2)/2.0),2))));
} else
{
$tag_output->attach(do_template('COMCODE_FAKE_TABLE_START',array('_GUID'=>'90be72fcbb6b9d8a312da0bee5b86cb3','WIDTH'=>array_key_exists($to_float,$ratios)?$ratios[$to_float]:'','FLOAT'=>$i_dir_1,'PADDING'=>($to_float==1)?'':'-left','PADDING_AMOUNT'=>(count($cells)==2)?'0':float_to_raw_string(3.0/(floatval(count($cells)-2.0)/2.0),2))));
}
$attaches_before=count($COMCODE_ATTACHMENTS[$pass_id]);
$tag_output->attach(comcode_text_to_tempcode(isset($cells[$to_float])?rtrim($cells[$to_float]):'',$source_member,$as_admin,60,$pass_id,$connection,$semiparse_mode,$preparse_mode,$in_semihtml,$structure_sweep,$check_only,$highlight_bits,$on_behalf_of_member));
for ($attach_inspect=$attaches_before;$attach_inspect<count($COMCODE_ATTACHMENTS[$pass_id]);$attach_inspect++)
{
$COMCODE_ATTACHMENTS[$pass_id][$attach_inspect]['marker']+=strpos($comcode,$cells[$to_float],$pos);
}
$tag_output->attach(do_template('COMCODE_FAKE_TABLE_END'));
// Do non-floated ones
$cell_i=0;
foreach ($cells as $i=>$cell)
{
if ($i%2==1)
{
if ($i!=$to_float)
{
if (preg_match('#(^|\s)wide($|\s)#',$caption)!=0)
{
$tag_output->attach(do_template('COMCODE_FAKE_TABLE_WIDE2_START',array('_GUID'=>'9bac42a1b62c5c9a2f758639fcb3bb2f','WIDTH'=>array_key_exists($cell_i,$ratios)?$ratios[$cell_i]:(float_to_raw_string(97.0/(floatval(count($cells))/2.0),2).'%'),'PADDING_AMOUNT'=>(count($cells)==2)?'0':float_to_raw_string(3.0/(floatval(count($cells)-2)/2.0),2),'FLOAT'=>$i_dir_1,'PADDING'=>(($to_float==1)||($cell_i!=0))?'-left':'')));
} else
{
$tag_output->attach(do_template('COMCODE_FAKE_TABLE_2_START',array('_GUID'=>'0f15f9d5554635ed7ac154c9dc5c72b8','WIDTH'=>array_key_exists($cell_i,$ratios)?$ratios[$cell_i]:'','FLOAT'=>$i_dir_1,'PADDING'=>(($to_float==1)||($cell_i!=0))?'-left':'','PADDING_AMOUNT'=>(count($cells)==2)?'0':float_to_raw_string(3.0/(floatval(count($cells)-2)/2.0),2))));
}
$attaches_before=count($COMCODE_ATTACHMENTS[$pass_id]);
$tag_output->attach(comcode_text_to_tempcode(rtrim($cell),$source_member,$as_admin,60,$pass_id,$connection,$semiparse_mode,$preparse_mode,$in_semihtml,$structure_sweep,$check_only,$highlight_bits,$on_behalf_of_member));
for ($attach_inspect=$attaches_before;$attach_inspect<count($COMCODE_ATTACHMENTS[$pass_id]);$attach_inspect++)
{
$COMCODE_ATTACHMENTS[$pass_id][$attach_inspect]['marker']+=strpos($comcode,$cell,$pos);
}
$tag_output->attach(do_template('COMCODE_FAKE_TABLE_END'));
}
$cell_i++;
}
}
$tag_output->attach(do_template('COMCODE_FAKE_TABLE_WRAP_END'));
}
} else
{
$ratios=array();
$ratios_matches=array();
if (preg_match('#(^|\s)([\d\.]+%(:[\d\.]+%)*)($|\s)#',$caption,$ratios_matches)!=0)
{
$ratios=explode(':',$ratios_matches[2]);
$caption=str_replace($ratios_matches[0],'',$caption);
}
if (preg_match('#(^|\s)wide($|\s)#',$caption)!=0)
{
$tag_output->attach(do_template('COMCODE_REAL_TABLE_START',array('SUMMARY'=>preg_replace('#(^|\s)wide($|\s)#','',$caption))));
} else
{
$tag_output->attach(do_template('COMCODE_REAL_TABLE_START_SUMMARY',array('_GUID'=>'0c5674fba61ba14b4b9fa39ea31ff54f','CAPTION'=>$caption)));
}
foreach ($rows as $table_row)
{
$tag_output->attach(do_template('COMCODE_REAL_TABLE_ROW_START'));
$cells=preg_split('/(\n\! | \!\! |\n\| | \|\| )/',$table_row,-1,PREG_SPLIT_DELIM_CAPTURE);
array_shift($cells); // First one is non-existant empty
$spec=true;
$c_type='';
$cell_i=0;
foreach ($cells as $i=>$cell)
{
if ($spec)
{
$c_type=(strpos($cell,'!')!==false)?'th':'td';
} else
{
$attaches_before=count($COMCODE_ATTACHMENTS[$pass_id]);
$_mid=comcode_text_to_tempcode(rtrim($cell),$source_member,$as_admin,60,$pass_id,$connection,$semiparse_mode,$preparse_mode,$in_semihtml,$structure_sweep,$check_only,$highlight_bits,$on_behalf_of_member);
for ($attach_inspect=$attaches_before;$attach_inspect<count($COMCODE_ATTACHMENTS[$pass_id]);$attach_inspect++)
{
$COMCODE_ATTACHMENTS[$pass_id][$attach_inspect]['marker']+=strpos($comcode,$cell,$pos);
}
$tag_output->attach(do_template('COMCODE_REAL_TABLE_CELL',array('_GUID'=>'6640df8b503f65e3d36f595b0acf7600','WIDTH'=>array_key_exists($cell_i,$ratios)?$ratios[$cell_i]:'','C_TYPE'=>$c_type,'MID'=>$_mid,'PADDING'=>($cell_i==0)?'':'-left','PADDING_AMOUNT'=>(count($cells)==2)?'0':float_to_raw_string(5.0/(floatval(count($cells)-2)/2.0),2))));
$cell_i++;
}
$spec=!$spec;
}
$tag_output->attach(do_template('COMCODE_REAL_TABLE_ROW_END'));
}
$tag_output->attach(do_template('COMCODE_REAL_TABLE_END'));
}
$pos=$end_tbl+3;
$differented=true;
}
}
}
// Advertising
$b_all=true; // leave true - for test purposes only
if ((!$differented) && (!$semiparse_mode) && (!$in_code_tag) && (addon_installed('banners')) && (($b_all) || (!has_specific_permission($source_member,'banner_free'))))
{
// Pick up correctly, including permission filtering
if (is_null($ADVERTISING_BANNERS))
{
$rows=$GLOBALS['SITE_DB']->query('SELECT * FROM '.get_table_prefix().'banners b LEFT JOIN '.get_table_prefix().'banner_types t ON b.b_type=t.id WHERE t_comcode_inline=1 AND '.db_string_not_equal_to('b_title_text',''),NULL,NULL,true);
if (!is_null($rows))
{
// Filter out what we don't have permission for
if (get_option('use_banner_permissions',true)=='1')
{
require_code('permissions');
$groups=_get_where_clause_groups($source_member);
if (!is_null($groups))
{
$perhaps=collapse_1d_complexity('category_name',$GLOBALS['SITE_DB']->query('SELECT category_name FROM '.get_table_prefix().'group_category_access WHERE '.db_string_equal_to('module_the_name','banners').' AND ('.$groups.')'));
$new_rows=array();
foreach ($rows as $row)
{
if (in_array($row['name'],$perhaps)) $new_rows[]=$row;
}
$rows=$new_rows;
}
}
$ADVERTISING_BANNERS=array();
foreach ($rows as $row)
{
$trigger_text=$row['b_title_text'];
foreach (explode(',',$trigger_text) as $t)
if (trim($t)!='') $ADVERTISING_BANNERS[trim($t)]=$row;
}
}
}
// Apply
if (!is_null($ADVERTISING_BANNERS))
{
foreach ($ADVERTISING_BANNERS as $ad_trigger=>$ad_bits)
{
if (strtolower($next)==strtolower($ad_trigger[0])) // optimisation
{
if (strtolower(substr($comcode,$pos-1,strlen($ad_trigger)))==strtolower($ad_trigger))
{
require_code('banners');
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($continuation);
$tag_output->attach($continuation);
$continuation='';
$differented=true;
$ad_text=show_banner($ad_bits['name'],$ad_bits['b_title_text'],get_translated_tempcode($ad_bits['caption']),$ad_bits['img_url'],'',$ad_bits['site_url'],$ad_bits['b_type']);
$embed_output=_do_tags_comcode('tooltip',array('param'=>$ad_text,'url'=>(url_is_local($ad_bits['site_url']) && ($ad_bits['site_url']!=''))?(get_custom_base_url().'/'.$ad_bits['site_url']):$ad_bits['site_url']),substr($comcode,$pos-1,strlen($ad_trigger)),$comcode_dangerous,$pass_id,$pos,$source_member,$as_admin,$connection,$comcode,$wml,$structure_sweep,$semiparse_mode,$highlight_bits);
$pos+=strlen($ad_trigger)-1;
$tag_output->attach($embed_output);
}
}
}
}
}
// Search highlighting lookahead
if ((!$differented) && (!is_null($highlight_bits)))
{
foreach ($highlight_bits as $highlight_bit)
{
if (strtolower($next)==strtolower($highlight_bit[0])) // optimisation
{
if (strtolower(substr($comcode,$pos-1,strlen($highlight_bit)))==strtolower($highlight_bit))
{
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($continuation);
$tag_output->attach($continuation);
$continuation='';
$differented=true;
$embed_output=_do_tags_comcode('highlight',array(),escape_html(substr($comcode,$pos-1,strlen($highlight_bit))),$comcode_dangerous,$pass_id,$pos,$source_member,$as_admin,$connection,$comcode,$wml,$structure_sweep,$semiparse_mode,$highlight_bits);
$pos+=strlen($highlight_bit)-1;
$tag_output->attach($embed_output);
break;
}
}
}
}
// Link lookahead
if ((!$differented) && (!$in_code_tag))
{
if ((!$in_semihtml) && ($next=='h') && ((substr($comcode,$pos-1,strlen('http://'))=='http://') || (substr($comcode,$pos-1,strlen('https://'))=='https://') || (substr($comcode,$pos-1,strlen('ftp://'))=='ftp://')))
{
$link_end_pos=strpos($comcode,' ',$pos-1);
$link_end_pos_2=strpos($comcode,chr(10),$pos-1);
$link_end_pos_3=strpos($comcode,'[',$pos-1);
$link_end_pos_4=strpos($comcode,')',$pos-1);
$link_end_pos_5=strpos($comcode,'"',$pos-1);
$link_end_pos_6=strpos($comcode,'>',$pos-1);
$link_end_pos_7=strpos($comcode,'<',$pos-1);
$link_end_pos_8=strpos($comcode,'.'.chr(10),$pos-1);
$link_end_pos_9=strpos($comcode,', ',$pos-1);
$link_end_pos_10=strpos($comcode,'. ',$pos-1);
$link_end_pos_11=strpos($comcode,"'",$pos-1);
if (($link_end_pos_2!==false) && (($link_end_pos===false) || ($link_end_pos_2<$link_end_pos))) $link_end_pos=$link_end_pos_2;
if (($link_end_pos_3!==false) && (($link_end_pos===false) || ($link_end_pos_3<$link_end_pos))) $link_end_pos=$link_end_pos_3;
if (($link_end_pos_4!==false) && (($link_end_pos===false) || ($link_end_pos_4<$link_end_pos))) $link_end_pos=$link_end_pos_4;
if (($link_end_pos_5!==false) && (($link_end_pos===false) || ($link_end_pos_5<$link_end_pos))) $link_end_pos=$link_end_pos_5;
if (($link_end_pos_6!==false) && (($link_end_pos===false) || ($link_end_pos_6<$link_end_pos))) $link_end_pos=$link_end_pos_6;
if (($link_end_pos_7!==false) && (($link_end_pos===false) || ($link_end_pos_7<$link_end_pos))) $link_end_pos=$link_end_pos_7;
if (($link_end_pos_8!==false) && (($link_end_pos===false) || ($link_end_pos_8<$link_end_pos))) $link_end_pos=$link_end_pos_8;
if (($link_end_pos_9!==false) && (($link_end_pos===false) || ($link_end_pos_9<$link_end_pos))) $link_end_pos=$link_end_pos_9;
if (($link_end_pos_10!==false) && (($link_end_pos===false) || ($link_end_pos_10<$link_end_pos))) $link_end_pos=$link_end_pos_10;
if (($link_end_pos_11!==false) && (($link_end_pos===false) || ($link_end_pos_11<$link_end_pos))) $link_end_pos=$link_end_pos_11;
if ($link_end_pos===false) $link_end_pos=strlen($comcode);
$auto_link=preg_replace('#(keep|for)_session=[\d\w]*#','filtered=1',substr($comcode,$pos-1,$link_end_pos-$pos+1));
if (substr($auto_link,-3)!='://')
{
if (substr($auto_link,-1)=='.')
{
$auto_link=substr($auto_link,0,strlen($auto_link)-1);
$link_end_pos--;
}
$auto_link_tempcode=new ocp_tempcode();
$auto_link_tempcode->attach($auto_link);
if (!$check_only)
{
$link_captions_title=$GLOBALS['SITE_DB']->query_value_null_ok('url_title_cache','t_title',array('t_url'=>$auto_link));
if ((is_null($link_captions_title)) || (substr($link_captions_title,0,1)=='!'))
{
$GLOBALS['COMCODE_PARSE_URLS_CHECKED']++;
if (($GLOBALS['NO_LINK_TITLES']) || ($GLOBALS['COMCODE_PARSE_URLS_CHECKED']>=MAX_URLS_TO_READ))
{
$link_captions_title=$auto_link;
} else
{
$link_captions_title='';
$downloaded_at_link=http_download_file($auto_link,3000,false);
if ((is_string($downloaded_at_link)) && (strpos($GLOBALS['HTTP_DOWNLOAD_MIME_TYPE'],'html')!==false) && ($GLOBALS['HTTP_MESSAGE']=='200'))
{
$matches=array();
if (preg_match('#\s*<title[^>]*\s*>\s*(.*)\s*\s*<\s*/title\s*>#miU',$downloaded_at_link,$matches)!=0)
{
require_code('character_sets');
$link_captions_title=trim(str_replace('–','-',str_replace('—','-',@html_entity_decode(convert_to_internal_encoding($matches[1]),ENT_QUOTES,get_charset()))));
if (((strpos(strtolower($link_captions_title),'login')!==false) || (strpos(strtolower($link_captions_title),'log in')!==false)) && (substr($auto_link,0,strlen(get_base_url()))==get_base_url()))
$link_captions_title=''; // don't show login screen titles for our own website. Better to see the link verbatim
}
}
$GLOBALS['SITE_DB']->query_insert('url_title_cache',array(
't_url'=>$auto_link,
't_title'=>$link_captions_title,
),false,true); // To stop weird race-like conditions
}
}
$embed_output=mixed();
$link_handlers=find_all_hooks('systems','comcode_link_handlers');
foreach (array_keys($link_handlers) as $link_handler)
{
require_code('hooks/systems/comcode_link_handlers/'.$link_handler);
$link_handler_ob=object_factory('Hook_comcode_link_handler_'.$link_handler);
$embed_output=$link_handler_ob->bind($auto_link,$link_captions_title,$comcode_dangerous,$pass_id,$pos,$source_member,$as_admin,$connection,$comcode,$wml,$structure_sweep,$semiparse_mode,$highlight_bits);
if (!is_null($embed_output)) break;
}
if (is_null($embed_output))
{
$page_link=url_to_pagelink($auto_link,true);
if ($link_captions_title=='') $link_captions_title=$auto_link;
if ($page_link!='')
{
$embed_output=_do_tags_comcode('page',array('param'=>$page_link),make_string_tempcode(escape_html($link_captions_title)),$comcode_dangerous,$pass_id,$pos,$source_member,$as_admin,$connection,$comcode,$wml,$structure_sweep,$semiparse_mode,$highlight_bits);
} else
{
$embed_output=_do_tags_comcode('url',array('param'=>$link_captions_title),$auto_link_tempcode,$comcode_dangerous,$pass_id,$pos,$source_member,$as_admin,$connection,$comcode,$wml,$structure_sweep,$semiparse_mode,$highlight_bits);
}
}
} else $embed_output=new ocp_tempcode();
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($continuation);
$tag_output->attach($continuation);
$continuation='';
$tag_output->attach($embed_output);
$pos+=$link_end_pos-$pos;
$differented=true;
}
}
}
}
if (!$differented)
{
if (($stupidity_mode!='') && ($textual_area))
{
if (($stupidity_mode=='leet') && (mt_rand(0,1)==1))
{
if (array_key_exists(strtoupper($next),$LEET_FILTER)) $next=$LEET_FILTER[strtoupper($next)];
}
elseif (($stupidity_mode=='bork') && (mt_rand(0,60)==1))
{
$next.='-bork-bork-bork-';
}
}
if ((!$in_separate_parse_section) && ((!$in_semihtml) || ((!$comcode_dangerous_html)/*If we don't support HTML and we haven't done the all_semihtml pre-filter at the top*/ && (!$is_all_semihtml)))) // Display char. We try and support entities
{
if ($next=='&')
{
$ahead=substr($comcode,$pos,20);
$ahead_lower=strtolower($ahead);
$matches=array();
$entity=preg_match('#^(\#)?([\w]*);#',$ahead_lower,$matches)!=0; // If it is a SAFE entity, use it
if (($entity) && (!$in_code_tag))
{
if (($matches[1]=='') && (($in_semihtml) || (isset($ALLOWED_ENTITIES[$matches[2]]))))
{
$pos+=strlen($matches[2])+1;
$continuation.='&'.$matches[2].';';
} elseif ((is_numeric($matches[2])) && ($matches[1]=='#'))
{
$matched_entity=intval(base_convert($matches[2],16,10));
if (($matched_entity<127) && (array_key_exists(chr($matched_entity),$POTENTIAL_JS_NAUGHTY_ARRAY)))
{
$continuation.=escape_html($next);
} else
{
$pos+=strlen($matches[2])+2;
$continuation.='&#'.$matches[2].';';
}
} else
{
$continuation.='&';
}
} else
{
$continuation.='&';
}
} else
{
$continuation.=($semiparse_mode && !($mindless_mode && $in_code_tag))?$next:escape_html($next);
}
} else
{
$continuation.=$next;
}
}
}
}
}
break;
case CCP_IN_TAG_NAME:
if (($mindless_mode) && ($next!='[')) $tag_raw.=($next);
if ($next=='=')
{
$status=CCP_IN_TAG_BETWEEN_ATTRIBUTE_NAME_VALUE_RIGHT;
$current_attribute_name='param';
}
elseif (trim($next)=='')
{
$status=CCP_IN_TAG_BETWEEN_ATTRIBUTES;
}
elseif ($next=='[')
{
if (!$lax) return comcode_parse_error($preparse_mode,array('CCP_TAG_OPEN_ANOMALY'),$pos,$comcode,$check_only);
$next=']';
$pos--;
}
if ($next==']')
{
if ($close)
{
if ($formatting_allowed)
{
list($close_list,$list_indent)=_close_open_lists($list_indent,$list_type);
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($close_list);
$tag_output->attach($close_list);
}
if (count($tag_stack)==0)
{
if ($lax)
{
$status=CCP_NO_MANS_LAND;
break;
}
return comcode_parse_error($preparse_mode,array('CCP_NO_CLOSE',$current_tag),strrpos(substr($comcode,0,$pos),'['),$comcode,$check_only);
}
$has_it=false;
foreach (array_reverse($tag_stack) as $t)
{
if ($t[0]==$current_tag)
{
$has_it=true;
break;
}
if (($in_semihtml) && (($current_tag=='html') || ($current_tag=='semihtml'))) // Only search one level for this
break;
}
if ($has_it)
{
$_last=array_pop($tag_stack);
if ($_last[0]!=$current_tag)
{
if (!$lax)
{
return comcode_parse_error($preparse_mode,array('CCP_NO_CLOSE_MATCH',$current_tag,$_last[0]),$pos,$comcode,$check_only);
}
do
{
$embed_output=_do_tags_comcode($_last[0],$_last[1],$tag_output,$comcode_dangerous,$pass_id,$pos,$source_member,$as_admin,$connection,$comcode,$wml,$structure_sweep,$semiparse_mode,NULL,NULL,$in_semihtml,$is_all_semihtml);
$in_code_tag=false;
$white_space_area=$_last[3];
$in_separate_parse_section=$_last[4];
$formatting_allowed=$_last[5];
$textual_area=$_last[6];
$tag_output=$_last[2];
$tag_output->attach($embed_output);
$mindless_mode=$_last[7];
$comcode_dangerous=$_last[8];
$comcode_dangerous_html=$_last[9];
if (count($tag_stack)==0) // Hmm, it was never open. So let's pretend this tag close never happened
{
$status=CCP_NO_MANS_LAND;
break 2;
}
$_last=array_pop($tag_stack);
}
while ($_last[0]!=$current_tag);
}
} else
{
$extraneous_semihtml=((!$is_all_semihtml) && (!$in_semihtml)) || (($current_tag!='html') && ($current_tag!='semihtml'));
if ((!$lax) && ($extraneous_semihtml))
{
$_last=array_pop($tag_stack);
return comcode_parse_error($preparse_mode,array('CCP_NO_CLOSE_MATCH',$current_tag,$_last[0]),$pos,$comcode,$check_only);
}
$status=CCP_NO_MANS_LAND;
break;
}
// Do the comcode for this tag
if ($in_semihtml) // We need to perform some magic to clean up the Comcode sections
{
foreach ($_last[1] as $index=>$conv)
{
$_last[1][$index]=@html_entity_decode(str_replace('<br />',chr(10),$conv),ENT_QUOTES,get_charset());
}
}
$mindless_mode=$_last[7];
if ($mindless_mode)
{
$embed_output=$tag_output;
}
elseif (!$check_only)
{
$_structure_sweep=false;
if ($structure_sweep)
{
$_structure_sweep=!in_tag_stack($tag_stack,array('title'));
}
$embed_output=_do_tags_comcode($_last[0],$_last[1],$tag_output,$comcode_dangerous,$pass_id,$pos,$source_member,$as_admin,$connection,$comcode,$wml,$_structure_sweep,$semiparse_mode,$highlight_bits,NULL,$in_semihtml,$is_all_semihtml);
} else $embed_output=new ocp_tempcode();
$in_code_tag=false;
$white_space_area=$_last[3];
$in_separate_parse_section=$_last[4];
$formatting_allowed=$_last[5];
$textual_area=$_last[6];
$tag_output=$_last[2];
$comcode_dangerous=$_last[8];
$comcode_dangerous_html=$_last[9];
if (($print_mode) && ($_last[0]=='exp_thumb'))
{
$queued_tempcode->attach($embed_output);
} else
{
$tag_output->attach($embed_output);
}
$just_ended=isset($BLOCK_TAGS[$current_tag]);
if ($current_tag=='title')
{
if ((strlen($comcode)>$pos+1) && ($comcode[$pos]==chr(10)) && ($comcode[$pos+1]==chr(10))) // Linux newline
{
$NUM_LINES+=2;
$pos+=2;
$just_new_line=true;
}
}
if ($current_tag=='html') $in_html=false;
elseif ($current_tag=='semihtml') $in_semihtml=false;
$status=CCP_NO_MANS_LAND;
} else
{
if ($current_tag=='title')
{
$just_new_line=false;
list($close_list,$list_indent)=_close_open_lists($list_indent,$list_type);
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($close_list);
$tag_output->attach($close_list);
}
array_push($tag_stack,array($current_tag,$attribute_map,$tag_output,$white_space_area,$in_separate_parse_section,$formatting_allowed,$textual_area,$mindless_mode,$comcode_dangerous,$comcode_dangerous_html));
list($tag_output,$comcode_dangerous,$comcode_dangerous_html,$white_space_area,$formatting_allowed,$in_separate_parse_section,$textual_area,$attribute_map,$status,$in_html,$in_semihtml,$pos,$in_code_tag)=_opened_tag($mindless_mode,$as_admin,$source_member,$attribute_map,$current_tag,$pos,$comcode_dangerous,$comcode_dangerous_html,$in_separate_parse_section,$in_html,$in_semihtml,$close,$len,$comcode);
if ($in_code_tag) $code_nest_stack=0;
}
$tag_output->attach($tag_raw);
if (($close) && ($mindless_mode))
{
$temp_tpl='</kbd>​';
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($temp_tpl);
$tag_output->attach($temp_tpl);
}
}
elseif ($status==CCP_IN_TAG_NAME) $current_tag.=strtolower($next);
break;
case CCP_STARTING_TAG:
if (($mindless_mode) && ($next!='[')) $tag_raw.=($next);
if ($next=='[') // Can't actually occur though
{
if (!$lax) return comcode_parse_error($preparse_mode,array('CCP_TAG_OPEN_ANOMALY'),$pos,$comcode,$check_only);
$status=CCP_NO_MANS_LAND;
$pos--;
}
elseif ($next==']') // Can't actual occur though
{
if (!$lax) return comcode_parse_error($preparse_mode,array('CCP_TAG_CLOSE_ANOMALY'),$pos,$comcode,$check_only);
$status=CCP_NO_MANS_LAND;
}
elseif ($next=='/')
{
$close=true;
}
else
{
$current_tag.=strtolower($next);
$status=CCP_IN_TAG_NAME;
}
break;
case CCP_IN_TAG_BETWEEN_ATTRIBUTES:
if (($mindless_mode) && ($next!='[')) $tag_raw.=($next);
if ($next==']')
{
if ($current_tag=='title')
{
$just_new_line=false;
list($close_list,$list_indent)=_close_open_lists($list_indent,$list_type);
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($close_list);
$tag_output->attach($close_list);
}
array_push($tag_stack,array($current_tag,$attribute_map,$tag_output,$white_space_area,$in_separate_parse_section,$formatting_allowed,$textual_area,$mindless_mode,$comcode_dangerous,$comcode_dangerous_html));
list($tag_output,$comcode_dangerous,$comcode_dangerous_html,$white_space_area,$formatting_allowed,$in_separate_parse_section,$textual_area,$attribute_map,$status,$in_html,$in_semihtml,$pos,$in_code_tag)=_opened_tag($mindless_mode,$as_admin,$source_member,$attribute_map,$current_tag,$pos,$comcode_dangerous,$comcode_dangerous_html,$in_separate_parse_section,$in_html,$in_semihtml,$close,$len,$comcode);
if ($in_code_tag) $code_nest_stack=0;
$tag_output->attach($tag_raw);
}
elseif ($next=='[')
{
if (!$lax) return comcode_parse_error($preparse_mode,array('CCP_TAG_OPEN_ANOMALY'),$pos,$comcode,$check_only);
if ($current_tag=='title')
{
$just_new_line=false;
list($close_list,$list_indent)=_close_open_lists($list_indent,$list_type);
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($close_list);
$tag_output->attach($close_list);
}
array_push($tag_stack,array($current_tag,$attribute_map,$tag_output,$white_space_area,$in_separate_parse_section,$formatting_allowed,$textual_area,$mindless_mode,$comcode_dangerous,$comcode_dangerous_html));
list($tag_output,$comcode_dangerous,$comcode_dangerous_html,$white_space_area,$formatting_allowed,$in_separate_parse_section,$textual_area,$attribute_map,$status,$in_html,$in_semihtml,$pos,$in_code_tag)=_opened_tag($mindless_mode,$as_admin,$source_member,$attribute_map,$current_tag,$pos,$comcode_dangerous,$comcode_dangerous_html,$in_separate_parse_section,$in_html,$in_semihtml,$close,$len,$comcode);
if ($in_code_tag) $code_nest_stack=0;
$tag_output->attach($tag_raw);
$pos--;
}
elseif (trim($next)!='')
{
$status=CCP_IN_TAG_ATTRIBUTE_NAME;
$current_attribute_name=$next;
}
break;
case CCP_IN_TAG_ATTRIBUTE_NAME:
if (($mindless_mode) && ($next!='[')) $tag_raw.=($next);
if ($next=='[')
{
$status=CCP_NO_MANS_LAND;
$pos--;
if (!$lax) return comcode_parse_error($preparse_mode,array('CCP_TAG_OPEN_ANOMALY'),$pos,$comcode,$check_only);
if ($current_tag=='title')
{
$just_new_line=false;
list($close_list,$list_indent)=_close_open_lists($list_indent,$list_type);
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($close_list);
$tag_output->attach($close_list);
}
array_push($tag_stack,array($current_tag,$attribute_map,$tag_output,$white_space_area,$in_separate_parse_section,$formatting_allowed,$textual_area,$mindless_mode,$comcode_dangerous,$comcode_dangerous_html));
list($tag_output,$comcode_dangerous,$comcode_dangerous_html,$white_space_area,$formatting_allowed,$in_separate_parse_section,$textual_area,$attribute_map,$status,$in_html,$in_semihtml,$pos,$in_code_tag)=_opened_tag($mindless_mode,$as_admin,$source_member,$attribute_map,$current_tag,$pos,$comcode_dangerous,$comcode_dangerous_html,$in_separate_parse_section,$in_html,$in_semihtml,$close,$len,$comcode);
if ($in_code_tag) $code_nest_stack=0;
$tag_output->attach($tag_raw);
}
elseif ($next==']')
{
if (($attribute_map==array()) && (!$lax))
{
return comcode_parse_error($preparse_mode,array('CCP_TAG_CLOSE_ANOMALY'),$pos,$comcode,$check_only);
}
if ($attribute_map!=array())
{
$at_map_keys=array_keys($attribute_map);
$old_attribute_name=$at_map_keys[count($at_map_keys)-1];
$attribute_map[$old_attribute_name].=' '.$current_attribute_name;
}
array_push($tag_stack,array($current_tag,$attribute_map,$tag_output,$white_space_area,$in_separate_parse_section,$formatting_allowed,$textual_area,$mindless_mode,$comcode_dangerous,$comcode_dangerous_html));
list($tag_output,$comcode_dangerous,$comcode_dangerous_html,$white_space_area,$formatting_allowed,$in_separate_parse_section,$textual_area,$attribute_map,$status,$in_html,$in_semihtml,$pos,$in_code_tag)=_opened_tag($mindless_mode,$as_admin,$source_member,$attribute_map,$current_tag,$pos,$comcode_dangerous,$comcode_dangerous_html,$in_separate_parse_section,$in_html,$in_semihtml,$close,$len,$comcode);
if ($in_code_tag) $code_nest_stack=0;
$tag_output->attach($tag_raw);
}
elseif ($next=='=') $status=CCP_IN_TAG_BETWEEN_ATTRIBUTE_NAME_VALUE_RIGHT;
elseif ($next!=' ') $current_attribute_name.=strtolower($next);
else $status=CCP_IN_TAG_BETWEEN_ATTRIBUTE_NAME_VALUE_LEFT;
break;
case CCP_IN_TAG_BETWEEN_ATTRIBUTE_NAME_VALUE_LEFT:
if (($mindless_mode) && ($next!='[') && ($next!=']')) $tag_raw.=($next);
if ($next=='=') $status=CCP_IN_TAG_BETWEEN_ATTRIBUTE_NAME_VALUE_RIGHT;
elseif (trim($next)!='')
{
if (!$lax) return comcode_parse_error($preparse_mode,array('CCP_ATTRIBUTE_ERROR',$current_attribute_name,$current_tag),$pos,$comcode,$check_only);
if ($next=='[')
{
$status=CCP_IN_TAG_BETWEEN_ATTRIBUTES;
$pos--;
}
elseif ($next==']')
{
$status=CCP_IN_TAG_BETWEEN_ATTRIBUTES;
$pos--;
}
}
break;
case CCP_IN_TAG_BETWEEN_ATTRIBUTE_NAME_VALUE_RIGHT:
if (($mindless_mode) && ($next!='[') && ($next!=']')) $tag_raw.=($next);
if ($next=='[') // Can't actually occur though
{
if (!$lax) return comcode_parse_error($preparse_mode,array('CCP_TAG_OPEN_ANOMALY'),$pos,$comcode,$check_only);
$status=CCP_IN_TAG_BETWEEN_ATTRIBUTES;
$pos--;
}
elseif ($next==']') // Can't actually occur though
{
if (!$lax) return comcode_parse_error($preparse_mode,array('CCP_TAG_CLOSE_ANOMALY'),$pos,$comcode,$check_only);
$status=CCP_IN_TAG_BETWEEN_ATTRIBUTES;
$pos--;
}
elseif ((($next=='"')/* && (!$in_semihtml)*/) || (($in_semihtml) && (substr($comcode,$pos-1,6)=='"')))
{
if ($next!='"')
{
$pos+=5;
if ($mindless_mode) $tag_raw.='quot;';
}
$status=CCP_IN_TAG_ATTRIBUTE_VALUE;
$current_attribute_value='';
}
elseif ($next!='')
{
$status=CCP_IN_TAG_ATTRIBUTE_VALUE_NO_QUOTE;
$current_attribute_value=$next;
}
break;
case CCP_IN_TAG_ATTRIBUTE_VALUE_NO_QUOTE:
if (($mindless_mode) && ($next!=']')) $tag_raw.=($next);
if ($next==' ')
{
$status=CCP_IN_TAG_BETWEEN_ATTRIBUTES;
if ((isset($attribute_map[$current_attribute_name])) && (!$lax)) return comcode_parse_error($preparse_mode,array('CCP_DUPLICATE_ATTRIBUTES',$current_attribute_name,$current_tag),$pos,$comcode,$check_only);
$attribute_map[$current_attribute_name]=$current_attribute_value;
}
elseif ($next==']')
{
if ((isset($attribute_map[$current_attribute_name])) && (!$lax)) return comcode_parse_error($preparse_mode,array('CCP_DUPLICATE_ATTRIBUTES',$current_attribute_name,$current_tag),$pos,$comcode,$check_only);
$status=CCP_IN_TAG_BETWEEN_ATTRIBUTES;
$attribute_map[$current_attribute_name]=$current_attribute_value;
$pos--;
}
else
{
$current_attribute_value.=$next;
}
break;
case CCP_IN_TAG_ATTRIBUTE_VALUE:
if ($mindless_mode) $tag_raw.=($next);
if ((($next=='"')/* && (!$in_semihtml)*/) || (($in_semihtml) && (substr($comcode,$pos-1,6)=='"')))
{
if ($next!='"')
{
$pos+=5;
if ($mindless_mode) $tag_raw.='quot;';
}
$status=CCP_IN_TAG_BETWEEN_ATTRIBUTES;
if ((isset($attribute_map[$current_attribute_name])) && (!$lax)) return comcode_parse_error($preparse_mode,array('CCP_DUPLICATE_ATTRIBUTES',$current_attribute_name,$current_tag),$pos,$comcode,$check_only);
$attribute_map[$current_attribute_name]=$current_attribute_value;
}
else
{
if ($next=='\\')
{
if ($comcode[$pos]=='"')
{
if ($mindless_mode) $tag_raw.='"';
$current_attribute_value.='"';
++$pos;
} elseif (substr($comcode,$pos-1,6)=='"')
{
if ($mindless_mode) $tag_raw.='"';
$current_attribute_value.='"';
$pos+=6;
}
elseif ($comcode[$pos]=='\\')
{
if ($mindless_mode) $tag_raw.='\\';
$current_attribute_value.='\\';
++$pos;
} else $current_attribute_value.=$next;
} else $current_attribute_value.=$next;
}
break;
}
}
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($continuation);
$tag_output->attach($continuation);
$continuation='';
list($close_list,$list_indent)=_close_open_lists($list_indent,$list_type);
if ($GLOBALS['XSS_DETECT']) ocp_mark_as_escaped($close_list);
$tag_output->attach($close_list);
if (($status!=CCP_NO_MANS_LAND) || (count($tag_stack)!=0))
{
if (!$lax)
{
$stack_top=array_pop($tag_stack);
return comcode_parse_error($preparse_mode,array('CCP_BROKEN_END',is_null($stack_top)?$current_tag:$stack_top[0]),$pos,$comcode,$check_only);
} else
{
while (count($tag_stack)>0)
{
$_last=array_pop($tag_stack);
/*if ($_last[0]=='title') Not sure about this
{
$_structure_sweep=false;
break;
}*/
$embed_output=_do_tags_comcode($_last[0],$_last[1],$tag_output,$comcode_dangerous,$pass_id,$pos,$source_member,$as_admin,$connection,$comcode,$wml,$structure_sweep,$semiparse_mode,NULL,NULL,$in_semihtml,$is_all_semihtml);
$in_code_tag=false;
$white_space_area=$_last[3];
$in_separate_parse_section=$_last[4];
$formatting_allowed=$_last[5];
$textual_area=$_last[6];
$tag_output=$_last[2];
$tag_output->attach($embed_output);
$mindless_mode=$_last[7];
$comcode_dangerous=$_last[8];
$comcode_dangerous_html=$_last[9];
}
}
}
// $tag_output->left_attach('<div class="xhtml_validator_off">');
// $tag_output->attach('</div>');
return $tag_output;
}
boolean in_tag_stack(array tag_stack, array tags)
Find if any of some tags are in the stack.
Parameters…
| Name |
tag_stack |
| Description |
The tag stack |
| Type |
array |
| Name |
tags |
| Description |
The tags |
| Type |
array |
Returns…
| Description |
Whether one is present |
| Type |
boolean |
function in_tag_stack($tag_stack,$tags)
{
foreach ($tag_stack as $_temp)
{
if (in_array($_temp[0],$tags))
{
return true;
}
}
return false;
}
array detect_link(string comcode, integer pos)
Detect a link in some text.
Parameters…
| Name |
comcode |
| Description |
The text |
| Type |
string |
| Name |
pos |
| Description |
Search position |
| Type |
integer |
Returns…
| Description |
A pair: where the link ends in the text, the URL |
| Type |
array |
function detect_link(&$comcode,$pos)
{
$link_end_pos=strpos($comcode,' ',$pos-1);
$link_end_pos_2=strpos($comcode,chr(10),$pos-1);
$link_end_pos_3=strpos($comcode,'[',$pos-1);
$link_end_pos_4=strpos($comcode,')',$pos-1);
$link_end_pos_5=strpos($comcode,'"',$pos-1);
$link_end_pos_6=strpos($comcode,'>',$pos-1);
$link_end_pos_7=strpos($comcode,'<',$pos-1);
$link_end_pos_8=strpos($comcode,'.'.chr(10),$pos-1);
$link_end_pos_9=strpos($comcode,',',$pos-1);
if (($link_end_pos_2!==false) && (($link_end_pos===false) || ($link_end_pos_2<$link_end_pos))) $link_end_pos=$link_end_pos_2;
if (($link_end_pos_3!==false) && (($link_end_pos===false) || ($link_end_pos_3<$link_end_pos))) $link_end_pos=$link_end_pos_3;
if (($link_end_pos_4!==false) && (($link_end_pos===false) || ($link_end_pos_4<$link_end_pos))) $link_end_pos=$link_end_pos_4;
if (($link_end_pos_5!==false) && (($link_end_pos===false) || ($link_end_pos_5<$link_end_pos))) $link_end_pos=$link_end_pos_5;
if (($link_end_pos_6!==false) && (($link_end_pos===false) || ($link_end_pos_6<$link_end_pos))) $link_end_pos=$link_end_pos_6;
if (($link_end_pos_7!==false) && (($link_end_pos===false) || ($link_end_pos_7<$link_end_pos))) $link_end_pos=$link_end_pos_7;
if (($link_end_pos_8!==false) && (($link_end_pos===false) || ($link_end_pos_8<$link_end_pos))) $link_end_pos=$link_end_pos_8;
if (($link_end_pos_9!==false) && (($link_end_pos===false) || ($link_end_pos_9<$link_end_pos))) $link_end_pos=$link_end_pos_9;
if ($link_end_pos===false) $link_end_pos=strlen($comcode);
$auto_link=preg_replace('#keep_session=\d*#','filtered=1',substr($comcode,$pos-1,$link_end_pos-$pos+1));
return array($link_end_pos,$auto_link);
}
array _opened_tag(boolean mindless_mode, boolean as_admin, MEMBER source_member, array attribute_map, string current_tag, integer pos, boolean comcode_dangerous, boolean comcode_dangerous_html, boolean in_separate_parse_section, boolean in_html, boolean in_semihtml, boolean close, integer len, LONG_TEXT comcode)
Helper function for setting up and juggling variables after reaching a new Comcode tag.
Parameters…
| Name |
mindless_mode |
| Description |
Whether we are not considering parsing properly. |
| Type |
boolean |
| Name |
as_admin |
| Description |
Whether to explicitly execute this with admin rights. There are a few rare situations where this should be done, for data you know didn't come from a member, but is being evaluated by one. |
| Type |
boolean |
| Name |
source_member |
| Description |
The member the evaluation is running as. This is a security issue, and you should only run as an administrator if you have considered where the comcode came from carefully |
| Type |
MEMBER |
| Name |
attribute_map |
| Description |
The attribute map of the tag |
| Type |
array |
| Name |
current_tag |
| Description |
The identifier for the tag |
| Type |
string |
| Name |
pos |
| Description |
The offset of the tag in the Comcode |
| Type |
integer |
| Name |
comcode_dangerous |
| Description |
Whether the parser allows dangerous Comcode |
| Type |
boolean |
| Name |
comcode_dangerous_html |
| Description |
Whether the parser allows dangerous HTML |
| Type |
boolean |
| Name |
in_separate_parse_section |
| Description |
Whether the parser is/was in a separate parse section (e.g. a 'code' tag) |
| Type |
boolean |
| Name |
in_html |
| Description |
Whether the parser is/was in an HTML region |
| Type |
boolean |
| Name |
in_semihtml |
| Description |
Whether the parser is/was in a Semi-HTML region |
| Type |
boolean |
| Name |
close |
| Description |
Whether the tag is a closing tag |
| Type |
boolean |
| Name |
len |
| Description |
The length of the Comcode |
| Type |
integer |
| Name |
comcode |
| Description |
The Comcode being parsed |
| Type |
LONG_TEXT |
Returns…
| Description |
A tuple of new parser settings. |
| Type |
array |
function _opened_tag($mindless_mode,$as_admin,$source_member,$attribute_map,$current_tag,$pos,$comcode_dangerous,$comcode_dangerous_html,$in_separate_parse_section,$in_html,$in_semihtml,$close,&$len,&$comcode)
{
global $BLOCK_TAGS,$TEXTUAL_TAGS,$CODE_TAGS;
$block_tag=isset($BLOCK_TAGS[$current_tag]);
if (($block_tag) && ($pos<$len) && ($comcode[$pos]==chr(10)))
{
++$pos;
global $NUM_LINES;
++$NUM_LINES;
}
$tag_output=new ocp_tempcode();
$textual_area=isset($TEXTUAL_TAGS[$current_tag]);
$white_space_area=$textual_area;
if (((($current_tag=='code') || ($current_tag=='codebox')) && (isset($attribute_map['param'])) && ((strtolower($attribute_map['param'])=='php') || (file_exists(get_file_base().'/sources/geshi/'.filter_naughty(strtolower($attribute_map['param'])).'.php')) || (file_exists(get_file_base().'/sources_custom/geshi/'.filter_naughty($attribute_map['param']).'.php')))) || ($current_tag=='php') || ($current_tag=='attachment') || ($current_tag=='attachment2') || ($current_tag=='attachment_safe') || ($current_tag=='menu'))
{
$in_separate_parse_section=true;
} else
{
// Code tags are white space area, but not textual area
if (isset($CODE_TAGS[$current_tag])) $white_space_area=true;
}
$in_code_tag=isset($CODE_TAGS[$current_tag]);
$attribute_map=array();
$formatting_allowed=(($textual_area?1:0) & ($block_tag?1:0))!=0;
// if (in_array($current_tag,$BLOCK_TAGS)) $just_new_line=true;
if ($current_tag=='html') $in_html=!$close;
elseif ($current_tag=='semihtml') $in_semihtml=!$close;
$status=CCP_NO_MANS_LAND;
if (($current_tag=='html') || ($current_tag=='semihtml')) // New state meaning we need to filter the contents
{
if (($in_html) || ($in_semihtml))
{
filter_html($as_admin,$source_member,$pos,$len,$comcode,$in_html,$in_semihtml);
}
}
if ($mindless_mode)
{
$white_space_area=true;
$in_separate_parse_section=false;
}
if ($current_tag=='quote')
{
$comcode_dangerous=false;
$comcode_dangerous_html=false;
}
return array($tag_output,$comcode_dangerous,$comcode_dangerous_html,$white_space_area,$formatting_allowed,$in_separate_parse_section,$textual_area,$attribute_map,$status,$in_html,$in_semihtml,$pos,$in_code_tag);
}
void filter_html(boolean as_admin, MEMBER source_member, integer pos, integer len, LONG_TEXT comcode, boolean in_html, boolean in_semihtml)
Filter HTML for safety.
Parameters…
| Name |
as_admin |
| Description |
Whether to explicitly execute this with admin rights. There are a few rare situations where this should be done, for data you know didn't come from a member, but is being evaluated by one. |
| Type |
boolean |
| Name |
source_member |
| Description |
The member the evaluation is running as. This is a security issue, and you should only run as an administrator if you have considered where the comcode came from carefully |
| Type |
MEMBER |
| Name |
pos |
| Description |
The offset of the tag in the Comcode |
| Type |
integer |
| Name |
len |
| Description |
The length of the Comcode |
| Type |
integer |
| Name |
comcode |
| Description |
The Comcode being parsed |
| Type |
LONG_TEXT |
| Name |
in_html |
| Description |
Whether the parser is/was in an HTML region |
| Type |
boolean |
| Name |
in_semihtml |
| Description |
Whether the parser is/was in a Semi-HTML region |
| Type |
boolean |
(No return value)
function filter_html($as_admin,$source_member,$pos,&$len,&$comcode,$in_html,$in_semihtml)
{
if ((!$as_admin) && (!has_specific_permission($source_member,'use_very_dangerous_comcode')))
{
global $POTENTIAL_JS_NAUGHTY_ARRAY;
$comcode=preg_replace('#(\\\\)+(\[/(html|semihtml)\])#','\2',$comcode); // Stops sneaky trying to trick the end of the HTML tag to hack this function
if (($in_html) && ($in_semihtml)) $ahead_end=max(strpos($comcode,'[/html]',$pos),strpos($comcode,'[/semihtml]',$pos));
elseif ($in_html) $ahead_end=strpos($comcode,'[/html]',$pos);
elseif ($in_semihtml) $ahead_end=strpos($comcode,'[/semihtml]',$pos);
else $ahead_end=false;
if ($ahead_end===false) $ahead_end=strlen($comcode);
$ahead=substr($comcode,$pos,$ahead_end-$pos);
// Null vector
$ahead=str_replace(chr(0),'',$ahead);
// Comment vector
$old_ahead='';
do
{
$old_ahead=$ahead;
$ahead=preg_replace('#/\*.*\*/#Us','',$ahead);
}
while ($old_ahead!=$ahead);
// Entity vector
$matches=array();
do
{
$old_ahead=$ahead;
$count=preg_match_all('#&\#(\d+)#i',$ahead,$matches); // No one would use this for an html tag unless it was malicious. The ASCII could have been put in directly.
for ($i=0;$i<$count;$i++)
{
$matched_entity=intval($matches[1][$i]);
if (($matched_entity<127) && (array_key_exists(chr($matched_entity),$POTENTIAL_JS_NAUGHTY_ARRAY)))
{
if ($matched_entity==0) $matched_entity=ord(' ');
$ahead=str_replace($matches[0][$i].';',chr($matched_entity),$ahead);
$ahead=str_replace($matches[0][$i],chr($matched_entity),$ahead);
}
}
$count=preg_match_all('#&\#x([\da-f]+)#i',$ahead,$matches); // No one would use this for an html tag unless it was malicious. The ASCII could have been put in directly.
for ($i=0;$i<$count;$i++)
{
$matched_entity=intval(base_convert($matches[1][$i],16,10));
if (($matched_entity<127) && (array_key_exists(chr($matched_entity),$POTENTIAL_JS_NAUGHTY_ARRAY)))
{
if ($matched_entity==0) $matched_entity=ord(' ');
$ahead=str_replace($matches[0][$i].';',chr($matched_entity),$ahead);
$ahead=str_replace($matches[0][$i],chr($matched_entity),$ahead);
}
}
}
while ($old_ahead!=$ahead);
// Tag vectors
$ahead=preg_replace('#\<(noscript|script|link|style|meta|iframe|frame|object|embed|applet|html|xml)#i','<span',$ahead);
$ahead=preg_replace('#\<(/noscript|/script|/link|/style|/meta|/iframe|/frame|/object|/embed|/applet|/html|/xml)#i','</span',$ahead);
// CSS attack vectors
$ahead=preg_replace('#\\\\(\d+)#i','${1}',$ahead); // CSS escaping
$ahead=preg_replace('#e\s*(x\s*p\s*r\s*e\s*s\s*s\s*i\s*o\s*n\()#i','é${1}',$ahead);
$ahead=preg_replace('#b\s*(e\s*h\s*a\s*v\s*i\s*o\s*r\s*\()#i','ß${1}',$ahead);
$ahead=preg_replace('#b\s*(i\s*n\s*d\s*i\s*n\s*g\s*\()#i','ß${1}',$ahead);
// Script-URL vectors
$ahead=preg_replace('#((j[\\\\\s]*a[\\\\\s]*v[\\\\\s]*a[\\\\\s]*|v[\\\\\s]*b[\\\\\s]*)s[\\\\\s]*c[\\\\\s]*r[\\\\\s]*i[\\\\\s]*p[\\\\\s]*t[\\\\\s]*):#i','${1};',$ahead);
// Event vectors
$ahead=preg_replace('#\son#i',' on',$ahead);
// Check tag balancing (we don't want to allow partial tags to compound together against separately checked chunks)
$len=strlen($ahead);
$depth=0;
for ($i=0;$i<$len;$i++)
{
$at=$ahead[$i];
if ($at=='<')
{
$depth++;
} elseif ($at=='>')
{
$depth--;
}
if ($depth<0) break;
}
if ($depth>=1)
{
$ahead.='">'; // Ugly way to make sure all is closed off
}
// Tidy up
$comcode=substr($comcode,0,$pos).$ahead.substr($comcode,$ahead_end);
$len=strlen($comcode);
}
}
array _close_open_lists(integer list_indent, string list_type)
Get HTML to close any open lists.
Parameters…
| Name |
list_indent |
| Description |
The depth level of lists that we need to close |
| Type |
integer |
| Name |
list_type |
| Description |
List-type code |
| Type |
string |
| Values restricted to |
ul a 1 |
Returns…
| Description |
The output needed to close the lists, and the new list indentation (always zero). Done like this so we can use 'list' to set both at once in the main parser. |
| Type |
array |
function _close_open_lists($list_indent,$list_type)
{
$tag_output='';
for ($i=0;$i<$list_indent;++$i) // Close any lists that exist
{
$tag_output.='</li>';
$temp_tpl=($list_type=='ul')?'</ul>':'</ol>';
$tag_output.=$temp_tpl;
}
$list_indent=0;
return array($tag_output,$list_indent);
}
array parse_single_comcode_tag(string data, string tag)
Parse a single tag. For use separately, not used by main parser.
Parameters…
| Name |
data |
| Description |
The data being parsed |
| Type |
string |
| Name |
tag |
| Description |
The tag we're expecting to see here / a regexp |
| Default value |
\w+ |
| Type |
string |
Returns…
| Description |
A map of parsed attributes |
| Type |
array |
function parse_single_comcode_tag($data,$tag='\w+')
{
$attributes=array();
$_attributes=preg_replace('#^\['.$tag.'\s*#','',preg_replace('#\[/'.$tag.'\]$#Us','',$data));
if (($_attributes!='') && ($_attributes!=$data/*if it matched*/))
{
if (substr($_attributes,0,1)=='=') $_attributes='param'.$_attributes;
$current_attribute='';
$current_value='';
$in_attribute=false;
for ($i=0;$i<strlen($_attributes);$i++)
{
$next=$_attributes[$i];
if (!$in_attribute)
{
if ($next=='=')
{
$in_attribute=true;
if ($_attributes[$i+1]=='"') $i++; // Skip opening "
$current_value='';
} elseif ($next==']')
{
$attributes['']=substr($_attributes,$i+1);
break;
} else
{
$current_attribute.=$next;
}
} else
{
if ($next=='"')
{
$in_attribute=false;
if (($i!=strlen($_attributes)-1) && ($_attributes[$i+1]==' ')) $i++; // Skip space
$attributes[$current_attribute]=str_replace(array('\\[','\\]','\\{','\\}','\\\''),array('[',']','{','}','\''),$current_value);
$current_attribute='';
} else
{
$current_value.=$next;
}
}
}
}
return $attributes;
}
Tutorial - Adding a Comcode Tag
To add comcode tags, you will need some templates, and some code:
- Open up root/sources/comcode.php in an editor.
- Find line 44
- In this tutorial, we are going to be adding a sample tag: align, so change line 47 from:
Code (php)
'quote'=>1,'block'=>1,'html'=>1);
To:
Code (php)
'quote'=>1,'block'=>1,'html'=>1,'align'=>1);
4) Now, go to line 627, which should look like this:
5) After this line, enter the following code:
Code (php)
case 'align':
switch ($attributes['param'])
{
case 'center':
$align='center';
break;
case 'right':
$align='right';
break;
default:
$align='left';
break;
}
$temp_tpl=do_template
('COMCODE_ALIGN',array('ALIGN'=>$align,'CONTENT'=>$embed));
break;
- Now that is done, we need to add the template, so create a new file entitled 'COMCODE_ALIGN.tpl' in your root/themes/themename/templates_custom/ folder.
- Open up this file in an editor, and insert the following:
Code (php)
<div align="{ALIGN}">
{CONTENT}
</div>
8) Create a new comcode page, and test your new custom comcode tag!
At the time of writing, the following ocPortal attributes support comcode:
- authors.skills
- authors.description
- banners.caption
- cached_comcode_pages.string_index
- catalogue_entry_field_values_* (if it is encoding text)
- catalogues.c_description
- catalogue_categories.cc_description
- chargelog.reason
- download_categories.description
- download_downloads.comments
- download_downloads.description
- galleries.description
- gifts.reason
- images.comments
- iotd.caption
- news.news
- news.news_article
- news.title
- poll.option1
- poll.option2
- poll.option3
- poll.option4
- poll.option5
- poll.question
- seedy_pages.description
- seedy_posts.the_message
- text.the_message
The following ocPortal input fields (that aren't attributes) support comcode:
- chat messages
- comment input: message, title
- newsletter input: message, title
0 reviews: Unrated (average)
There have been no comments yet