[ Index ] |
PHP Cross Reference of BBPress |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * bbPress BBCode Parser 5 * 6 * @package bbPress 7 * @subpackage Administration 8 */ 9 10 /* 11 This is a compressed copy of NBBC. Do not edit! 12 13 Copyright (c) 2008-9, the Phantom Inker. All rights reserved. 14 Portions Copyright (c) 2004-2008 AddedBytes.com 15 16 Redistribution and use in source and binary forms, with or without 17 modification, are permitted provided that the following conditions 18 are met: 19 20 * Redistributions of source code must retain the above copyright 21 notice, this list of conditions and the following disclaimer. 22 23 * Redistributions in binary form must reproduce the above copyright 24 notice, this list of conditions and the following disclaimer in 25 the documentation and/or other materials provided with the 26 distribution. 27 28 THIS SOFTWARE IS PROVIDED BY THE PHANTOM INKER "AS IS" AND ANY EXPRESS 29 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 30 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 31 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 32 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 35 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 36 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 37 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 38 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 */ 40 41 define("BBCODE_VERSION", "1.4.5"); 42 define("BBCODE_RELEASE", "2010-09-17"); 43 define("BBCODE_VERBATIM", 2); 44 define("BBCODE_REQUIRED", 1); 45 define("BBCODE_OPTIONAL", 0); 46 define("BBCODE_PROHIBIT", -1); 47 define("BBCODE_CHECK", 1); 48 define("BBCODE_OUTPUT", 2); 49 define("BBCODE_ENDTAG", 5); 50 define("BBCODE_TAG", 4); 51 define("BBCODE_TEXT", 3); 52 define("BBCODE_NL", 2); 53 define("BBCODE_WS", 1); 54 define("BBCODE_EOI", 0); 55 define("BBCODE_LEXSTATE_TEXT", 0); 56 define("BBCODE_LEXSTATE_TAG", 1); 57 define("BBCODE_MODE_SIMPLE", 0); 58 define("BBCODE_MODE_CALLBACK", 1); 59 define("BBCODE_MODE_INTERNAL", 2); 60 define("BBCODE_MODE_LIBRARY", 3); 61 define("BBCODE_MODE_ENHANCED", 4); 62 define("BBCODE_STACK_TOKEN", 0); 63 define("BBCODE_STACK_TEXT", 1); 64 define("BBCODE_STACK_TAG", 2); 65 define("BBCODE_STACK_CLASS", 3); 66 if (!function_exists('str_split')) { 67 function str_split($string, $split_length = 1) { 68 $array = explode("\r\n", chunk_split($string, $split_length)); 69 array_pop($array); 70 return $array; 71 } 72 } 73 $BBCode_SourceDir = dirname(__FILE__); 74 75 class BBCodeLexer { 76 var $token; 77 var $text; 78 var $tag; 79 var $state; 80 var $input; 81 var $ptr; 82 var $unget; 83 var $verbatim; 84 var $debug; 85 var $tagmarker; 86 var $end_tagmarker; 87 var $pat_main; 88 var $pat_comment; 89 var $pat_comment2; 90 var $pat_wiki; 91 function __construct($string, $tagmarker = '[') { 92 $regex_beginmarkers = Array( '[' => '\[', '<' => '<', '{' => '\{', '(' => '\(' ); 93 $regex_endmarkers = Array( '[' => '\]', '<' => '>', '{' => '\}', '(' => '\)' ); 94 $endmarkers = Array( '[' => ']', '<' => '>', '{' => '}', '(' => ')' ); 95 if (!isset($regex_endmarkers[$tagmarker])) $tagmarker = '['; 96 $e = $regex_endmarkers[$tagmarker]; 97 $b = $regex_beginmarkers[$tagmarker]; 98 $this->tagmarker = $tagmarker; 99 $this->end_tagmarker = $endmarkers[$tagmarker]; 100 $this->pat_main = "/( " 101 . "{$b}" 102 . "(?! -- | ' | !-- | {$b}{$b} )" 103 . "(?: [^\\n\\r{$b}{$e}] | \\\" [^\\\"\\n\\r]* \\\" | \\' [^\\'\\n\\r]* \\' )*" 104 . "{$e}" 105 . "| {$b}{$b} (?: [^{$e}\\r\\n] | {$e}[^{$e}\\r\\n] )* {$e}{$e}" 106 . "| {$b} (?: -- | ' ) (?: [^{$e}\\n\\r]* ) {$e}" 107 . "| {$b}!-- (?: [^-] | -[^-] | --[^{$e}] )* --{$e}" 108 . "| -----+" 109 . "| \\x0D\\x0A | \\x0A\\x0D | \\x0D | \\x0A" 110 . "| [\\x00-\\x09\\x0B-\\x0C\\x0E-\\x20]+(?=[\\x0D\\x0A{$b}]|-----|$)" 111 . "| (?<=[\\x0D\\x0A{$e}]|-----|^)[\\x00-\\x09\\x0B-\\x0C\\x0E-\\x20]+" 112 . " )/Dx"; 113 $this->input = preg_split($this->pat_main, $string, -1, PREG_SPLIT_DELIM_CAPTURE); 114 $this->pat_comment = "/^ {$b} (?: -- | ' ) /Dx"; 115 $this->pat_comment2 = "/^ {$b}!-- (?: [^-] | -[^-] | --[^{$e}] )* --{$e} $/Dx"; 116 $this->pat_wiki = "/^ {$b}{$b} ([^\\|]*) (?:\\|(.*))? {$e}{$e} $/Dx"; 117 $this->ptr = 0; 118 $this->unget = false; 119 $this->state = BBCODE_LEXSTATE_TEXT; 120 $this->verbatim = false; 121 $this->token = BBCODE_EOI; 122 $this->tag = false; 123 $this->text = ""; 124 } 125 function BBCodeLexer($string, $tagmarker = '[') { 126 $this->__construct($string, $tagmarker); 127 } 128 function GuessTextLength() { 129 $length = 0; 130 $ptr = 0; 131 $state = BBCODE_LEXSTATE_TEXT; 132 while ($ptr < count($this->input)) { 133 $text = $this->input[$ptr++]; 134 if ($state == BBCODE_LEXSTATE_TEXT) { 135 $state = BBCODE_LEXSTATE_TAG; 136 $length += strlen($text); 137 } 138 else { 139 switch (ord(substr($this->text, 0, 1))) { 140 case 10: 141 case 13: 142 $state = BBCODE_LEXSTATE_TEXT; 143 $length++; 144 break; 145 default: 146 $state = BBCODE_LEXSTATE_TEXT; 147 $length += strlen($text); 148 break; 149 case 40: 150 case 60: 151 case 91: 152 case 123: 153 $state = BBCODE_LEXSTATE_TEXT; 154 break; 155 } 156 } 157 } 158 return $length; 159 } 160 function NextToken() { 161 if ($this->unget) { 162 $this->unget = false; 163 return $this->token; 164 } 165 while (true) { 166 if ($this->ptr >= count($this->input)) { 167 $this->text = ""; 168 $this->tag = false; 169 return $this->token = BBCODE_EOI; 170 } 171 $this->text = preg_replace("/[\\x00-\\x08\\x0B-\\x0C\\x0E-\\x1F]/", "", 172 $this->input[$this->ptr++]); 173 if ($this->verbatim) { 174 $this->tag = false; 175 if ($this->state == BBCODE_LEXSTATE_TEXT) { 176 $this->state = BBCODE_LEXSTATE_TAG; 177 $token_type = BBCODE_TEXT; 178 } 179 else { 180 $this->state = BBCODE_LEXSTATE_TEXT; 181 switch (ord(substr($this->text, 0, 1))) { 182 case 10: 183 case 13: 184 $token_type = BBCODE_NL; 185 break; 186 default: 187 $token_type = BBCODE_WS; 188 break; 189 case 45: 190 case 40: 191 case 60: 192 case 91: 193 case 123: 194 $token_type = BBCODE_TEXT; 195 break; 196 } 197 } 198 if (strlen($this->text) > 0) 199 return $this->token = $token_type; 200 } 201 else if ($this->state == BBCODE_LEXSTATE_TEXT) { 202 $this->state = BBCODE_LEXSTATE_TAG; 203 $this->tag = false; 204 if (strlen($this->text) > 0) 205 return $this->token = BBCODE_TEXT; 206 } 207 else { 208 switch (ord(substr($this->text, 0, 1))) { 209 case 10: 210 case 13: 211 $this->tag = false; 212 $this->state = BBCODE_LEXSTATE_TEXT; 213 return $this->token = BBCODE_NL; 214 case 45: 215 if (preg_match("/^-----/", $this->text)) { 216 $this->tag = Array('_name' => 'rule', '_endtag' => false, '_default' => ''); 217 $this->state = BBCODE_LEXSTATE_TEXT; 218 return $this->token = BBCODE_TAG; 219 } 220 else { 221 $this->tag = false; 222 $this->state = BBCODE_LEXSTATE_TEXT; 223 if (strlen($this->text) > 0) 224 return $this->token = BBCODE_TEXT; 225 continue 2; 226 } 227 default: 228 $this->tag = false; 229 $this->state = BBCODE_LEXSTATE_TEXT; 230 return $this->token = BBCODE_WS; 231 case 40: 232 case 60: 233 case 91: 234 case 123: 235 if (preg_match($this->pat_comment, $this->text)) { 236 $this->state = BBCODE_LEXSTATE_TEXT; 237 continue 2; 238 } 239 if (preg_match($this->pat_comment2, $this->text)) { 240 $this->state = BBCODE_LEXSTATE_TEXT; 241 continue 2; 242 } 243 if (preg_match($this->pat_wiki, $this->text, $matches)) { 244 $this->tag = Array('_name' => 'wiki', '_endtag' => false, 245 '_default' => @$matches[1], 'title' => @$matches[2]); 246 $this->state = BBCODE_LEXSTATE_TEXT; 247 return $this->token = BBCODE_TAG; 248 } 249 $this->tag = $this->Internal_DecodeTag($this->text); 250 $this->state = BBCODE_LEXSTATE_TEXT; 251 return $this->token = ($this->tag['_end'] ? BBCODE_ENDTAG : BBCODE_TAG); 252 } 253 } 254 } 255 } 256 function UngetToken() { 257 if ($this->token !== BBCODE_EOI) 258 $this->unget = true; 259 } 260 function PeekToken() { 261 $result = $this->NextToken(); 262 if ($this->token !== BBCODE_EOI) 263 $this->unget = true; 264 return $result; 265 } 266 function SaveState() { 267 return Array( 268 'token' => $this->token, 269 'text' => $this->text, 270 'tag' => $this->tag, 271 'state' => $this->state, 272 'input' => $this->input, 273 'ptr' => $this->ptr, 274 'unget' => $this->unget, 275 'verbatim' => $this->verbatim 276 ); 277 } 278 function RestoreState($state) { 279 if (!is_array($state)) return; 280 $this->token = @$state['token']; 281 $this->text = @$state['text']; 282 $this->tag = @$state['tag']; 283 $this->state = @$state['state']; 284 $this->input = @$state['input']; 285 $this->ptr = @$state['ptr']; 286 $this->unget = @$state['unget']; 287 $this->verbatim = @$state['verbatim']; 288 } 289 function Internal_StripQuotes($string) { 290 if (preg_match("/^\\\"(.*)\\\"$/", $string, $matches)) 291 return $matches[1]; 292 else if (preg_match("/^\\'(.*)\\'$/", $string, $matches)) 293 return $matches[1]; 294 else return $string; 295 } 296 function Internal_ClassifyPiece($ptr, $pieces) { 297 if ($ptr >= count($pieces)) return -1; 298 $piece = $pieces[$ptr]; 299 if ($piece == '=') return '='; 300 else if (preg_match("/^[\\'\\\"]/", $piece)) return '"'; 301 else if (preg_match("/^[\\x00-\\x20]+$/", $piece)) return ' '; 302 else return 'A'; 303 } 304 function Internal_DecodeTag($tag) { 305 $result = Array('_tag' => $tag, '_endtag' => '', '_name' => '', 306 '_hasend' => false, '_end' => false, '_default' => false); 307 $tag = substr($tag, 1, strlen($tag)-2); 308 $ch = ord(substr($tag, 0, 1)); 309 if ($ch >= 0 && $ch <= 32) return $result; 310 $pieces = preg_split("/(\\\"[^\\\"]+\\\"|\\'[^\\']+\\'|=|[\\x00-\\x20]+)/", 311 $tag, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY); 312 $ptr = 0; 313 if (count($pieces) < 1) return $result; 314 if (@substr($pieces[$ptr], 0, 1) == '/') { 315 $result['_name'] = strtolower(substr($pieces[$ptr++], 1)); 316 $result['_end'] = true; 317 } 318 else { 319 $result['_name'] = strtolower($pieces[$ptr++]); 320 $result['_end'] = false; 321 } 322 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ') 323 $ptr++; 324 $params = Array(); 325 if ($type != '=') { 326 $result['_default'] = false; 327 $params[] = Array('key' => '', 'value' => ''); 328 } 329 else { 330 $ptr++; 331 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ') 332 $ptr++; 333 if ($type == "\"") 334 $value = $this->Internal_StripQuotes($pieces[$ptr++]); 335 else { 336 $after_space = false; 337 $start = $ptr; 338 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) != -1) { 339 if ($type == ' ') $after_space = true; 340 if ($type == '=' && $after_space) break; 341 $ptr++; 342 } 343 if ($type == -1) $ptr--; 344 if ($type == '=') { 345 $ptr--; 346 while ($ptr > $start && $this->Internal_ClassifyPiece($ptr, $pieces) == ' ') 347 $ptr--; 348 while ($ptr > $start && $this->Internal_ClassifyPiece($ptr, $pieces) != ' ') 349 $ptr--; 350 } 351 $value = ""; 352 for (; $start <= $ptr; $start++) { 353 if ($this->Internal_ClassifyPiece($start, $pieces) == ' ') 354 $value .= " "; 355 else $value .= $this->Internal_StripQuotes($pieces[$start]); 356 } 357 $value = trim($value); 358 $ptr++; 359 } 360 $result['_default'] = $value; 361 $params[] = Array('key' => '', 'value' => $value); 362 } 363 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) != -1) { 364 while ($type == ' ') { 365 $ptr++; 366 $type = $this->Internal_ClassifyPiece($ptr, $pieces); 367 } 368 if ($type == 'A' || $type == '"') 369 $key = strtolower($this->Internal_StripQuotes(@$pieces[$ptr++])); 370 else if ($type == '=') { 371 $ptr++; 372 continue; 373 } 374 else if ($type == -1) break; 375 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ') 376 $ptr++; 377 if ($type != '=') 378 $value = $this->Internal_StripQuotes($key); 379 else { 380 $ptr++; 381 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ') 382 $ptr++; 383 if ($type == '"') { 384 $value = $this->Internal_StripQuotes($pieces[$ptr++]); 385 } 386 else if ($type != -1) { 387 $value = $pieces[$ptr++]; 388 while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) != -1 389 && $type != ' ') 390 $value .= $pieces[$ptr++]; 391 } 392 else $value = ""; 393 } 394 if (substr($key, 0, 1) != '_') 395 $result[$key] = $value; 396 $params[] = Array('key' => $key, 'value' => $value); 397 } 398 $result['_params'] = $params; 399 return $result; 400 } 401 } 402 403 class BBCodeLibrary { 404 var $default_smileys = Array( 405 ':)' => 'smile.gif', ':-)' => 'smile.gif', 406 '=)' => 'smile.gif', '=-)' => 'smile.gif', 407 ':(' => 'frown.gif', ':-(' => 'frown.gif', 408 '=(' => 'frown.gif', '=-(' => 'frown.gif', 409 ':D' => 'bigsmile.gif', ':-D' => 'bigsmile.gif', 410 '=D' => 'bigsmile.gif', '=-D' => 'bigsmile.gif', 411 '>:('=> 'angry.gif', '>:-('=> 'angry.gif', 412 '>=('=> 'angry.gif', '>=-('=> 'angry.gif', 413 'D:' => 'angry.gif', 'D-:' => 'angry.gif', 414 'D=' => 'angry.gif', 'D-=' => 'angry.gif', 415 '>:)'=> 'evil.gif', '>:-)'=> 'evil.gif', 416 '>=)'=> 'evil.gif', '>=-)'=> 'evil.gif', 417 '>:D'=> 'evil.gif', '>:-D'=> 'evil.gif', 418 '>=D'=> 'evil.gif', '>=-D'=> 'evil.gif', 419 '>;)'=> 'sneaky.gif', '>;-)'=> 'sneaky.gif', 420 '>;D'=> 'sneaky.gif', '>;-D'=> 'sneaky.gif', 421 'O:)' => 'saint.gif', 'O:-)' => 'saint.gif', 422 'O=)' => 'saint.gif', 'O=-)' => 'saint.gif', 423 ':O' => 'surprise.gif', ':-O' => 'surprise.gif', 424 '=O' => 'surprise.gif', '=-O' => 'surprise.gif', 425 ':?' => 'confuse.gif', ':-?' => 'confuse.gif', 426 '=?' => 'confuse.gif', '=-?' => 'confuse.gif', 427 ':s' => 'worry.gif', ':-S' => 'worry.gif', 428 '=s' => 'worry.gif', '=-S' => 'worry.gif', 429 ':|' => 'neutral.gif', ':-|' => 'neutral.gif', 430 '=|' => 'neutral.gif', '=-|' => 'neutral.gif', 431 ':I' => 'neutral.gif', ':-I' => 'neutral.gif', 432 '=I' => 'neutral.gif', '=-I' => 'neutral.gif', 433 ':/' => 'irritated.gif', ':-/' => 'irritated.gif', 434 '=/' => 'irritated.gif', '=-/' => 'irritated.gif', 435 ':\\' => 'irritated.gif', ':-\\' => 'irritated.gif', 436 '=\\' => 'irritated.gif', '=-\\' => 'irritated.gif', 437 ':P' => 'tongue.gif', ':-P' => 'tongue.gif', 438 '=P' => 'tongue.gif', '=-P' => 'tongue.gif', 439 'X-P' => 'tongue.gif', 440 '8)' => 'bigeyes.gif', '8-)' => 'bigeyes.gif', 441 'B)' => 'cool.gif', 'B-)' => 'cool.gif', 442 ';)' => 'wink.gif', ';-)' => 'wink.gif', 443 ';D' => 'bigwink.gif', ';-D' => 'bigwink.gif', 444 '^_^'=> 'anime.gif', '^^;' => 'sweatdrop.gif', 445 '>_>'=> 'lookright.gif', '>.>' => 'lookright.gif', 446 '<_<'=> 'lookleft.gif', '<.<' => 'lookleft.gif', 447 'XD' => 'laugh.gif', 'X-D' => 'laugh.gif', 448 ';D' => 'bigwink.gif', ';-D' => 'bigwink.gif', 449 ':3' => 'smile3.gif', ':-3' => 'smile3.gif', 450 '=3' => 'smile3.gif', '=-3' => 'smile3.gif', 451 ';3' => 'wink3.gif', ';-3' => 'wink3.gif', 452 '<g>' => 'teeth.gif', '<G>' => 'teeth.gif', 453 'o.O' => 'boggle.gif', 'O.o' => 'boggle.gif', 454 ':blue:' => 'blue.gif', 455 ':zzz:' => 'sleepy.gif', 456 '<3' => 'heart.gif', 457 ':star:' => 'star.gif', 458 ); 459 var $default_tag_rules = Array( 460 'b' => Array( 461 'simple_start' => "<b>", 462 'simple_end' => "</b>", 463 'class' => 'inline', 464 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), 465 'plain_start' => "<b>", 466 'plain_end' => "</b>", 467 ), 468 'i' => Array( 469 'simple_start' => "<i>", 470 'simple_end' => "</i>", 471 'class' => 'inline', 472 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), 473 'plain_start' => "<i>", 474 'plain_end' => "</i>", 475 ), 476 'u' => Array( 477 'simple_start' => "<u>", 478 'simple_end' => "</u>", 479 'class' => 'inline', 480 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), 481 'plain_start' => "<u>", 482 'plain_end' => "</u>", 483 ), 484 's' => Array( 485 'simple_start' => "<strike>", 486 'simple_end' => "</strike>", 487 'class' => 'inline', 488 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), 489 'plain_start' => "<i>", 490 'plain_end' => "</i>", 491 ), 492 'font' => Array( 493 'mode' => BBCODE_MODE_LIBRARY, 494 'allow' => Array('_default' => '/^[a-zA-Z0-9._ -]+$/'), 495 'method' => 'DoFont', 496 'class' => 'inline', 497 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), 498 ), 499 'color' => Array( 500 'mode' => BBCODE_MODE_ENHANCED, 501 'allow' => Array('_default' => '/^#?[a-zA-Z0-9._ -]+$/'), 502 'template' => '<span style="color:{$_default/tw}">{$_content/v}</span>', 503 'class' => 'inline', 504 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), 505 ), 506 'size' => Array( 507 'mode' => BBCODE_MODE_LIBRARY, 508 'allow' => Array('_default' => '/^[0-9.]+$/D'), 509 'method' => 'DoSize', 510 'class' => 'inline', 511 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), 512 ), 513 'sup' => Array( 514 'simple_start' => "<sup>", 515 'simple_end' => "</sup>", 516 'class' => 'inline', 517 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), 518 ), 519 'sub' => Array( 520 'simple_start' => "<sub>", 521 'simple_end' => "</sub>", 522 'class' => 'inline', 523 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), 524 ), 525 'spoiler' => Array( 526 'simple_start' => "<span class=\"bbcode_spoiler\">", 527 'simple_end' => "</span>", 528 'class' => 'inline', 529 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), 530 ), 531 'acronym' => Array( 532 'mode' => BBCODE_MODE_ENHANCED, 533 'template' => '<span class="bbcode_acronym" title="{$_default/e}">{$_content/v}</span>', 534 'class' => 'inline', 535 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), 536 ), 537 'url' => Array( 538 'mode' => BBCODE_MODE_LIBRARY, 539 'method' => 'DoURL', 540 'class' => 'link', 541 'allow_in' => Array('listitem', 'block', 'columns', 'inline'), 542 'content' => BBCODE_REQUIRED, 543 'plain_start' => "<a href=\"{\$link}\">", 544 'plain_end' => "</a>", 545 'plain_content' => Array('_content', '_default'), 546 'plain_link' => Array('_default', '_content'), 547 ), 548 'email' => Array( 549 'mode' => BBCODE_MODE_LIBRARY, 550 'method' => 'DoEmail', 551 'class' => 'link', 552 'allow_in' => Array('listitem', 'block', 'columns', 'inline'), 553 'content' => BBCODE_REQUIRED, 554 'plain_start' => "<a href=\"mailto:{\$link}\">", 555 'plain_end' => "</a>", 556 'plain_content' => Array('_content', '_default'), 557 'plain_link' => Array('_default', '_content'), 558 ), 559 'wiki' => Array( 560 'mode' => BBCODE_MODE_LIBRARY, 561 'method' => "DoWiki", 562 'class' => 'link', 563 'allow_in' => Array('listitem', 'block', 'columns', 'inline'), 564 'end_tag' => BBCODE_PROHIBIT, 565 'content' => BBCODE_PROHIBIT, 566 'plain_start' => "<b>[", 567 'plain_end' => "]</b>", 568 'plain_content' => Array('title', '_default'), 569 'plain_link' => Array('_default', '_content'), 570 ), 571 'img' => Array( 572 'mode' => BBCODE_MODE_LIBRARY, 573 'method' => "DoImage", 574 'class' => 'image', 575 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), 576 'end_tag' => BBCODE_REQUIRED, 577 'content' => BBCODE_REQUIRED, 578 'plain_start' => "[image]", 579 'plain_content' => Array(), 580 ), 581 'rule' => Array( 582 'mode' => BBCODE_MODE_LIBRARY, 583 'method' => "DoRule", 584 'class' => 'block', 585 'allow_in' => Array('listitem', 'block', 'columns'), 586 'end_tag' => BBCODE_PROHIBIT, 587 'content' => BBCODE_PROHIBIT, 588 'before_tag' => "sns", 589 'after_tag' => "sns", 590 'plain_start' => "\n-----\n", 591 'plain_end' => "", 592 'plain_content' => Array(), 593 ), 594 'br' => Array( 595 'mode' => BBCODE_MODE_SIMPLE, 596 'simple_start' => "<br />\n", 597 'simple_end' => "", 598 'class' => 'inline', 599 'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'), 600 'end_tag' => BBCODE_PROHIBIT, 601 'content' => BBCODE_PROHIBIT, 602 'before_tag' => "s", 603 'after_tag' => "s", 604 'plain_start' => "\n", 605 'plain_end' => "", 606 'plain_content' => Array(), 607 ), 608 'left' => Array( 609 'simple_start' => "\n<div class=\"bbcode_left\" style=\"text-align:left\">\n", 610 'simple_end' => "\n</div>\n", 611 'allow_in' => Array('listitem', 'block', 'columns'), 612 'before_tag' => "sns", 613 'after_tag' => "sns", 614 'before_endtag' => "sns", 615 'after_endtag' => "sns", 616 'plain_start' => "\n", 617 'plain_end' => "\n", 618 ), 619 'right' => Array( 620 'simple_start' => "\n<div class=\"bbcode_right\" style=\"text-align:right\">\n", 621 'simple_end' => "\n</div>\n", 622 'allow_in' => Array('listitem', 'block', 'columns'), 623 'before_tag' => "sns", 624 'after_tag' => "sns", 625 'before_endtag' => "sns", 626 'after_endtag' => "sns", 627 'plain_start' => "\n", 628 'plain_end' => "\n", 629 ), 630 'center' => Array( 631 'simple_start' => "\n<div class=\"bbcode_center\" style=\"text-align:center\">\n", 632 'simple_end' => "\n</div>\n", 633 'allow_in' => Array('listitem', 'block', 'columns'), 634 'before_tag' => "sns", 635 'after_tag' => "sns", 636 'before_endtag' => "sns", 637 'after_endtag' => "sns", 638 'plain_start' => "\n", 639 'plain_end' => "\n", 640 ), 641 'indent' => Array( 642 'simple_start' => "\n<div class=\"bbcode_indent\" style=\"margin-left:4em\">\n", 643 'simple_end' => "\n</div>\n", 644 'allow_in' => Array('listitem', 'block', 'columns'), 645 'before_tag' => "sns", 646 'after_tag' => "sns", 647 'before_endtag' => "sns", 648 'after_endtag' => "sns", 649 'plain_start' => "\n", 650 'plain_end' => "\n", 651 ), 652 'columns' => Array( 653 'simple_start' => "\n<table class=\"bbcode_columns\"><tbody><tr><td class=\"bbcode_column bbcode_firstcolumn\">\n", 654 'simple_end' => "\n</td></tr></tbody></table>\n", 655 'class' => 'columns', 656 'allow_in' => Array('listitem', 'block', 'columns'), 657 'end_tag' => BBCODE_REQUIRED, 658 'content' => BBCODE_REQUIRED, 659 'before_tag' => "sns", 660 'after_tag' => "sns", 661 'before_endtag' => "sns", 662 'after_endtag' => "sns", 663 'plain_start' => "\n", 664 'plain_end' => "\n", 665 ), 666 'nextcol' => Array( 667 'simple_start' => "\n</td><td class=\"bbcode_column\">\n", 668 'class' => 'nextcol', 669 'allow_in' => Array('columns'), 670 'end_tag' => BBCODE_PROHIBIT, 671 'content' => BBCODE_PROHIBIT, 672 'before_tag' => "sns", 673 'after_tag' => "sns", 674 'before_endtag' => "sns", 675 'after_endtag' => "sns", 676 'plain_start' => "\n", 677 'plain_end' => "", 678 ), 679 'code' => Array( 680 'mode' => BBCODE_MODE_ENHANCED, 681 'template' => "\n<div class=\"bbcode_code\">\n<div class=\"bbcode_code_head\">Code:</div>\n<div class=\"bbcode_code_body\" style=\"white-space:pre\">{\$_content/v}</div>\n</div>\n", 682 'class' => 'code', 683 'allow_in' => Array('listitem', 'block', 'columns'), 684 'content' => BBCODE_VERBATIM, 685 'before_tag' => "sns", 686 'after_tag' => "sn", 687 'before_endtag' => "sn", 688 'after_endtag' => "sns", 689 'plain_start' => "\n<b>Code:</b>\n", 690 'plain_end' => "\n", 691 ), 692 'quote' => Array( 693 'mode' => BBCODE_MODE_LIBRARY, 694 'method' => "DoQuote", 695 'allow_in' => Array('listitem', 'block', 'columns'), 696 'before_tag' => "sns", 697 'after_tag' => "sns", 698 'before_endtag' => "sns", 699 'after_endtag' => "sns", 700 'plain_start' => "\n<b>Quote:</b>\n", 701 'plain_end' => "\n", 702 ), 703 'list' => Array( 704 'mode' => BBCODE_MODE_LIBRARY, 705 'method' => 'DoList', 706 'class' => 'list', 707 'allow_in' => Array('listitem', 'block', 'columns'), 708 'before_tag' => "sns", 709 'after_tag' => "sns", 710 'before_endtag' => "sns", 711 'after_endtag' => "sns", 712 'plain_start' => "\n", 713 'plain_end' => "\n", 714 ), 715 '*' => Array( 716 'simple_start' => "<li>", 717 'simple_end' => "</li>\n", 718 'class' => 'listitem', 719 'allow_in' => Array('list'), 720 'end_tag' => BBCODE_OPTIONAL, 721 'before_tag' => "s", 722 'after_tag' => "s", 723 'before_endtag' => "sns", 724 'after_endtag' => "sns", 725 'plain_start' => "\n * ", 726 'plain_end' => "\n", 727 ), 728 ); 729 function DoURL($bbcode, $action, $name, $default, $params, $content) { 730 if ($action == BBCODE_CHECK) return true; 731 $url = is_string($default) ? $default : $bbcode->UnHTMLEncode(strip_tags($content)); 732 if ($bbcode->IsValidURL($url)) { 733 if ($bbcode->debug) 734 print "ISVALIDURL<br />"; 735 if ($bbcode->url_targetable !== false && isset($params['target'])) 736 $target = " target=\"" . htmlspecialchars($params['target']) . "\""; 737 else $target = ""; 738 if ($bbcode->url_target !== false) 739 if (!($bbcode->url_targetable == 'override' && isset($params['target']))) 740 $target = " target=\"" . htmlspecialchars($bbcode->url_target) . "\""; 741 return '<a href="' . htmlspecialchars($url) . '" class="bbcode_url"' . $target . '>' . $content . '</a>'; 742 } 743 else return htmlspecialchars($params['_tag']) . $content . htmlspecialchars($params['_endtag']); 744 } 745 function DoEmail($bbcode, $action, $name, $default, $params, $content) { 746 if ($action == BBCODE_CHECK) return true; 747 $email = is_string($default) ? $default : $bbcode->UnHTMLEncode(strip_tags($content)); 748 if ($bbcode->IsValidEmail($email)) 749 return '<a href="mailto:' . htmlspecialchars($email) . '" class="bbcode_email">' . $content . '</a>'; 750 else return htmlspecialchars($params['_tag']) . $content . htmlspecialchars($params['_endtag']); 751 } 752 function DoSize($bbcode, $action, $name, $default, $params, $content) { 753 switch ($default) { 754 case '0': $size = '.5em'; break; 755 case '1': $size = '.67em'; break; 756 case '2': $size = '.83em'; break; 757 default: 758 case '3': $size = '1.0em'; break; 759 case '4': $size = '1.17em'; break; 760 case '5': $size = '1.5em'; break; 761 case '6': $size = '2.0em'; break; 762 case '7': $size = '2.5em'; break; 763 } 764 return "<span style=\"font-size:$size\">$content</span>"; 765 } 766 function DoFont($bbcode, $action, $name, $default, $params, $content) { 767 $fonts = explode(",", $default); 768 $result = ""; 769 $special_fonts = Array( 770 'serif' => 'serif', 771 'sans-serif' => 'sans-serif', 772 'sans serif' => 'sans-serif', 773 'sansserif' => 'sans-serif', 774 'sans' => 'sans-serif', 775 'cursive' => 'cursive', 776 'fantasy' => 'fantasy', 777 'monospace' => 'monospace', 778 'mono' => 'monospace', 779 ); 780 foreach ($fonts as $font) { 781 $font = trim($font); 782 if (isset($special_fonts[$font])) { 783 if (strlen($result) > 0) $result .= ","; 784 $result .= $special_fonts[$font]; 785 } 786 else if (strlen($font) > 0) { 787 if (strlen($result) > 0) $result .= ","; 788 $result .= "'$font'"; 789 } 790 } 791 return "<span style=\"font-family:$result\">$content</span>"; 792 } 793 function DoWiki($bbcode, $action, $name, $default, $params, $content) { 794 $name = $bbcode->Wikify($default); 795 if ($action == BBCODE_CHECK) 796 return strlen($name) > 0; 797 $title = trim(@$params['title']); 798 if (strlen($title) <= 0) $title = trim($default); 799 return "<a href=\"{$bbcode->wiki_url}$name\" class=\"bbcode_wiki\">" 800 . htmlspecialchars($title) . "</a>"; 801 } 802 function DoImage($bbcode, $action, $name, $default, $params, $content) { 803 if ($action == BBCODE_CHECK) return true; 804 $content = trim($bbcode->UnHTMLEncode(strip_tags($content))); 805 if (preg_match("/\\.(?:gif|jpeg|jpg|jpe|png)$/", $content)) { 806 if (preg_match("/^[a-zA-Z0-9_][^:]+$/", $content)) { 807 if (!preg_match("/(?:\\/\\.\\.\\/)|(?:^\\.\\.\\/)|(?:^\\/)/", $content)) { 808 $info = @getimagesize("{$bbcode->local_img_dir}/{$content}"); 809 if ($info[2] == IMAGETYPE_GIF || $info[2] == IMAGETYPE_JPEG || $info[2] == IMAGETYPE_PNG) { 810 return "<img src=\"" 811 . htmlspecialchars("{$bbcode->local_img_url}/{$content}") . "\" alt=\"" 812 . htmlspecialchars(basename($content)) . "\" width=\"" 813 . htmlspecialchars($info[0]) . "\" height=\"" 814 . htmlspecialchars($info[1]) . "\" class=\"bbcode_img\" />"; 815 } 816 } 817 } 818 else if ($bbcode->IsValidURL($content, false)) { 819 return "<img src=\"" . htmlspecialchars($content) . "\" alt=\"" 820 . htmlspecialchars(basename($content)) . "\" class=\"bbcode_img\" />"; 821 } 822 } 823 return htmlspecialchars($params['_tag']) . htmlspecialchars($content) . htmlspecialchars($params['_endtag']); 824 } 825 function DoRule($bbcode, $action, $name, $default, $params, $content) { 826 if ($action == BBCODE_CHECK) return true; 827 else return $bbcode->rule_html; 828 } 829 function DoQuote($bbcode, $action, $name, $default, $params, $content) { 830 if ($action == BBCODE_CHECK) return true; 831 if (isset($params['name'])) { 832 $title = htmlspecialchars(trim($params['name'])) . " wrote"; 833 if (isset($params['date'])) 834 $title .= " on " . htmlspecialchars(trim($params['date'])); 835 $title .= ":"; 836 if (isset($params['url'])) { 837 $url = trim($params['url']); 838 if ($bbcode->IsValidURL($url)) 839 $title = "<a href=\"" . htmlspecialchars($params['url']) . "\">" . $title . "</a>"; 840 } 841 } 842 else if (!is_string($default)) 843 $title = "Quote:"; 844 else $title = htmlspecialchars(trim($default)) . " wrote:"; 845 return "\n<div class=\"bbcode_quote\">\n<div class=\"bbcode_quote_head\">" 846 . $title . "</div>\n<div class=\"bbcode_quote_body\">" 847 . $content . "</div>\n</div>\n"; 848 } 849 function DoList($bbcode, $action, $name, $default, $params, $content) { 850 $list_styles = Array( 851 '1' => 'decimal', 852 '01' => 'decimal-leading-zero', 853 'i' => 'lower-roman', 854 'I' => 'upper-roman', 855 'a' => 'lower-alpha', 856 'A' => 'upper-alpha', 857 ); 858 $ci_list_styles = Array( 859 'circle' => 'circle', 860 'disc' => 'disc', 861 'square' => 'square', 862 'greek' => 'lower-greek', 863 'armenian' => 'armenian', 864 'georgian' => 'georgian', 865 ); 866 $ul_types = Array( 867 'circle' => 'circle', 868 'disc' => 'disc', 869 'square' => 'square', 870 ); 871 $default = trim($default); 872 if ($action == BBCODE_CHECK) { 873 if (!is_string($default) || strlen($default) == "") return true; 874 else if (isset($list_styles[$default])) return true; 875 else if (isset($ci_list_styles[strtolower($default)])) return true; 876 else return false; 877 } 878 if (!is_string($default) || strlen($default) == "") { 879 $elem = 'ul'; 880 $type = ''; 881 } 882 else if ($default == '1') { 883 $elem = 'ol'; 884 $type = ''; 885 } 886 else if (isset($list_styles[$default])) { 887 $elem = 'ol'; 888 $type = $list_styles[$default]; 889 } 890 else { 891 $default = strtolower($default); 892 if (isset($ul_types[$default])) { 893 $elem = 'ul'; 894 $type = $ul_types[$default]; 895 } 896 else if (isset($ci_list_styles[$default])) { 897 $elem = 'ol'; 898 $type = $ci_list_styles[$default]; 899 } 900 } 901 if (strlen($type)) 902 return "\n<$elem class=\"bbcode_list\" style=\"list-style-type:$type\">\n$content</$elem>\n"; 903 else return "\n<$elem class=\"bbcode_list\">\n$content</$elem>\n"; 904 } 905 } 906 907 class BBCodeEmailAddressValidator { 908 function check_email_address($strEmailAddress) { 909 if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $strEmailAddress)) { 910 return false; 911 } 912 $intAtSymbol = strrpos($strEmailAddress, '@'); 913 if ($intAtSymbol === false) { 914 return false; 915 } 916 $arrEmailAddress[0] = substr($strEmailAddress, 0, $intAtSymbol); 917 $arrEmailAddress[1] = substr($strEmailAddress, $intAtSymbol + 1); 918 $arrTempAddress[0] = preg_replace('/"[^"]+"/' 919 ,'' 920 ,$arrEmailAddress[0]); 921 $arrTempAddress[1] = $arrEmailAddress[1]; 922 $strTempAddress = $arrTempAddress[0] . $arrTempAddress[1]; 923 if (strrpos($strTempAddress, '@') !== false) { 924 return false; 925 } 926 if (!$this->check_local_portion($arrEmailAddress[0])) { 927 return false; 928 } 929 if (!$this->check_domain_portion($arrEmailAddress[1])) { 930 return false; 931 } 932 return true; 933 } 934 function check_local_portion($strLocalPortion) { 935 if (!$this->check_text_length($strLocalPortion, 1, 64)) { 936 return false; 937 } 938 $arrLocalPortion = explode('.', $strLocalPortion); 939 for ($i = 0, $max = sizeof($arrLocalPortion); $i < $max; $i++) { 940 if (!preg_match('.^(' 941 . '([A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]' 942 . '[A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]{0,63})' 943 .'|' 944 . '("[^\\\"]{0,62}")' 945 .')$.' 946 ,$arrLocalPortion[$i])) { 947 return false; 948 } 949 } 950 return true; 951 } 952 function check_domain_portion($strDomainPortion) { 953 if (!$this->check_text_length($strDomainPortion, 1, 255)) { 954 return false; 955 } 956 if (preg_match('/^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])' 957 .'(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}$/' 958 ,$strDomainPortion) || 959 preg_match('/^\[(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])' 960 .'(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}\]$/' 961 ,$strDomainPortion)) { 962 return true; 963 } else { 964 $arrDomainPortion = explode('.', $strDomainPortion); 965 if (sizeof($arrDomainPortion) < 2) { 966 return false; 967 } 968 for ($i = 0, $max = sizeof($arrDomainPortion); $i < $max; $i++) { 969 if (!$this->check_text_length($arrDomainPortion[$i], 1, 63)) { 970 return false; 971 } 972 if (!preg_match('/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|' 973 .'([A-Za-z0-9]+))$/', $arrDomainPortion[$i])) { 974 return false; 975 } 976 } 977 } 978 return true; 979 } 980 function check_text_length($strText, $intMinimum, $intMaximum) { 981 $intTextLength = strlen($strText); 982 if (($intTextLength < $intMinimum) || ($intTextLength > $intMaximum)) { 983 return false; 984 } else { 985 return true; 986 } 987 } 988 } 989 990 class BBCode { 991 var $tag_rules; 992 var $defaults; 993 var $current_class; 994 var $root_class; 995 var $lost_start_tags; 996 var $start_tags; 997 var $allow_ampersand; 998 var $tag_marker; 999 var $ignore_newlines; 1000 var $plain_mode; 1001 var $detect_urls; 1002 var $url_pattern; 1003 var $output_limit; 1004 var $text_length; 1005 var $was_limited; 1006 var $limit_tail; 1007 var $limit_precision; 1008 var $smiley_dir; 1009 var $smiley_url; 1010 var $smileys; 1011 var $smiley_regex; 1012 var $enable_smileys; 1013 var $wiki_url; 1014 var $local_img_dir; 1015 var $local_img_url; 1016 var $url_targetable; 1017 var $url_target; 1018 var $rule_html; 1019 var $pre_trim; 1020 var $post_trim; 1021 var $debug; 1022 1023 1024 /* ADDED */ 1025 // singleton instance 1026 private static $instance; 1027 1028 // private constructor function 1029 // to prevent external instantiation 1030 private function __construct() 1031 { 1032 $this->defaults = new BBCodeLibrary; 1033 $this->tag_rules = $this->defaults->default_tag_rules; 1034 $this->smileys = $this->defaults->default_smileys; 1035 $this->enable_smileys = true; 1036 $this->smiley_regex = false; 1037 $this->smiley_dir = $this->GetDefaultSmileyDir(); 1038 $this->smiley_url = $this->GetDefaultSmileyURL(); 1039 $this->wiki_url = $this->GetDefaultWikiURL(); 1040 $this->local_img_dir = $this->GetDefaultLocalImgDir(); 1041 $this->local_img_url = $this->GetDefaultLocalImgURL(); 1042 $this->rule_html = $this->GetDefaultRuleHTML(); 1043 $this->pre_trim = ""; 1044 $this->post_trim = ""; 1045 $this->root_class = 'block'; 1046 $this->lost_start_tags = Array(); 1047 $this->start_tags = Array(); 1048 $this->tag_marker = '['; 1049 $this->allow_ampsersand = false; 1050 $this->current_class = $this->root_class; 1051 $this->debug = false; 1052 $this->ignore_newlines = false; 1053 $this->output_limit = 0; 1054 $this->plain_mode = false; 1055 $this->was_limited = false; 1056 $this->limit_tail = "..."; 1057 $this->limit_precision = 0.15; 1058 $this->detect_urls = false; 1059 $this->url_pattern = '<a href="{$url/h}">{$text/h}</a>'; 1060 $this->url_targetable = false; 1061 $this->url_target = false; 1062 } 1063 1064 // getInstance method 1065 public static function getInstance() 1066 { 1067 if(!self::$instance) 1068 { 1069 self::$instance = new self(); 1070 } 1071 1072 return self::$instance; 1073 } 1074 /* ADDED */ 1075 1076 1077 function SetPreTrim($trim = "a") { $this->pre_trim = $trim; } 1078 function GetPreTrim() { return $this->pre_trim; } 1079 function SetPostTrim($trim = "a") { $this->post_trim = $trim; } 1080 function GetPostTrim() { return $this->post_trim; } 1081 function SetRoot($class = 'block') { $this->root_class = $class; } 1082 function SetRootInline() { $this->root_class = 'inline'; } 1083 function SetRootBlock() { $this->root_class = 'block'; } 1084 function GetRoot() { return $this->root_class; } 1085 function SetDebug($enable = true) { $this->debug = $enable; } 1086 function GetDebug() { return $this->debug; } 1087 function SetAllowAmpersand($enable = true) { $this->allow_ampersand = $enable; } 1088 function GetAllowAmpersand() { return $this->allow_ampersand; } 1089 function SetTagMarker($marker = '[') { $this->tag_marker = $marker; } 1090 function GetTagMarker() { return $this->tag_marker; } 1091 function SetIgnoreNewlines($ignore = true) { $this->ignore_newlines = $ignore; } 1092 function GetIgnoreNewlines() { return $this->ignore_newlines; } 1093 function SetLimit($limit = 0) { $this->output_limit = $limit; } 1094 function GetLimit() { return $this->output_limit; } 1095 function SetLimitTail($tail = "...") { $this->limit_tail = $tail; } 1096 function GetLimitTail() { return $this->limit_tail; } 1097 function SetLimitPrecision($prec = 0.15) { $this->limit_precision = $prec; } 1098 function GetLimitPrecision() { return $this->limit_precision; } 1099 function WasLimited() { return $this->was_limited; } 1100 function SetPlainMode($enable = true) { $this->plain_mode = $enable; } 1101 function GetPlainMode() { return $this->plain_mode; } 1102 function SetDetectURLs($enable = true) { $this->detect_urls = $enable; } 1103 function GetDetectURLs() { return $this->detect_urls; } 1104 function SetURLPattern($pattern) { $this->url_pattern = $pattern; } 1105 function GetURLPattern() { return $this->url_pattern; } 1106 function SetURLTargetable($enable) { $this->url_targetable = $enable; } 1107 function GetURLTargetable() { return $this->url_targetable; } 1108 function SetURLTarget($target) { $this->url_target = $target; } 1109 function GetURLTarget() { return $this->url_target; } 1110 function AddRule($name, $rule) { $this->tag_rules[$name] = $rule; } 1111 function RemoveRule($name) { unset($this->tag_rules[$name]); } 1112 function GetRule($name) { return isset($this->tag_rules[$name]) 1113 ? $this->tag_rules[$name] : false; } 1114 function ClearRules() { $this->tag_rules = Array(); } 1115 function GetDefaultRule($name) { return isset($this->defaults->default_tag_rules[$name]) 1116 ? $this->defaults->default_tag_rules[$name] : false; } 1117 function SetDefaultRule($name) { if (isset($this->defaults->default_tag_rules[$name])) 1118 $this->AddRule($name, $this->defaults->default_tag_rules[$name]); 1119 else $this->RemoveRule($name); } 1120 function GetDefaultRules() { return $this->defaults->default_tag_rules; } 1121 function SetDefaultRules() { $this->tag_rules = $this->defaults->default_tag_rules; } 1122 function SetWikiURL($url) { $this->wiki_url = $url; } 1123 function GetWikiURL($url) { return $this->wiki_url; } 1124 function GetDefaultWikiURL() { return '/?page='; } 1125 function SetLocalImgDir($path) { $this->local_img_dir = $path; } 1126 function GetLocalImgDir() { return $this->local_img_dir; } 1127 function GetDefaultLocalImgDir() { return "img"; } 1128 function SetLocalImgURL($path) { $this->local_img_url = $path; } 1129 function GetLocalImgURL() { return $this->local_img_url; } 1130 function GetDefaultLocalImgURL() { return "img"; } 1131 function SetRuleHTML($html) { $this->rule_html = $html; } 1132 function GetRuleHTML() { return $this->rule_html; } 1133 function GetDefaultRuleHTML() { return "\n<hr class=\"bbcode_rule\" />\n"; } 1134 function AddSmiley($code, $image) { $this->smileys[$code] = $image; $this->smiley_regex = false; } 1135 function RemoveSmiley($code) { unset($this->smileys[$code]); $this->smiley_regex = false; } 1136 function GetSmiley($code) { return isset($this->smileys[$code]) 1137 ? $this->smileys[$code] : false; } 1138 function ClearSmileys() { $this->smileys = Array(); $this->smiley_regex = false; } 1139 function GetDefaultSmiley($code) { return isset($this->defaults->default_smileys[$code]) 1140 ? $this->defaults->default_smileys[$code] : false; } 1141 function SetDefaultSmiley($code) { $this->smileys[$code] = @$this->defaults->default_smileys[$code]; 1142 $this->smiley_regex = false; } 1143 function GetDefaultSmileys() { return $this->defaults->default_smileys; } 1144 function SetDefaultSmileys() { $this->smileys = $this->defaults->default_smileys; 1145 $this->smiley_regex = false; } 1146 function SetSmileyDir($path) { $this->smiley_dir = $path; } 1147 function GetSmileyDir() { return $this->smiley_dir; } 1148 function GetDefaultSmileyDir() { return "smileys"; } 1149 function SetSmileyURL($path) { $this->smiley_url = $path; } 1150 function GetSmileyURL() { return $this->smiley_url; } 1151 function GetDefaultSmileyURL() { return "smileys"; } 1152 function SetEnableSmileys($enable = true) { $this->enable_smileys = $enable; } 1153 function GetEnableSmileys() { return $this->enable_smileys; } 1154 function nl2br($string) { 1155 return preg_replace("/\\x0A|\\x0D|\\x0A\\x0D|\\x0D\\x0A/", "<br />\n", $string); 1156 } 1157 function UnHTMLEncode($string) { 1158 if (function_exists("html_entity_decode")) 1159 return html_entity_decode($string); 1160 $string = preg_replace_callback('~&#x([0-9a-f]+);~i', array( $this, '_UnHTMLEncode_chr_callback'), $string); 1161 $string = preg_replace_callback('~&#([0-9]+);~', array($this, '_UnHTMLEncode_chr_hexdec_callback'), $string); 1162 $trans_tbl = get_html_translation_table(HTML_ENTITIES); 1163 $trans_tbl = array_flip($trans_tbl); 1164 return strtr($string, $trans_tbl); 1165 } 1166 function _UnHTMLEncode_chr_callback($match) { 1167 return chr(hexdec($match[1])); 1168 } 1169 function _UnHTMLEncode_chr_hexdec_callback($match) { 1170 return chr(hexdec($match[1])); 1171 } 1172 function Wikify($string) { 1173 return rawurlencode(str_replace(" ", "_", 1174 trim(preg_replace("/[!?;@#\$%\\^&*<>=+`~\\x00-\\x20_-]+/", " ", $string)))); 1175 } 1176 function IsValidURL($string, $email_too = true) { 1177 if (preg_match("/^ 1178 (?:https?|ftp):\\/\\/ 1179 (?: 1180 (?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+ 1181 [a-zA-Z0-9] 1182 (?:[a-zA-Z0-9-]*[a-zA-Z0-9])? 1183 | 1184 \\[ 1185 (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3} 1186 (?: 1187 25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]: 1188 (?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21-\\x5A\\x53-\\x7F] 1189 |\\\\[\\x01-\\x09\\x0B\\x0C\\x0E-\\x7F])+ 1190 ) 1191 \\] 1192 ) 1193 (?::[0-9]{1,5})? 1194 (?:[\\/\\?\\#][^\\n\\r]*)? 1195 $/Dx", $string)) return true; 1196 if (preg_match("/^[^:]+([\\/\\\\?#][^\\r\\n]*)?$/D", $string)) 1197 return true; 1198 if ($email_too) 1199 if (substr($string, 0, 7) == "mailto:") 1200 return $this->IsValidEmail(substr($string, 7)); 1201 return false; 1202 } 1203 function IsValidEmail($string) { 1204 $validator = new BBCodeEmailAddressValidator; 1205 return $validator->check_email_address($string); 1206 /* 1207 return preg_match("/^ 1208 (?: 1209 [a-z0-9\\!\\#\\\$\\%\\&\\'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]+ 1210 (?:\.[a-z0-9\\!\\#\\\$\\%\\&\\'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]+)* 1211 | 1212 \"(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F] 1213 |\\\\[\\x01-\\x09\\x0B\\x0C\\x0E-\\x7F])*\" 1214 ) 1215 @ 1216 (?: 1217 (?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+ 1218 [a-z0-9] 1219 (?:[a-z0-9-]*[a-z0-9])? 1220 | 1221 \\[ 1222 (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3} 1223 (?: 1224 25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]: 1225 (?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21-\\x5A\\x53-\\x7F] 1226 |\\\\[\\x01-\\x09\\x0B\\x0C\\x0E-\\x7F])+ 1227 ) 1228 \\] 1229 ) 1230 $/Dx", $string); 1231 */ 1232 } 1233 function HTMLEncode($string) { 1234 if (!$this->allow_ampersand) 1235 return htmlspecialchars($string); 1236 else return str_replace(Array('<', '>', '"'), 1237 Array('<', '>', '"'), $string); 1238 } 1239 function FixupOutput($string) { 1240 if (!$this->detect_urls) { 1241 $output = $this->Internal_ProcessSmileys($string); 1242 } 1243 else { 1244 $chunks = $this->Internal_AutoDetectURLs($string); 1245 $output = Array(); 1246 if (count($chunks)) { 1247 $is_a_url = false; 1248 foreach ($chunks as $index => $chunk) { 1249 if (!$is_a_url) { 1250 $chunk = $this->Internal_ProcessSmileys($chunk); 1251 } 1252 $output[] = $chunk; 1253 $is_a_url = !$is_a_url; 1254 } 1255 } 1256 $output = implode("", $output); 1257 } 1258 return $output; 1259 } 1260 function Internal_ProcessSmileys($string) { 1261 if (!$this->enable_smileys || $this->plain_mode) { 1262 $output = $this->HTMLEncode($string); 1263 } 1264 else { 1265 if ($this->smiley_regex === false) { 1266 $this->Internal_RebuildSmileys(); 1267 } 1268 $tokens = preg_split($this->smiley_regex, $string, -1, PREG_SPLIT_DELIM_CAPTURE); 1269 if (count($tokens) <= 1) { 1270 $output = $this->HTMLEncode($string); 1271 } 1272 else { 1273 $output = ""; 1274 $is_a_smiley = false; 1275 foreach ($tokens as $token) { 1276 if (!$is_a_smiley) { 1277 $output .= $this->HTMLEncode($token); 1278 } 1279 else { 1280 if (isset($this->smiley_info[$token])) { 1281 $info = $this->smiley_info[$token]; 1282 } 1283 else { 1284 $info = @getimagesize($this->smiley_dir . '/' . $this->smileys[$token]); 1285 $this->smiley_info[$token] = $info; 1286 } 1287 $alt = htmlspecialchars($token); 1288 $output .= "<img src=\"" . htmlspecialchars($this->smiley_url . '/' . $this->smileys[$token]) 1289 . "\" width=\"{$info[0]}\" height=\"{$info[1]}\"" 1290 . " alt=\"$alt\" title=\"$alt\" class=\"bbcode_smiley\" />"; 1291 } 1292 $is_a_smiley = !$is_a_smiley; 1293 } 1294 } 1295 } 1296 return $output; 1297 } 1298 function Internal_RebuildSmileys() { 1299 $regex = Array("/(?<![\\w])("); 1300 $first = true; 1301 foreach ($this->smileys as $code => $filename) { 1302 if (!$first) $regex[] = "|"; 1303 $regex[] = preg_quote("$code", '/'); 1304 $first = false; 1305 } 1306 $regex[] = ")(?![\\w])/"; 1307 $this->smiley_regex = implode("", $regex); 1308 } 1309 function Internal_AutoDetectURLs($string) { 1310 $output = preg_split("/( (?: 1311 (?:https?|ftp) : \\/* 1312 (?: 1313 (?: (?: [a-zA-Z0-9-]{2,} \\. )+ 1314 (?: arpa | com | org | net | edu | gov | mil | int | [a-z]{2} 1315 | aero | biz | coop | info | museum | name | pro 1316 | example | invalid | localhost | test | local | onion | swift ) ) 1317 | (?: [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} ) 1318 | (?: [0-9A-Fa-f:]+ : [0-9A-Fa-f]{1,4} ) 1319 ) 1320 (?: : [0-9]+ )? 1321 (?! [a-zA-Z0-9.:-] ) 1322 (?: 1323 \\/ 1324 [^&?#\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]* 1325 )? 1326 (?: 1327 [?#] 1328 [^\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]+ 1329 )? 1330 ) | (?: 1331 (?: 1332 (?: (?: [a-zA-Z0-9-]{2,} \\. )+ 1333 (?: arpa | com | org | net | edu | gov | mil | int | [a-z]{2} 1334 | aero | biz | coop | info | museum | name | pro 1335 | example | invalid | localhost | test | local | onion | swift ) ) 1336 | (?: [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} ) 1337 ) 1338 (?: : [0-9]+ )? 1339 (?! [a-zA-Z0-9.:-] ) 1340 (?: 1341 \\/ 1342 [^&?#\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]* 1343 )? 1344 (?: 1345 [?#] 1346 [^\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]+ 1347 )? 1348 ) | (?: 1349 [a-zA-Z0-9._-]{2,} @ 1350 (?: 1351 (?: (?: [a-zA-Z0-9-]{2,} \\. )+ 1352 (?: arpa | com | org | net | edu | gov | mil | int | [a-z]{2} 1353 | aero | biz | coop | info | museum | name | pro 1354 | example | invalid | localhost | test | local | onion | swift ) ) 1355 | (?: [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} ) 1356 ) 1357 ) )/Dx", $string, -1, PREG_SPLIT_DELIM_CAPTURE); 1358 if (count($output) > 1) { 1359 $is_a_url = false; 1360 foreach ($output as $index => $token) { 1361 if ($is_a_url) { 1362 if (preg_match("/^[a-zA-Z0-9._-]{2,}@/", $token)) { 1363 $url = "mailto:" . $token; 1364 } 1365 else if (preg_match("/^(https?:|ftp:)\\/*([^\\/&?#]+)\\/*(.*)\$/", $token, $matches)) { 1366 $url = $matches[1] . '/' . '/' . $matches[2] . "/" . $matches[3]; 1367 } 1368 else { 1369 preg_match("/^([^\\/&?#]+)\\/*(.*)\$/", $token, $matches); 1370 $url = "http:/" . "/" . $matches[1] . "/" . $matches[2]; 1371 } 1372 $params = @parse_url($url); 1373 if (!is_array($params)) $params = Array(); 1374 $params['url'] = $url; 1375 $params['link'] = $url; 1376 $params['text'] = $token; 1377 $output[$index] = $this->FillTemplate($this->url_pattern, $params); 1378 } 1379 $is_a_url = !$is_a_url; 1380 } 1381 } 1382 return $output; 1383 } 1384 function FillTemplate($template, $insert_array, $default_array = Array()) { 1385 $pieces = preg_split('/(\{\$[a-zA-Z0-9_.:\/-]+\})/', $template, 1386 -1, PREG_SPLIT_DELIM_CAPTURE); 1387 if (count($pieces) <= 1) 1388 return $template; 1389 $result = Array(); 1390 $is_an_insert = false; 1391 foreach ($pieces as $piece) { 1392 if (!$is_an_insert) { 1393 $result[] = $piece; 1394 } 1395 else if (!preg_match('/\{\$([a-zA-Z0-9_:-]+)((?:\\.[a-zA-Z0-9_:-]+)*)(?:\/([a-zA-Z0-9_:-]+))?\}/', $piece, $matches)) { 1396 $result[] = $piece; 1397 } 1398 else { 1399 if (isset($insert_array[$matches[1]])) 1400 $value = @$insert_array[$matches[1]]; 1401 else $value = @$default_array[$matches[1]]; 1402 if (strlen(@$matches[2])) { 1403 foreach (explode(".", substr($matches[2], 1)) as $index) { 1404 if (is_array($value)) 1405 $value = @$value[$index]; 1406 else if (is_object($value)) { 1407 $value = (array)$value; 1408 $value = @$value[$index]; 1409 } 1410 else $value = ""; 1411 } 1412 } 1413 switch (gettype($value)) { 1414 case 'boolean': $value = $value ? "true" : "false"; break; 1415 case 'integer': $value = (string)$value; break; 1416 case 'double': $value = (string)$value; break; 1417 case 'string': break; 1418 default: $value = ""; break; 1419 } 1420 if (strlen(@$matches[3])) 1421 $flags = array_flip(str_split($matches[3])); 1422 else $flags = Array(); 1423 if (!isset($flags['v'])) { 1424 if (isset($flags['w'])) 1425 $value = preg_replace("/[\\x00-\\x09\\x0B-\x0C\x0E-\\x20]+/", " ", $value); 1426 if (isset($flags['t'])) $value = trim($value); 1427 if (isset($flags['b'])) $value = basename($value); 1428 if (isset($flags['e'])) $value = $this->HTMLEncode($value); 1429 else if (isset($flags['k'])) $value = $this->Wikify($value); 1430 else if (isset($flags['h'])) $value = htmlspecialchars($value); 1431 else if (isset($flags['u'])) $value = urlencode($value); 1432 if (isset($flags['n'])) $value = $this->nl2br($value); 1433 } 1434 $result[] = $value; 1435 } 1436 $is_an_insert = !$is_an_insert; 1437 } 1438 return implode("", $result); 1439 } 1440 function Internal_CollectText($array, $start = 0) { 1441 ob_start(); 1442 for ($start = intval($start), $end = count($array); $start < $end; $start++) 1443 print $array[$start][BBCODE_STACK_TEXT]; 1444 $output = ob_get_contents(); 1445 ob_end_clean(); 1446 return $output; 1447 } 1448 function Internal_CollectTextReverse($array, $start = 0, $end = 0) { 1449 ob_start(); 1450 for ($start = intval($start); $start >= $end; $start--) 1451 print $array[$start][BBCODE_STACK_TEXT]; 1452 $output = ob_get_contents(); 1453 ob_end_clean(); 1454 return $output; 1455 } 1456 function Internal_GenerateOutput($pos) { 1457 $output = Array(); 1458 while (count($this->stack) > $pos) { 1459 $token = array_pop($this->stack); 1460 if ($token[BBCODE_STACK_TOKEN] != BBCODE_TAG) { 1461 $output[] = $token; 1462 } 1463 else { 1464 $name = @$token[BBCODE_STACK_TAG]['_name']; 1465 $rule = @$this->tag_rules[$name]; 1466 $end_tag = @$rule['end_tag']; 1467 if (!isset($rule['end_tag'])) $end_tag = BBCODE_REQUIRED; 1468 else $end_tag = $rule['end_tag']; 1469 array_pop($this->start_tags[$name]); 1470 if ($end_tag == BBCODE_PROHIBIT) { 1471 $output[] = Array( 1472 BBCODE_STACK_TOKEN => BBCODE_TEXT, 1473 BBCODE_STACK_TAG => false, 1474 BBCODE_STACK_TEXT => $token[BBCODE_STACK_TEXT], 1475 BBCODE_STACK_CLASS => $this->current_class, 1476 ); 1477 } 1478 else { 1479 if ($end_tag == BBCODE_REQUIRED) 1480 @$this->lost_start_tags[$name] += 1; 1481 $end = $this->Internal_CleanupWSByIteratingPointer(@$rule['before_endtag'], 0, $output); 1482 $this->Internal_CleanupWSByPoppingStack(@$rule['after_tag'], $output); 1483 $tag_body = $this->Internal_CollectTextReverse($output, count($output)-1, $end); 1484 $this->Internal_CleanupWSByPoppingStack(@$rule['before_tag'], $this->stack); 1485 @$token[BBCODE_STACK_TAG]=@$this->Internal_UpdateParamsForMissingEndTag(@$token[BBCODE_STACK_TAG]); 1486 $tag_output = $this->DoTag(BBCODE_OUTPUT, $name, 1487 @$token[BBCODE_STACK_TAG]['_default'], @$token[BBCODE_STACK_TAG], $tag_body); 1488 $output = Array(Array( 1489 BBCODE_STACK_TOKEN => BBCODE_TEXT, 1490 BBCODE_STACK_TAG => false, 1491 BBCODE_STACK_TEXT => $tag_output, 1492 BBCODE_STACK_CLASS => $this->current_class 1493 )); 1494 } 1495 } 1496 } 1497 $this->Internal_ComputeCurrentClass(); 1498 return $output; 1499 } 1500 function Internal_RewindToClass($class_list) { 1501 $pos = count($this->stack) - 1; 1502 while ($pos >= 0 && !in_array($this->stack[$pos][BBCODE_STACK_CLASS], $class_list)) 1503 $pos--; 1504 if ($pos < 0) { 1505 if (!in_array($this->root_class, $class_list)) 1506 return false; 1507 } 1508 $output = $this->Internal_GenerateOutput($pos+1); 1509 while (count($output)) { 1510 $token = array_pop($output); 1511 $token[BBCODE_STACK_CLASS] = $this->current_class; 1512 $this->stack[] = $token; 1513 } 1514 return true; 1515 } 1516 function Internal_FinishTag($tag_name) { 1517 if (strlen($tag_name) <= 0) 1518 return false; 1519 if (isset($this->start_tags[$tag_name]) 1520 && count($this->start_tags[$tag_name])) 1521 $pos = array_pop($this->start_tags[$tag_name]); 1522 else $pos = -1; 1523 if ($pos < 0) return false; 1524 $newpos = $this->Internal_CleanupWSByIteratingPointer(@$this->tag_rules[$tag_name]['after_tag'], 1525 $pos+1, $this->stack); 1526 $delta = $newpos - ($pos+1); 1527 $output = $this->Internal_GenerateOutput($newpos); 1528 $newend = $this->Internal_CleanupWSByIteratingPointer(@$this->tag_rules[$tag_name]['before_endtag'], 1529 0, $output); 1530 $output = $this->Internal_CollectTextReverse($output, count($output) - 1, $newend); 1531 while ($delta-- > 0) 1532 array_pop($this->stack); 1533 $this->Internal_ComputeCurrentClass(); 1534 return $output; 1535 } 1536 function Internal_ComputeCurrentClass() { 1537 if (count($this->stack) > 0) 1538 $this->current_class = $this->stack[count($this->stack)-1][BBCODE_STACK_CLASS]; 1539 else $this->current_class = $this->root_class; 1540 } 1541 function Internal_DumpStack($array = false, $raw = false) { 1542 if (!$raw) $string = "<span style='color: #00C;'>"; 1543 else $string = ""; 1544 if ($array === false) 1545 $array = $this->stack; 1546 foreach ($array as $item) { 1547 switch (@$item[BBCODE_STACK_TOKEN]) { 1548 case BBCODE_TEXT: 1549 $string .= "\"" . htmlspecialchars(@$item[BBCODE_STACK_TEXT]) . "\" "; 1550 break; 1551 case BBCODE_WS: 1552 $string .= "WS "; 1553 break; 1554 case BBCODE_NL: 1555 $string .= "NL "; 1556 break; 1557 case BBCODE_TAG: 1558 $string .= "[" . htmlspecialchars(@$item[BBCODE_STACK_TAG]['_name']) . "] "; 1559 break; 1560 default: 1561 $string .= "unknown "; 1562 break; 1563 } 1564 } 1565 if (!$raw) $string .= "</span>"; 1566 return $string; 1567 } 1568 function Internal_CleanupWSByPoppingStack($pattern, &$array) { 1569 if (strlen($pattern) <= 0) return; 1570 $oldlen = count($array); 1571 foreach (str_split($pattern) as $char) { 1572 switch ($char) { 1573 case 's': 1574 while (count($array) > 0 && $array[count($array)-1][BBCODE_STACK_TOKEN] == BBCODE_WS) 1575 array_pop($array); 1576 break; 1577 case 'n': 1578 if (count($array) > 0 && $array[count($array)-1][BBCODE_STACK_TOKEN] == BBCODE_NL) 1579 array_pop($array); 1580 break; 1581 case 'a': 1582 while (count($array) > 0 1583 && (($token = $array[count($array)-1][BBCODE_STACK_TOKEN]) == BBCODE_WS 1584 || $token == BBCODE_NL)) 1585 array_pop($array); 1586 break; 1587 } 1588 } 1589 if (count($array) != $oldlen) { 1590 $this->Internal_ComputeCurrentClass(); 1591 } 1592 } 1593 function Internal_CleanupWSByEatingInput($pattern) { 1594 if (strlen($pattern) <= 0) return; 1595 foreach (str_split($pattern) as $char) { 1596 switch ($char) { 1597 case 's': 1598 $token_type = $this->lexer->NextToken(); 1599 while ($token_type == BBCODE_WS) { 1600 $token_type = $this->lexer->NextToken(); 1601 } 1602 $this->lexer->UngetToken(); 1603 break; 1604 case 'n': 1605 $token_type = $this->lexer->NextToken(); 1606 if ($token_type != BBCODE_NL) 1607 $this->lexer->UngetToken(); 1608 break; 1609 case 'a': 1610 $token_type = $this->lexer->NextToken(); 1611 while ($token_type == BBCODE_WS || $token_type == BBCODE_NL) { 1612 $token_type = $this->lexer->NextToken(); 1613 } 1614 $this->lexer->UngetToken(); 1615 break; 1616 } 1617 } 1618 } 1619 function Internal_CleanupWSByIteratingPointer($pattern, $pos, $array) { 1620 if (strlen($pattern) <= 0) return $pos; 1621 foreach (str_split($pattern) as $char) { 1622 switch ($char) { 1623 case 's': 1624 while ($pos < count($array) && $array[$pos][BBCODE_STACK_TOKEN] == BBCODE_WS) 1625 $pos++; 1626 break; 1627 case 'n': 1628 if ($pos < count($array) && $array[$pos][BBCODE_STACK_TOKEN] == BBCODE_NL) 1629 $pos++; 1630 break; 1631 case 'a': 1632 while ($pos < count($array) 1633 && (($token = $array[$pos][BBCODE_STACK_TOKEN]) == BBCODE_WS || $token == BBCODE_NL)) 1634 $pos++; 1635 break; 1636 } 1637 } 1638 return $pos; 1639 } 1640 function Internal_LimitText($string, $limit) { 1641 $chunks = preg_split("/([\\x00-\\x20]+)/", $string, -1, PREG_SPLIT_DELIM_CAPTURE); 1642 $output = ""; 1643 foreach ($chunks as $chunk) { 1644 if (strlen($output) + strlen($chunk) > $limit) 1645 break; 1646 $output .= $chunk; 1647 } 1648 $output = rtrim($output); 1649 return $output; 1650 } 1651 function Internal_DoLimit() { 1652 $this->Internal_CleanupWSByPoppingStack("a", $this->stack); 1653 if (strlen($this->limit_tail) > 0) { 1654 $this->stack[] = Array( 1655 BBCODE_STACK_TOKEN => BBCODE_TEXT, 1656 BBCODE_STACK_TEXT => $this->limit_tail, 1657 BBCODE_STACK_TAG => false, 1658 BBCODE_STACK_CLASS => $this->current_class, 1659 ); 1660 } 1661 $this->was_limited = true; 1662 } 1663 function DoTag($action, $tag_name, $default_value, $params, $contents) { 1664 $tag_rule = @$this->tag_rules[$tag_name]; 1665 switch ($action) { 1666 case BBCODE_CHECK: 1667 if (isset($tag_rule['allow'])) { 1668 foreach ($tag_rule['allow'] as $param => $pattern) { 1669 if ($param == '_content') $value = $contents; 1670 else if ($param == '_defaultcontent') { 1671 if (strlen($default_value)) 1672 $value = $default_value; 1673 else $value = $contents; 1674 } 1675 else { 1676 if (isset($params[$param])) 1677 $value = $params[$param]; 1678 else $value = @$tag_rule['default'][$param]; 1679 } 1680 if (!preg_match($pattern, $value)) { 1681 return false; 1682 } 1683 } 1684 return true; 1685 } 1686 switch (@$tag_rule['mode']) { 1687 default: 1688 case BBCODE_MODE_SIMPLE: 1689 $result = true; 1690 break; 1691 case BBCODE_MODE_ENHANCED: 1692 $result = true; 1693 break; 1694 case BBCODE_MODE_INTERNAL: 1695 $result = @call_user_func(Array($this, @$tag_rule['method']), BBCODE_CHECK, 1696 $tag_name, $default_value, $params, $contents); 1697 break; 1698 case BBCODE_MODE_LIBRARY: 1699 $result = @call_user_func(Array($this->defaults, @$tag_rule['method']), $this, BBCODE_CHECK, 1700 $tag_name, $default_value, $params, $contents); 1701 break; 1702 case BBCODE_MODE_CALLBACK: 1703 $result = @call_user_func(@$tag_rule['method'], $this, BBCODE_CHECK, 1704 $tag_name, $default_value, $params, $contents); 1705 break; 1706 } 1707 return $result; 1708 case BBCODE_OUTPUT: 1709 if ($this->plain_mode) { 1710 if (!isset($tag_rule['plain_content'])) 1711 $plain_content = Array('_content'); 1712 else $plain_content = $tag_rule['plain_content']; 1713 $result = $possible_content = ""; 1714 foreach ($plain_content as $possible_content) { 1715 if ($possible_content == '_content' 1716 && strlen($contents) > 0) { 1717 $result = $contents; 1718 break; 1719 } 1720 if (isset($params[$possible_content]) 1721 && strlen($params[$possible_content]) > 0) { 1722 $result = htmlspecialchars($params[$possible_content]); 1723 break; 1724 } 1725 } 1726 $start = @$tag_rule['plain_start']; 1727 $end = @$tag_rule['plain_end']; 1728 if (isset($tag_rule['plain_link'])) { 1729 $link = $possible_content = ""; 1730 foreach ($tag_rule['plain_link'] as $possible_content) { 1731 if ($possible_content == '_content' 1732 && strlen($contents) > 0) { 1733 $link = $this->UnHTMLEncode(strip_tags($contents)); 1734 break; 1735 } 1736 if (isset($params[$possible_content]) 1737 && strlen($params[$possible_content]) > 0) { 1738 $link = $params[$possible_content]; 1739 break; 1740 } 1741 } 1742 $params = @parse_url($link); 1743 if (!is_array($params)) $params = Array(); 1744 $params['link'] = $link; 1745 $params['url'] = $link; 1746 $start = $this->FillTemplate($start, $params); 1747 $end = $this->FillTemplate($end, $params); 1748 } 1749 return $start . $result . $end; 1750 } 1751 switch (@$tag_rule['mode']) { 1752 default: 1753 case BBCODE_MODE_SIMPLE: 1754 $result = @$tag_rule['simple_start'] . $contents . @$tag_rule['simple_end']; 1755 break; 1756 case BBCODE_MODE_ENHANCED: 1757 $result = $this->Internal_DoEnhancedTag($tag_rule, $params, $contents); 1758 break; 1759 case BBCODE_MODE_INTERNAL: 1760 $result = @call_user_func(Array($this, @$tag_rule['method']), BBCODE_OUTPUT, 1761 $tag_name, $default_value, $params, $contents); 1762 break; 1763 case BBCODE_MODE_LIBRARY: 1764 $result = @call_user_func(Array($this->defaults, @$tag_rule['method']), $this, BBCODE_OUTPUT, 1765 $tag_name, $default_value, $params, $contents); 1766 break; 1767 case BBCODE_MODE_CALLBACK: 1768 $result = @call_user_func(@$tag_rule['method'], $this, BBCODE_OUTPUT, 1769 $tag_name, $default_value, $params, $contents); 1770 break; 1771 } 1772 return $result; 1773 default: 1774 return false; 1775 } 1776 } 1777 function Internal_DoEnhancedTag($tag_rule, $params, $contents) { 1778 $params['_content'] = $contents; 1779 $params['_defaultcontent'] = strlen(@$params['_default']) ? $params['_default'] : $contents; 1780 return $this->FillTemplate(@$tag_rule['template'], $params, @$tag_rule['default']); 1781 } 1782 function Internal_UpdateParamsForMissingEndTag($params) { 1783 switch ($this->tag_marker) { 1784 case '[': $tail_marker = ']'; break; 1785 case '<': $tail_marker = '>'; break; 1786 case '{': $tail_marker = '}'; break; 1787 case '(': $tail_marker = ')'; break; 1788 default: $tail_marker = $this->tag_marker; break; 1789 } 1790 $params['_endtag'] = $this->tag_marker . '/' . $params['_name'] . $tail_marker; 1791 return $params; 1792 } 1793 function Internal_ProcessIsolatedTag($tag_name, $tag_params, $tag_rule) { 1794 if (!$this->DoTag(BBCODE_CHECK, $tag_name, @$tag_params['_default'], $tag_params, "")) { 1795 $this->stack[] = Array( 1796 BBCODE_STACK_TOKEN => BBCODE_TEXT, 1797 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text), 1798 BBCODE_STACK_TAG => false, 1799 BBCODE_STACK_CLASS => $this->current_class, 1800 ); 1801 return; 1802 } 1803 $this->Internal_CleanupWSByPoppingStack(@$tag_rule['before_tag'], $this->stack); 1804 $output = $this->DoTag(BBCODE_OUTPUT, $tag_name, @$tag_params['_default'], $tag_params, ""); 1805 $this->Internal_CleanupWSByEatingInput(@$tag_rule['after_tag']); 1806 $this->stack[] = Array( 1807 BBCODE_STACK_TOKEN => BBCODE_TEXT, 1808 BBCODE_STACK_TEXT => $output, 1809 BBCODE_STACK_TAG => false, 1810 BBCODE_STACK_CLASS => $this->current_class, 1811 ); 1812 } 1813 function Internal_ProcessVerbatimTag($tag_name, $tag_params, $tag_rule) { 1814 $state = $this->lexer->SaveState(); 1815 $end_tag = $this->lexer->tagmarker . "/" . $tag_name . $this->lexer->end_tagmarker; 1816 $start = count($this->stack); 1817 $this->lexer->verbatim = true; 1818 while (($token_type = $this->lexer->NextToken()) != BBCODE_EOI) { 1819 if ($this->lexer->text == $end_tag) { 1820 $end_tag_params = $this->lexer->tag; 1821 break; 1822 } 1823 if ($this->output_limit > 0 1824 && $this->text_length + strlen($this->lexer->text) >= $this->output_limit) { 1825 $text = $this->Internal_LimitText($this->lexer->text, 1826 $this->output_limit - $this->text_length); 1827 if (strlen($text) > 0) { 1828 $this->text_length += strlen($text); 1829 $this->stack[] = Array( 1830 BBCODE_STACK_TOKEN => BBCODE_TEXT, 1831 BBCODE_STACK_TEXT => $this->FixupOutput($text), 1832 BBCODE_STACK_TAG => false, 1833 BBCODE_STACK_CLASS => $this->current_class, 1834 ); 1835 } 1836 $this->Internal_DoLimit(); 1837 break; 1838 } 1839 $this->text_length += strlen($this->lexer->text); 1840 $this->stack[] = Array( 1841 BBCODE_STACK_TOKEN => $token_type, 1842 BBCODE_STACK_TEXT => htmlspecialchars($this->lexer->text), 1843 BBCODE_STACK_TAG => $this->lexer->tag, 1844 BBCODE_STACK_CLASS => $this->current_class, 1845 ); 1846 } 1847 $this->lexer->verbatim = false; 1848 if ($token_type == BBCODE_EOI) { 1849 $this->lexer->RestoreState($state); 1850 $this->stack[] = Array( 1851 BBCODE_STACK_TOKEN => BBCODE_TEXT, 1852 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text), 1853 BBCODE_STACK_TAG => false, 1854 BBCODE_STACK_CLASS => $this->current_class, 1855 ); 1856 return; 1857 } 1858 $newstart = $this->Internal_CleanupWSByIteratingPointer(@$tag_rule['after_tag'], $start, $this->stack); 1859 $this->Internal_CleanupWSByPoppingStack(@$tag_rule['before_endtag'], $this->stack); 1860 $this->Internal_CleanupWSByEatingInput(@$tag_rule['after_endtag']); 1861 $content = $this->Internal_CollectText($this->stack, $newstart); 1862 array_splice($this->stack, $start); 1863 $this->Internal_ComputeCurrentClass(); 1864 $this->Internal_CleanupWSByPoppingStack(@$tag_rule['before_tag'], $this->stack); 1865 $tag_params['_endtag'] = $end_tag_params['_tag']; 1866 $tag_params['_hasend'] = true; 1867 $output = $this->DoTag(BBCODE_OUTPUT, $tag_name, 1868 @$tag_params['_default'], $tag_params, $content); 1869 $this->stack[] = Array( 1870 BBCODE_STACK_TOKEN => BBCODE_TEXT, 1871 BBCODE_STACK_TEXT => $output, 1872 BBCODE_STACK_TAG => false, 1873 BBCODE_STACK_CLASS => $this->current_class, 1874 ); 1875 } 1876 function Internal_ParseStartTagToken() { 1877 $tag_params = $this->lexer->tag; 1878 $tag_name = @$tag_params['_name']; 1879 if (!isset($this->tag_rules[$tag_name])) { 1880 $this->stack[] = Array( 1881 BBCODE_STACK_TOKEN => BBCODE_TEXT, 1882 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text), 1883 BBCODE_STACK_TAG => false, 1884 BBCODE_STACK_CLASS => $this->current_class, 1885 ); 1886 return; 1887 } 1888 $tag_rule = $this->tag_rules[$tag_name]; 1889 $allow_in = is_array($tag_rule['allow_in']) 1890 ? $tag_rule['allow_in'] : Array($this->root_class); 1891 if (!in_array($this->current_class, $allow_in)) { 1892 if (!$this->Internal_RewindToClass($allow_in)) { 1893 $this->stack[] = Array( 1894 BBCODE_STACK_TOKEN => BBCODE_TEXT, 1895 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text), 1896 BBCODE_STACK_TAG => false, 1897 BBCODE_STACK_CLASS => $this->current_class, 1898 ); 1899 return; 1900 } 1901 } 1902 $end_tag = isset($tag_rule['end_tag']) ? $tag_rule['end_tag'] : BBCODE_REQUIRED; 1903 if ($end_tag == BBCODE_PROHIBIT) { 1904 $this->Internal_ProcessIsolatedTag($tag_name, $tag_params, $tag_rule); 1905 return; 1906 } 1907 if (!$this->DoTag(BBCODE_CHECK, $tag_name, @$tag_params['_default'], $tag_params, "")) { 1908 $this->stack[] = Array( 1909 BBCODE_STACK_TOKEN => BBCODE_TEXT, 1910 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text), 1911 BBCODE_STACK_TAG => false, 1912 BBCODE_STACK_CLASS => $this->current_class, 1913 ); 1914 return; 1915 } 1916 if (@$tag_rule['content'] == BBCODE_VERBATIM) { 1917 $this->Internal_ProcessVerbatimTag($tag_name, $tag_params, $tag_rule); 1918 return; 1919 } 1920 if (isset($tag_rule['class'])) 1921 $newclass = $tag_rule['class']; 1922 else $newclass = $this->root_class; 1923 $this->stack[] = Array( 1924 BBCODE_STACK_TOKEN => $this->lexer->token, 1925 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text), 1926 BBCODE_STACK_TAG => $this->lexer->tag, 1927 BBCODE_STACK_CLASS => ($this->current_class = $newclass), 1928 ); 1929 if (!isset($this->start_tags[$tag_name])) 1930 $this->start_tags[$tag_name] = Array(count($this->stack)-1); 1931 else $this->start_tags[$tag_name][] = count($this->stack)-1; 1932 } 1933 function Internal_ParseEndTagToken() { 1934 $tag_params = $this->lexer->tag; 1935 $tag_name = @$tag_params['_name']; 1936 $contents = $this->Internal_FinishTag($tag_name); 1937 if ($contents === false) { 1938 if (@$this->lost_start_tags[$tag_name] > 0) { 1939 $this->lost_start_tags[$tag_name]--; 1940 } 1941 else { 1942 $this->stack[] = Array( 1943 BBCODE_STACK_TOKEN => BBCODE_TEXT, 1944 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text), 1945 BBCODE_STACK_TAG => false, 1946 BBCODE_STACK_CLASS => $this->current_class, 1947 ); 1948 } 1949 return; 1950 } 1951 $start_tag_node = array_pop($this->stack); 1952 $start_tag_params = $start_tag_node[BBCODE_STACK_TAG]; 1953 $this->Internal_ComputeCurrentClass(); 1954 $this->Internal_CleanupWSByPoppingStack(@$this->tag_rules[$tag_name]['before_tag'], $this->stack); 1955 $start_tag_params['_endtag'] = $tag_params['_tag']; 1956 $start_tag_params['_hasend'] = true; 1957 $output = $this->DoTag(BBCODE_OUTPUT, $tag_name, @$start_tag_params['_default'], 1958 $start_tag_params, $contents); 1959 $this->Internal_CleanupWSByEatingInput(@$this->tag_rules[$tag_name]['after_endtag']); 1960 $this->stack[] = Array( 1961 BBCODE_STACK_TOKEN => BBCODE_TEXT, 1962 BBCODE_STACK_TEXT => $output, 1963 BBCODE_STACK_TAG => false, 1964 BBCODE_STACK_CLASS => $this->current_class, 1965 ); 1966 } 1967 function Parse($string) { 1968 $this->lexer = new BBCodeLexer($string, $this->tag_marker); 1969 $this->lexer->debug = $this->debug; 1970 $old_output_limit = $this->output_limit; 1971 if ($this->output_limit > 0) { 1972 if (strlen($string) < $this->output_limit) { 1973 $this->output_limit = 0; 1974 } 1975 else if ($this->limit_precision > 0) { 1976 $guess_length = $this->lexer->GuessTextLength(); 1977 if ($guess_length < $this->output_limit * ($this->limit_precision + 1.0)) { 1978 $this->output_limit = 0; 1979 } 1980 else { 1981 } 1982 } 1983 } 1984 $this->stack = Array(); 1985 $this->start_tags = Array(); 1986 $this->lost_start_tags = Array(); 1987 $this->text_length = 0; 1988 $this->was_limited = false; 1989 if (strlen($this->pre_trim) > 0) 1990 $this->Internal_CleanupWSByEatingInput($this->pre_trim); 1991 $newline = $this->plain_mode ? "\n" : "<br />\n"; 1992 while (true) { 1993 if (($token_type = $this->lexer->NextToken()) == BBCODE_EOI) { 1994 break; 1995 } 1996 switch ($token_type) { 1997 case BBCODE_TEXT: 1998 if ($this->output_limit > 0 1999 && $this->text_length + strlen($this->lexer->text) >= $this->output_limit) { 2000 $text = $this->Internal_LimitText($this->lexer->text, 2001 $this->output_limit - $this->text_length); 2002 if (strlen($text) > 0) { 2003 $this->text_length += strlen($text); 2004 $this->stack[] = Array( 2005 BBCODE_STACK_TOKEN => BBCODE_TEXT, 2006 BBCODE_STACK_TEXT => $this->FixupOutput($text), 2007 BBCODE_STACK_TAG => false, 2008 BBCODE_STACK_CLASS => $this->current_class, 2009 ); 2010 } 2011 $this->Internal_DoLimit(); 2012 break 2; 2013 } 2014 $this->text_length += strlen($this->lexer->text); 2015 $this->stack[] = Array( 2016 BBCODE_STACK_TOKEN => BBCODE_TEXT, 2017 BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text), 2018 BBCODE_STACK_TAG => false, 2019 BBCODE_STACK_CLASS => $this->current_class, 2020 ); 2021 break; 2022 case BBCODE_WS: 2023 if ($this->output_limit > 0 2024 && $this->text_length + strlen($this->lexer->text) >= $this->output_limit) { 2025 $this->Internal_DoLimit(); 2026 break 2; 2027 } 2028 $this->text_length += strlen($this->lexer->text); 2029 $this->stack[] = Array( 2030 BBCODE_STACK_TOKEN => BBCODE_WS, 2031 BBCODE_STACK_TEXT => $this->lexer->text, 2032 BBCODE_STACK_TAG => false, 2033 BBCODE_STACK_CLASS => $this->current_class, 2034 ); 2035 break; 2036 case BBCODE_NL: 2037 if ($this->ignore_newlines) { 2038 if ($this->output_limit > 0 2039 && $this->text_length + 1 >= $this->output_limit) { 2040 $this->Internal_DoLimit(); 2041 break 2; 2042 } 2043 $this->text_length += 1; 2044 $this->stack[] = Array( 2045 BBCODE_STACK_TOKEN => BBCODE_WS, 2046 BBCODE_STACK_TEXT => "\n", 2047 BBCODE_STACK_TAG => false, 2048 BBCODE_STACK_CLASS => $this->current_class, 2049 ); 2050 } 2051 else { 2052 $this->Internal_CleanupWSByPoppingStack("s", $this->stack); 2053 if ($this->output_limit > 0 2054 && $this->text_length + 1 >= $this->output_limit) { 2055 $this->Internal_DoLimit(); 2056 break 2; 2057 } 2058 $this->text_length += 1; 2059 $this->stack[] = Array( 2060 BBCODE_STACK_TOKEN => BBCODE_NL, 2061 BBCODE_STACK_TEXT => $newline, 2062 BBCODE_STACK_TAG => false, 2063 BBCODE_STACK_CLASS => $this->current_class, 2064 ); 2065 $this->Internal_CleanupWSByEatingInput("s"); 2066 } 2067 break; 2068 case BBCODE_TAG: 2069 $this->Internal_ParseStartTagToken(); 2070 break; 2071 case BBCODE_ENDTAG: 2072 $this->Internal_ParseEndTagToken(); 2073 break; 2074 default: 2075 break; 2076 } 2077 } 2078 if (strlen($this->post_trim) > 0) 2079 $this->Internal_CleanupWSByPoppingStack($this->post_trim, $this->stack); 2080 $result = $this->Internal_GenerateOutput(0); 2081 $result = $this->Internal_CollectTextReverse($result, count($result) - 1); 2082 $this->output_limit = $old_output_limit; 2083 if ($this->plain_mode) { 2084 $result = preg_replace("/[\\x00-\\x09\\x0B-\\x20]+/", " ", $result); 2085 $result = preg_replace("/(?:[\\x20]*\\n){2,}[\\x20]*/", "\n\n", $result); 2086 $result = trim($result); 2087 } 2088 return $result; 2089 } 2090 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sat Dec 21 01:00:52 2024 | Cross-referenced by PHPXref 0.7.1 |