[ Index ] |
PHP Cross Reference of phpBB-3.2.11-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * 4 * This file is part of the phpBB Forum Software package. 5 * 6 * @copyright (c) phpBB Limited <https://www.phpbb.com> 7 * @license GNU General Public License, version 2 (GPL-2.0) 8 * 9 * For full copyright and license information, please see 10 * the docs/CREDITS.txt file. 11 * 12 */ 13 14 /** 15 * @ignore 16 */ 17 if (!defined('IN_PHPBB')) 18 { 19 exit; 20 } 21 22 if (!class_exists('bbcode')) 23 { 24 // The following lines are for extensions which include message_parser.php 25 // while $phpbb_root_path and $phpEx are out of the script scope 26 // which may lead to the 'Undefined variable' and 'failed to open stream' errors 27 if (!isset($phpbb_root_path)) 28 { 29 global $phpbb_root_path; 30 } 31 32 if (!isset($phpEx)) 33 { 34 global $phpEx; 35 } 36 37 include($phpbb_root_path . 'includes/bbcode.' . $phpEx); 38 } 39 40 /** 41 * BBCODE FIRSTPASS 42 * BBCODE first pass class (functions for parsing messages for db storage) 43 */ 44 class bbcode_firstpass extends bbcode 45 { 46 var $message = ''; 47 var $warn_msg = array(); 48 var $parsed_items = array(); 49 50 /** 51 * Parse BBCode 52 */ 53 function parse_bbcode() 54 { 55 if (!$this->bbcodes) 56 { 57 $this->bbcode_init(); 58 } 59 60 global $user; 61 62 $this->bbcode_bitfield = ''; 63 $bitfield = new bitfield(); 64 65 foreach ($this->bbcodes as $bbcode_name => $bbcode_data) 66 { 67 if (isset($bbcode_data['disabled']) && $bbcode_data['disabled']) 68 { 69 foreach ($bbcode_data['regexp'] as $regexp => $replacement) 70 { 71 if (preg_match($regexp, $this->message)) 72 { 73 $this->warn_msg[] = sprintf($user->lang['UNAUTHORISED_BBCODE'] , '[' . $bbcode_name . ']'); 74 continue; 75 } 76 } 77 } 78 else 79 { 80 foreach ($bbcode_data['regexp'] as $regexp => $replacement) 81 { 82 // The pattern gets compiled and cached by the PCRE extension, 83 // it should not demand recompilation 84 if (preg_match($regexp, $this->message)) 85 { 86 if (is_callable($replacement)) 87 { 88 $this->message = preg_replace_callback($regexp, $replacement, $this->message); 89 } 90 else 91 { 92 $this->message = preg_replace($regexp, $replacement, $this->message); 93 } 94 $bitfield->set($bbcode_data['bbcode_id']); 95 } 96 } 97 } 98 } 99 100 $this->bbcode_bitfield = $bitfield->get_base64(); 101 } 102 103 /** 104 * Prepare some bbcodes for better parsing 105 */ 106 function prepare_bbcodes() 107 { 108 // Ok, seems like users instead want the no-parsing of urls, smilies, etc. after and before and within quote tags being tagged as "not a bug". 109 // Fine by me ;) Will ease our live... but do not come back and cry at us, we won't hear you. 110 111 /* Add newline at the end and in front of each quote block to prevent parsing errors (urls, smilies, etc.) 112 if (strpos($this->message, '[quote') !== false && strpos($this->message, '[/quote]') !== false) 113 { 114 $this->message = str_replace("\r\n", "\n", $this->message); 115 116 // We strip newlines and spaces after and before quotes in quotes (trimming) and then add exactly one newline 117 $this->message = preg_replace('#\[quote(=".*?")?\]\s*(.*?)\s*\[/quote\]#siu', '[quote\1]' . "\n" . '\2' ."\n[/quote]", $this->message); 118 } 119 */ 120 121 // Add other checks which needs to be placed before actually parsing anything (be it bbcodes, smilies, urls...) 122 } 123 124 /** 125 * Init bbcode data for later parsing 126 */ 127 function bbcode_init($allow_custom_bbcode = true) 128 { 129 global $phpbb_dispatcher; 130 131 static $rowset; 132 133 $bbcode_class = $this; 134 135 // This array holds all bbcode data. BBCodes will be processed in this 136 // order, so it is important to keep [code] in first position and 137 // [quote] in second position. 138 // To parse multiline URL we enable dotall option setting only for URL text 139 // but not for link itself, thus [url][/url] is not affected. 140 // 141 // To perform custom validation in extension, use $this->validate_bbcode_by_extension() 142 // method which accepts variable number of parameters 143 $this->bbcodes = array( 144 'code' => array('bbcode_id' => BBCODE_ID_CODE, 'regexp' => array('#\[code(?:=([a-z]+))?\](.+\[/code\])#uis' => function ($match) use($bbcode_class) 145 { 146 return $bbcode_class->bbcode_code($match[1], $match[2]); 147 } 148 )), 149 'quote' => array('bbcode_id' => BBCODE_ID_QUOTE, 'regexp' => array('#\[quote(?:="(.*?)")?\](.+)\[/quote\]#uis' => function ($match) use($bbcode_class) 150 { 151 return $bbcode_class->bbcode_quote($match[0]); 152 } 153 )), 154 'attachment' => array('bbcode_id' => BBCODE_ID_ATTACH, 'regexp' => array('#\[attachment=([0-9]+)\](.*?)\[/attachment\]#uis' => function ($match) use($bbcode_class) 155 { 156 return $bbcode_class->bbcode_attachment($match[1], $match[2]); 157 } 158 )), 159 'b' => array('bbcode_id' => BBCODE_ID_B, 'regexp' => array('#\[b\](.*?)\[/b\]#uis' => function ($match) use($bbcode_class) 160 { 161 return $bbcode_class->bbcode_strong($match[1]); 162 } 163 )), 164 'i' => array('bbcode_id' => BBCODE_ID_I, 'regexp' => array('#\[i\](.*?)\[/i\]#uis' => function ($match) use($bbcode_class) 165 { 166 return $bbcode_class->bbcode_italic($match[1]); 167 } 168 )), 169 'url' => array('bbcode_id' => BBCODE_ID_URL, 'regexp' => array('#\[url(=(.*))?\](?(1)((?s).*(?-s))|(.*))\[/url\]#uiU' => function ($match) use($bbcode_class) 170 { 171 return $bbcode_class->validate_url($match[2], ($match[3]) ? $match[3] : $match[4]); 172 } 173 )), 174 'img' => array('bbcode_id' => BBCODE_ID_IMG, 'regexp' => array('#\[img\](.*)\[/img\]#uiU' => function ($match) use($bbcode_class) 175 { 176 return $bbcode_class->bbcode_img($match[1]); 177 } 178 )), 179 'size' => array('bbcode_id' => BBCODE_ID_SIZE, 'regexp' => array('#\[size=([\-\+]?\d+)\](.*?)\[/size\]#uis' => function ($match) use($bbcode_class) 180 { 181 return $bbcode_class->bbcode_size($match[1], $match[2]); 182 } 183 )), 184 'color' => array('bbcode_id' => BBCODE_ID_COLOR, 'regexp' => array('!\[color=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+)\](.*?)\[/color\]!uis' => function ($match) use($bbcode_class) 185 { 186 return $bbcode_class->bbcode_color($match[1], $match[2]); 187 } 188 )), 189 'u' => array('bbcode_id' => BBCODE_ID_U, 'regexp' => array('#\[u\](.*?)\[/u\]#uis' => function ($match) use($bbcode_class) 190 { 191 return $bbcode_class->bbcode_underline($match[1]); 192 } 193 )), 194 'list' => array('bbcode_id' => BBCODE_ID_LIST, 'regexp' => array('#\[list(?:=(?:[a-z0-9]|disc|circle|square))?].*\[/list]#uis' => function ($match) use($bbcode_class) 195 { 196 return $bbcode_class->bbcode_parse_list($match[0]); 197 } 198 )), 199 'email' => array('bbcode_id' => BBCODE_ID_EMAIL, 'regexp' => array('#\[email=?(.*?)?\](.*?)\[/email\]#uis' => function ($match) use($bbcode_class) 200 { 201 return $bbcode_class->validate_email($match[1], $match[2]); 202 } 203 )), 204 'flash' => array('bbcode_id' => BBCODE_ID_FLASH, 'regexp' => array('#\[flash=([0-9]+),([0-9]+)\](.*?)\[/flash\]#ui' => function ($match) use($bbcode_class) 205 { 206 return $bbcode_class->bbcode_flash($match[1], $match[2], $match[3]); 207 } 208 )) 209 ); 210 211 // Zero the parsed items array 212 $this->parsed_items = array(); 213 214 foreach ($this->bbcodes as $tag => $bbcode_data) 215 { 216 $this->parsed_items[$tag] = 0; 217 } 218 219 if (!$allow_custom_bbcode) 220 { 221 return; 222 } 223 224 if (!is_array($rowset)) 225 { 226 global $db; 227 $rowset = array(); 228 229 $sql = 'SELECT * 230 FROM ' . BBCODES_TABLE; 231 $result = $db->sql_query($sql); 232 233 while ($row = $db->sql_fetchrow($result)) 234 { 235 $rowset[] = $row; 236 } 237 $db->sql_freeresult($result); 238 } 239 240 foreach ($rowset as $row) 241 { 242 $this->bbcodes[$row['bbcode_tag']] = array( 243 'bbcode_id' => (int) $row['bbcode_id'], 244 'regexp' => array($row['first_pass_match'] => str_replace('$uid', $this->bbcode_uid, $row['first_pass_replace'])) 245 ); 246 } 247 248 $bbcodes = $this->bbcodes; 249 250 /** 251 * Event to modify the bbcode data for later parsing 252 * 253 * @event core.modify_bbcode_init 254 * @var array bbcodes Array of bbcode data for use in parsing 255 * @var array rowset Array of bbcode data from the database 256 * @since 3.1.0-a3 257 */ 258 $vars = array('bbcodes', 'rowset'); 259 extract($phpbb_dispatcher->trigger_event('core.modify_bbcode_init', compact($vars))); 260 261 $this->bbcodes = $bbcodes; 262 } 263 264 /** 265 * Making some pre-checks for bbcodes as well as increasing the number of parsed items 266 */ 267 function check_bbcode($bbcode, &$in) 268 { 269 // when using the /e modifier, preg_replace slashes double-quotes but does not 270 // seem to slash anything else 271 $in = str_replace("\r\n", "\n", str_replace('\"', '"', $in)); 272 273 // Trimming here to make sure no empty bbcodes are parsed accidently 274 if (trim($in) == '') 275 { 276 return false; 277 } 278 279 $this->parsed_items[$bbcode]++; 280 281 return true; 282 } 283 284 /** 285 * Transform some characters in valid bbcodes 286 */ 287 function bbcode_specialchars($text) 288 { 289 $str_from = array('<', '>', '[', ']', '.', ':'); 290 $str_to = array('<', '>', '[', ']', '.', ':'); 291 292 return str_replace($str_from, $str_to, $text); 293 } 294 295 /** 296 * Parse size tag 297 */ 298 function bbcode_size($stx, $in) 299 { 300 global $user, $config; 301 302 if (!$this->check_bbcode('size', $in)) 303 { 304 return $in; 305 } 306 307 if ($config['max_' . $this->mode . '_font_size'] && $config['max_' . $this->mode . '_font_size'] < $stx) 308 { 309 $this->warn_msg[] = $user->lang('MAX_FONT_SIZE_EXCEEDED', (int) $config['max_' . $this->mode . '_font_size']); 310 311 return '[size=' . $stx . ']' . $in . '[/size]'; 312 } 313 314 // Do not allow size=0 315 if ($stx <= 0) 316 { 317 return '[size=' . $stx . ']' . $in . '[/size]'; 318 } 319 320 return '[size=' . $stx . ':' . $this->bbcode_uid . ']' . $in . '[/size:' . $this->bbcode_uid . ']'; 321 } 322 323 /** 324 * Parse color tag 325 */ 326 function bbcode_color($stx, $in) 327 { 328 if (!$this->check_bbcode('color', $in)) 329 { 330 return $in; 331 } 332 333 return '[color=' . $stx . ':' . $this->bbcode_uid . ']' . $in . '[/color:' . $this->bbcode_uid . ']'; 334 } 335 336 /** 337 * Parse u tag 338 */ 339 function bbcode_underline($in) 340 { 341 if (!$this->check_bbcode('u', $in)) 342 { 343 return $in; 344 } 345 346 return '[u:' . $this->bbcode_uid . ']' . $in . '[/u:' . $this->bbcode_uid . ']'; 347 } 348 349 /** 350 * Parse b tag 351 */ 352 function bbcode_strong($in) 353 { 354 if (!$this->check_bbcode('b', $in)) 355 { 356 return $in; 357 } 358 359 return '[b:' . $this->bbcode_uid . ']' . $in . '[/b:' . $this->bbcode_uid . ']'; 360 } 361 362 /** 363 * Parse i tag 364 */ 365 function bbcode_italic($in) 366 { 367 if (!$this->check_bbcode('i', $in)) 368 { 369 return $in; 370 } 371 372 return '[i:' . $this->bbcode_uid . ']' . $in . '[/i:' . $this->bbcode_uid . ']'; 373 } 374 375 /** 376 * Parse img tag 377 */ 378 function bbcode_img($in) 379 { 380 global $user, $config; 381 382 if (!$this->check_bbcode('img', $in)) 383 { 384 return $in; 385 } 386 387 $in = trim($in); 388 $error = false; 389 390 $in = str_replace(' ', '%20', $in); 391 392 // Checking urls 393 if (!preg_match('#^' . get_preg_expression('url_http') . '$#iu', $in) && !preg_match('#^' . get_preg_expression('www_url') . '$#iu', $in)) 394 { 395 return '[img]' . $in . '[/img]'; 396 } 397 398 // Try to cope with a common user error... not specifying a protocol but only a subdomain 399 if (!preg_match('#^[a-z0-9]+://#i', $in)) 400 { 401 $in = 'http://' . $in; 402 } 403 404 if ($error || $this->path_in_domain($in)) 405 { 406 return '[img]' . $in . '[/img]'; 407 } 408 409 return '[img:' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($in) . '[/img:' . $this->bbcode_uid . ']'; 410 } 411 412 /** 413 * Parse flash tag 414 */ 415 function bbcode_flash($width, $height, $in) 416 { 417 global $user, $config; 418 419 if (!$this->check_bbcode('flash', $in)) 420 { 421 return $in; 422 } 423 424 $in = trim($in); 425 $error = false; 426 427 // Do not allow 0-sizes generally being entered 428 if ($width <= 0 || $height <= 0) 429 { 430 return '[flash=' . $width . ',' . $height . ']' . $in . '[/flash]'; 431 } 432 433 $in = str_replace(' ', '%20', $in); 434 435 // Make sure $in is a URL. 436 if (!preg_match('#^' . get_preg_expression('url') . '$#iu', $in) && 437 !preg_match('#^' . get_preg_expression('www_url') . '$#iu', $in)) 438 { 439 return '[flash=' . $width . ',' . $height . ']' . $in . '[/flash]'; 440 } 441 442 // Apply the same size checks on flash files as on images 443 if ($config['max_' . $this->mode . '_img_height'] || $config['max_' . $this->mode . '_img_width']) 444 { 445 if ($config['max_' . $this->mode . '_img_height'] && $config['max_' . $this->mode . '_img_height'] < $height) 446 { 447 $error = true; 448 $this->warn_msg[] = $user->lang('MAX_FLASH_HEIGHT_EXCEEDED', (int) $config['max_' . $this->mode . '_img_height']); 449 } 450 451 if ($config['max_' . $this->mode . '_img_width'] && $config['max_' . $this->mode . '_img_width'] < $width) 452 { 453 $error = true; 454 $this->warn_msg[] = $user->lang('MAX_FLASH_WIDTH_EXCEEDED', (int) $config['max_' . $this->mode . '_img_width']); 455 } 456 } 457 458 if ($error || $this->path_in_domain($in)) 459 { 460 return '[flash=' . $width . ',' . $height . ']' . $in . '[/flash]'; 461 } 462 463 return '[flash=' . $width . ',' . $height . ':' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($in) . '[/flash:' . $this->bbcode_uid . ']'; 464 } 465 466 /** 467 * Parse inline attachments [ia] 468 */ 469 function bbcode_attachment($stx, $in) 470 { 471 if (!$this->check_bbcode('attachment', $in)) 472 { 473 return $in; 474 } 475 476 return '[attachment=' . $stx . ':' . $this->bbcode_uid . ']<!-- ia' . $stx . ' -->' . trim($in) . '<!-- ia' . $stx . ' -->[/attachment:' . $this->bbcode_uid . ']'; 477 } 478 479 /** 480 * Parse code text from code tag 481 * @access private 482 */ 483 function bbcode_parse_code($stx, &$code) 484 { 485 switch (strtolower($stx)) 486 { 487 case 'php': 488 489 $remove_tags = false; 490 491 $str_from = array('<', '>', '[', ']', '.', ':', ':'); 492 $str_to = array('<', '>', '[', ']', '.', ':', ':'); 493 $code = str_replace($str_from, $str_to, $code); 494 495 if (!preg_match('/\<\?.*?\?\>/is', $code)) 496 { 497 $remove_tags = true; 498 $code = "<?php $code ?>"; 499 } 500 501 $conf = array('highlight.bg', 'highlight.comment', 'highlight.default', 'highlight.html', 'highlight.keyword', 'highlight.string'); 502 foreach ($conf as $ini_var) 503 { 504 @ini_set($ini_var, str_replace('highlight.', 'syntax', $ini_var)); 505 } 506 507 // Because highlight_string is specialcharing the text (but we already did this before), we have to reverse this in order to get correct results 508 $code = htmlspecialchars_decode($code); 509 $code = highlight_string($code, true); 510 511 $str_from = array('<span style="color: ', '<font color="syntax', '</font>', '<code>', '</code>','[', ']', '.', ':'); 512 $str_to = array('<span class="', '<span class="syntax', '</span>', '', '', '[', ']', '.', ':'); 513 514 if ($remove_tags) 515 { 516 $str_from[] = '<span class="syntaxdefault"><?php </span>'; 517 $str_to[] = ''; 518 $str_from[] = '<span class="syntaxdefault"><?php '; 519 $str_to[] = '<span class="syntaxdefault">'; 520 } 521 522 $code = str_replace($str_from, $str_to, $code); 523 $code = preg_replace('#^(<span class="[a-z_]+">)\n?(.*?)\n?(</span>)$#is', '$1$2$3', $code); 524 525 if ($remove_tags) 526 { 527 $code = preg_replace('#(<span class="[a-z]+">)?\?>(</span>)#', '$1 $2', $code); 528 } 529 530 $code = preg_replace('#^<span class="[a-z]+"><span class="([a-z]+)">(.*)</span></span>#s', '<span class="$1">$2</span>', $code); 531 $code = preg_replace('#(?:\s++| )*+</span>$#u', '</span>', $code); 532 533 // remove newline at the end 534 if (!empty($code) && substr($code, -1) == "\n") 535 { 536 $code = substr($code, 0, -1); 537 } 538 539 return "[code=$stx:" . $this->bbcode_uid . ']' . $code . '[/code:' . $this->bbcode_uid . ']'; 540 break; 541 542 default: 543 return '[code:' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($code) . '[/code:' . $this->bbcode_uid . ']'; 544 break; 545 } 546 } 547 548 /** 549 * Parse code tag 550 * Expects the argument to start right after the opening [code] tag and to end with [/code] 551 */ 552 function bbcode_code($stx, $in) 553 { 554 if (!$this->check_bbcode('code', $in)) 555 { 556 return $in; 557 } 558 559 // We remove the hardcoded elements from the code block here because it is not used in code blocks 560 // Having it here saves us one preg_replace per message containing [code] blocks 561 // Additionally, magic url parsing should go after parsing bbcodes, but for safety those are stripped out too... 562 $htm_match = get_preg_expression('bbcode_htm'); 563 unset($htm_match[4], $htm_match[5]); 564 $htm_replace = array('\1', '\1', '\2', '\1'); 565 566 $out = $code_block = ''; 567 $open = 1; 568 569 while ($in) 570 { 571 // Determine position and tag length of next code block 572 preg_match('#(.*?)(\[code(?:=([a-z]+))?\])(.+)#is', $in, $buffer); 573 $pos = (isset($buffer[1])) ? strlen($buffer[1]) : false; 574 $tag_length = (isset($buffer[2])) ? strlen($buffer[2]) : false; 575 576 // Determine position of ending code tag 577 $pos2 = stripos($in, '[/code]'); 578 579 // Which is the next block, ending code or code block 580 if ($pos !== false && $pos < $pos2) 581 { 582 // Open new block 583 if (!$open) 584 { 585 $out .= substr($in, 0, $pos); 586 $in = substr($in, $pos); 587 $stx = (isset($buffer[3])) ? $buffer[3] : ''; 588 $code_block = ''; 589 } 590 else 591 { 592 // Already opened block, just append to the current block 593 $code_block .= substr($in, 0, $pos) . ((isset($buffer[2])) ? $buffer[2] : ''); 594 $in = substr($in, $pos); 595 } 596 597 $in = substr($in, $tag_length); 598 $open++; 599 } 600 else 601 { 602 // Close the block 603 if ($open == 1) 604 { 605 $code_block .= substr($in, 0, $pos2); 606 $code_block = preg_replace($htm_match, $htm_replace, $code_block); 607 608 // Parse this code block 609 $out .= $this->bbcode_parse_code($stx, $code_block); 610 $code_block = ''; 611 $open--; 612 } 613 else if ($open) 614 { 615 // Close one open tag... add to the current code block 616 $code_block .= substr($in, 0, $pos2 + 7); 617 $open--; 618 } 619 else 620 { 621 // end code without opening code... will be always outside code block 622 $out .= substr($in, 0, $pos2 + 7); 623 } 624 625 $in = substr($in, $pos2 + 7); 626 } 627 } 628 629 // if now $code_block has contents we need to parse the remaining code while removing the last closing tag to match up. 630 if ($code_block) 631 { 632 $code_block = substr($code_block, 0, -7); 633 $code_block = preg_replace($htm_match, $htm_replace, $code_block); 634 635 $out .= $this->bbcode_parse_code($stx, $code_block); 636 } 637 638 return $out; 639 } 640 641 /** 642 * Parse list bbcode 643 * Expects the argument to start with a tag 644 */ 645 function bbcode_parse_list($in) 646 { 647 if (!$this->check_bbcode('list', $in)) 648 { 649 return $in; 650 } 651 652 // $tok holds characters to stop at. Since the string starts with a '[' we'll get everything up to the first ']' which should be the opening [list] tag 653 $tok = ']'; 654 $out = '['; 655 656 // First character is [ 657 $in = substr($in, 1); 658 $list_end_tags = $item_end_tags = array(); 659 660 do 661 { 662 $pos = strlen($in); 663 664 for ($i = 0, $tok_len = strlen($tok); $i < $tok_len; ++$i) 665 { 666 $tmp_pos = strpos($in, $tok[$i]); 667 668 if ($tmp_pos !== false && $tmp_pos < $pos) 669 { 670 $pos = $tmp_pos; 671 } 672 } 673 674 $buffer = substr($in, 0, $pos); 675 $tok = $in[$pos]; 676 677 $in = substr($in, $pos + 1); 678 679 if ($tok == ']') 680 { 681 // if $tok is ']' the buffer holds a tag 682 if (strtolower($buffer) == '/list' && count($list_end_tags)) 683 { 684 // valid [/list] tag, check nesting so that we don't hit false positives 685 if (count($item_end_tags) && count($item_end_tags) >= count($list_end_tags)) 686 { 687 // current li tag has not been closed 688 $out = preg_replace('/\n?\[$/', '[', $out) . array_pop($item_end_tags) . ']['; 689 } 690 691 $out .= array_pop($list_end_tags) . ']'; 692 $tok = '['; 693 } 694 else if (preg_match('#^list(=[0-9a-z]+)?$#i', $buffer, $m)) 695 { 696 // sub-list, add a closing tag 697 if (empty($m[1]) || preg_match('/^=(?:disc|square|circle)$/i', $m[1])) 698 { 699 array_push($list_end_tags, '/list:u:' . $this->bbcode_uid); 700 } 701 else 702 { 703 array_push($list_end_tags, '/list:o:' . $this->bbcode_uid); 704 } 705 $out .= 'list' . substr($buffer, 4) . ':' . $this->bbcode_uid . ']'; 706 $tok = '['; 707 } 708 else 709 { 710 if (($buffer == '*' || substr($buffer, -2) == '[*') && count($list_end_tags)) 711 { 712 // the buffer holds a bullet tag and we have a [list] tag open 713 if (count($item_end_tags) >= count($list_end_tags)) 714 { 715 if (substr($buffer, -2) == '[*') 716 { 717 $out .= substr($buffer, 0, -2) . '['; 718 } 719 // current li tag has not been closed 720 if (preg_match('/\n\[$/', $out, $m)) 721 { 722 $out = preg_replace('/\n\[$/', '[', $out); 723 $buffer = array_pop($item_end_tags) . "]\n[*:" . $this->bbcode_uid; 724 } 725 else 726 { 727 $buffer = array_pop($item_end_tags) . '][*:' . $this->bbcode_uid; 728 } 729 } 730 else 731 { 732 $buffer = '*:' . $this->bbcode_uid; 733 } 734 735 $item_end_tags[] = '/*:m:' . $this->bbcode_uid; 736 } 737 else if ($buffer == '/*') 738 { 739 array_pop($item_end_tags); 740 $buffer = '/*:' . $this->bbcode_uid; 741 } 742 743 $out .= $buffer . $tok; 744 $tok = '[]'; 745 } 746 } 747 else 748 { 749 // Not within a tag, just add buffer to the return string 750 $out .= $buffer . $tok; 751 $tok = ($tok == '[') ? ']' : '[]'; 752 } 753 } 754 while ($in); 755 756 // do we have some tags open? close them now 757 if (count($item_end_tags)) 758 { 759 $out .= '[' . implode('][', $item_end_tags) . ']'; 760 } 761 if (count($list_end_tags)) 762 { 763 $out .= '[' . implode('][', $list_end_tags) . ']'; 764 } 765 766 return $out; 767 } 768 769 /** 770 * Parse quote bbcode 771 * Expects the argument to start with a tag 772 */ 773 function bbcode_quote($in) 774 { 775 $in = str_replace("\r\n", "\n", str_replace('\"', '"', trim($in))); 776 777 if (!$in) 778 { 779 return ''; 780 } 781 782 // To let the parser not catch tokens within quote_username quotes we encode them before we start this... 783 $in = preg_replace_callback('#quote="(.*?)"\]#i', function ($match) { 784 return 'quote="' . str_replace(array('[', ']', '\\\"'), array('[', ']', '\"'), $match[1]) . '"]'; 785 }, $in); 786 787 $tok = ']'; 788 $out = '['; 789 790 $in = substr($in, 1); 791 $close_tags = $error_ary = array(); 792 $buffer = ''; 793 794 do 795 { 796 $pos = strlen($in); 797 for ($i = 0, $tok_len = strlen($tok); $i < $tok_len; ++$i) 798 { 799 $tmp_pos = strpos($in, $tok[$i]); 800 if ($tmp_pos !== false && $tmp_pos < $pos) 801 { 802 $pos = $tmp_pos; 803 } 804 } 805 806 $buffer .= substr($in, 0, $pos); 807 $tok = $in[$pos]; 808 $in = substr($in, $pos + 1); 809 810 if ($tok == ']') 811 { 812 if (strtolower($buffer) == '/quote' && count($close_tags) && substr($out, -1, 1) == '[') 813 { 814 // we have found a closing tag 815 $out .= array_pop($close_tags) . ']'; 816 $tok = '['; 817 $buffer = ''; 818 819 /* Add space at the end of the closing tag if not happened before to allow following urls/smilies to be parsed correctly 820 * Do not try to think for the user. :/ Do not parse urls/smilies if there is no space - is the same as with other bbcodes too. 821 * Also, we won't have any spaces within $in anyway, only adding up spaces -> #10982 822 if (!$in || $in[0] !== ' ') 823 { 824 $out .= ' '; 825 }*/ 826 } 827 else if (preg_match('#^quote(?:="(.*?)")?$#is', $buffer, $m) && substr($out, -1, 1) == '[') 828 { 829 $this->parsed_items['quote']++; 830 array_push($close_tags, '/quote:' . $this->bbcode_uid); 831 832 if (isset($m[1]) && $m[1]) 833 { 834 $username = str_replace(array('[', ']'), array('[', ']'), $m[1]); 835 $username = preg_replace('#\[(?!b|i|u|color|url|email|/b|/i|/u|/color|/url|/email)#iU', '[$1', $username); 836 837 $end_tags = array(); 838 $error = false; 839 840 preg_match_all('#\[((?:/)?(?:[a-z]+))#i', $username, $tags); 841 foreach ($tags[1] as $tag) 842 { 843 if ($tag[0] != '/') 844 { 845 $end_tags[] = '/' . $tag; 846 } 847 else 848 { 849 $end_tag = array_pop($end_tags); 850 $error = ($end_tag != $tag) ? true : false; 851 } 852 } 853 854 if ($error) 855 { 856 $username = $m[1]; 857 } 858 859 $out .= 'quote="' . $username . '":' . $this->bbcode_uid . ']'; 860 } 861 else 862 { 863 $out .= 'quote:' . $this->bbcode_uid . ']'; 864 } 865 866 $tok = '['; 867 $buffer = ''; 868 } 869 else if (preg_match('#^quote="(.*?)#is', $buffer, $m)) 870 { 871 // the buffer holds an invalid opening tag 872 $buffer .= ']'; 873 } 874 else 875 { 876 $out .= $buffer . $tok; 877 $tok = '[]'; 878 $buffer = ''; 879 } 880 } 881 else 882 { 883 /** 884 * Old quote code working fine, but having errors listed in bug #3572 885 * 886 * $out .= $buffer . $tok; 887 * $tok = ($tok == '[') ? ']' : '[]'; 888 * $buffer = ''; 889 */ 890 891 $out .= $buffer . $tok; 892 893 if ($tok == '[') 894 { 895 // Search the text for the next tok... if an ending quote comes first, then change tok to [] 896 $pos1 = stripos($in, '[/quote'); 897 // If the token ] comes first, we change it to ] 898 $pos2 = strpos($in, ']'); 899 // If the token [ comes first, we change it to [ 900 $pos3 = strpos($in, '['); 901 902 if ($pos1 !== false && ($pos2 === false || $pos1 < $pos2) && ($pos3 === false || $pos1 < $pos3)) 903 { 904 $tok = '[]'; 905 } 906 else if ($pos3 !== false && ($pos2 === false || $pos3 < $pos2)) 907 { 908 $tok = '['; 909 } 910 else 911 { 912 $tok = ']'; 913 } 914 } 915 else 916 { 917 $tok = '[]'; 918 } 919 $buffer = ''; 920 } 921 } 922 while ($in); 923 924 $out .= $buffer; 925 926 if (count($close_tags)) 927 { 928 $out .= '[' . implode('][', $close_tags) . ']'; 929 } 930 931 foreach ($error_ary as $error_msg) 932 { 933 $this->warn_msg[] = $error_msg; 934 } 935 936 return $out; 937 } 938 939 /** 940 * Validate email 941 */ 942 function validate_email($var1, $var2) 943 { 944 $var1 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var1))); 945 $var2 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var2))); 946 947 $txt = $var2; 948 $email = ($var1) ? $var1 : $var2; 949 950 $validated = true; 951 952 if (!preg_match('/^' . get_preg_expression('email') . '$/i', $email)) 953 { 954 $validated = false; 955 } 956 957 if (!$validated) 958 { 959 return '[email' . (($var1) ? "=$var1" : '') . ']' . $var2 . '[/email]'; 960 } 961 962 $this->parsed_items['email']++; 963 964 if ($var1) 965 { 966 $retval = '[email=' . $this->bbcode_specialchars($email) . ':' . $this->bbcode_uid . ']' . $txt . '[/email:' . $this->bbcode_uid . ']'; 967 } 968 else 969 { 970 $retval = '[email:' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($email) . '[/email:' . $this->bbcode_uid . ']'; 971 } 972 973 return $retval; 974 } 975 976 /** 977 * Validate url 978 * 979 * @param string $var1 optional url parameter for url bbcode: [url(=$var1)]$var2[/url] 980 * @param string $var2 url bbcode content: [url(=$var1)]$var2[/url] 981 */ 982 function validate_url($var1, $var2) 983 { 984 $var1 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var1))); 985 $var2 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var2))); 986 987 $url = ($var1) ? $var1 : $var2; 988 989 if ($var1 && !$var2) 990 { 991 $var2 = $var1; 992 } 993 994 if (!$url) 995 { 996 return '[url' . (($var1) ? '=' . $var1 : '') . ']' . $var2 . '[/url]'; 997 } 998 999 $valid = false; 1000 1001 $url = str_replace(' ', '%20', $url); 1002 1003 // Checking urls 1004 if (preg_match('#^' . get_preg_expression('url') . '$#iu', $url) || 1005 preg_match('#^' . get_preg_expression('www_url') . '$#iu', $url) || 1006 preg_match('#^' . preg_quote(generate_board_url(), '#') . get_preg_expression('relative_url') . '$#iu', $url)) 1007 { 1008 $valid = true; 1009 } 1010 1011 if ($valid) 1012 { 1013 $this->parsed_items['url']++; 1014 1015 // if there is no scheme, then add http schema 1016 if (!preg_match('#^[a-z][a-z\d+\-.]*:/{2}#i', $url)) 1017 { 1018 $url = 'http://' . $url; 1019 } 1020 1021 // Is this a link to somewhere inside this board? If so then remove the session id from the url 1022 if (strpos($url, generate_board_url()) !== false && strpos($url, 'sid=') !== false) 1023 { 1024 $url = preg_replace('/(&|\?)sid=[0-9a-f]{32}&/', '\1', $url); 1025 $url = preg_replace('/(&|\?)sid=[0-9a-f]{32}$/', '', $url); 1026 $url = append_sid($url); 1027 } 1028 1029 return ($var1) ? '[url=' . $this->bbcode_specialchars($url) . ':' . $this->bbcode_uid . ']' . $var2 . '[/url:' . $this->bbcode_uid . ']' : '[url:' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($url) . '[/url:' . $this->bbcode_uid . ']'; 1030 } 1031 1032 return '[url' . (($var1) ? '=' . $var1 : '') . ']' . $var2 . '[/url]'; 1033 } 1034 1035 /** 1036 * Check if url is pointing to this domain/script_path/php-file 1037 * 1038 * @param string $url the url to check 1039 * @return true if the url is pointing to this domain/script_path/php-file, false if not 1040 * 1041 * @access private 1042 */ 1043 function path_in_domain($url) 1044 { 1045 global $config, $phpEx, $user; 1046 1047 if ($config['force_server_vars']) 1048 { 1049 $check_path = !empty($config['script_path']) ? $config['script_path'] : '/'; 1050 } 1051 else 1052 { 1053 $check_path = ($user->page['root_script_path'] != '/') ? substr($user->page['root_script_path'], 0, -1) : '/'; 1054 } 1055 1056 // Is the user trying to link to a php file in this domain and script path? 1057 if (strpos($url, ".{$phpEx}") !== false && strpos($url, $check_path) !== false) 1058 { 1059 $server_name = $user->host; 1060 1061 // Forcing server vars is the only way to specify/override the protocol 1062 if ($config['force_server_vars'] || !$server_name) 1063 { 1064 $server_name = $config['server_name']; 1065 } 1066 1067 // Check again in correct order... 1068 $pos_ext = strpos($url, ".{$phpEx}"); 1069 $pos_path = strpos($url, $check_path); 1070 $pos_domain = strpos($url, $server_name); 1071 1072 if ($pos_domain !== false && $pos_path >= $pos_domain && $pos_ext >= $pos_path) 1073 { 1074 // Ok, actually we allow linking to some files (this may be able to be extended in some way later...) 1075 if (strpos($url, '/' . $check_path . '/download/file.' . $phpEx) !== 0) 1076 { 1077 return false; 1078 } 1079 1080 return true; 1081 } 1082 } 1083 1084 return false; 1085 } 1086 } 1087 1088 /** 1089 * Main message parser for posting, pm, etc. takes raw message 1090 * and parses it for attachments, bbcode and smilies 1091 */ 1092 class parse_message extends bbcode_firstpass 1093 { 1094 var $attachment_data = array(); 1095 var $filename_data = array(); 1096 1097 // Helps ironing out user error 1098 var $message_status = ''; 1099 1100 var $allow_img_bbcode = true; 1101 var $allow_flash_bbcode = true; 1102 var $allow_quote_bbcode = true; 1103 var $allow_url_bbcode = true; 1104 1105 var $mode; 1106 1107 /** 1108 * The plupload object used for dealing with attachments 1109 * @var \phpbb\plupload\plupload 1110 */ 1111 protected $plupload; 1112 1113 /** 1114 * Init - give message here or manually 1115 */ 1116 function __construct($message = '') 1117 { 1118 // Init BBCode UID 1119 $this->bbcode_uid = substr(base_convert(unique_id(), 16, 36), 0, BBCODE_UID_LEN); 1120 $this->message = $message; 1121 } 1122 1123 /** 1124 * Parse Message 1125 */ 1126 function parse($allow_bbcode, $allow_magic_url, $allow_smilies, $allow_img_bbcode = true, $allow_flash_bbcode = true, $allow_quote_bbcode = true, $allow_url_bbcode = true, $update_this_message = true, $mode = 'post') 1127 { 1128 global $config, $user, $phpbb_dispatcher, $phpbb_container; 1129 1130 $this->mode = $mode; 1131 1132 foreach (array('chars', 'smilies', 'urls', 'font_size', 'img_height', 'img_width') as $key) 1133 { 1134 if (!isset($config['max_' . $mode . '_' . $key])) 1135 { 1136 $config['max_' . $mode . '_' . $key] = 0; 1137 } 1138 } 1139 1140 $this->allow_img_bbcode = $allow_img_bbcode; 1141 $this->allow_flash_bbcode = $allow_flash_bbcode; 1142 $this->allow_quote_bbcode = $allow_quote_bbcode; 1143 $this->allow_url_bbcode = $allow_url_bbcode; 1144 1145 // If false, then $this->message won't be altered, the text will be returned instead. 1146 if (!$update_this_message) 1147 { 1148 $tmp_message = $this->message; 1149 $return_message = &$this->message; 1150 } 1151 1152 if ($this->message_status == 'display') 1153 { 1154 $this->decode_message(); 1155 } 1156 1157 // Store message length... 1158 $message_length = ($mode == 'post') ? utf8_strlen($this->message) : utf8_strlen(preg_replace('#\[\/?[a-z\*\+\-]+(=[\S]+)?\]#ius', ' ', $this->message)); 1159 1160 // Maximum message length check. 0 disables this check completely. 1161 if ((int) $config['max_' . $mode . '_chars'] > 0 && $message_length > (int) $config['max_' . $mode . '_chars']) 1162 { 1163 $this->warn_msg[] = $user->lang('CHARS_' . strtoupper($mode) . '_CONTAINS', $message_length) . '<br />' . $user->lang('TOO_MANY_CHARS_LIMIT', (int) $config['max_' . $mode . '_chars']); 1164 return (!$update_this_message) ? $return_message : $this->warn_msg; 1165 } 1166 1167 // Minimum message length check for post only 1168 if ($mode === 'post') 1169 { 1170 if (!$message_length || $message_length < (int) $config['min_post_chars']) 1171 { 1172 $this->warn_msg[] = (!$message_length) ? $user->lang['TOO_FEW_CHARS'] : ($user->lang('CHARS_POST_CONTAINS', $message_length) . '<br />' . $user->lang('TOO_FEW_CHARS_LIMIT', (int) $config['min_post_chars'])); 1173 return (!$update_this_message) ? $return_message : $this->warn_msg; 1174 } 1175 } 1176 1177 /** 1178 * This event can be used for additional message checks/cleanup before parsing 1179 * 1180 * @event core.message_parser_check_message 1181 * @var bool allow_bbcode Do we allow BBCodes 1182 * @var bool allow_magic_url Do we allow magic urls 1183 * @var bool allow_smilies Do we allow smilies 1184 * @var bool allow_img_bbcode Do we allow image BBCode 1185 * @var bool allow_flash_bbcode Do we allow flash BBCode 1186 * @var bool allow_quote_bbcode Do we allow quote BBCode 1187 * @var bool allow_url_bbcode Do we allow url BBCode 1188 * @var bool update_this_message Do we alter the parsed message 1189 * @var string mode Posting mode 1190 * @var string message The message text to parse 1191 * @var string bbcode_bitfield The bbcode_bitfield before parsing 1192 * @var string bbcode_uid The bbcode_uid before parsing 1193 * @var bool return Do we return after the event is triggered if $warn_msg is not empty 1194 * @var array warn_msg Array of the warning messages 1195 * @since 3.1.2-RC1 1196 * @changed 3.1.3-RC1 Added vars $bbcode_bitfield and $bbcode_uid 1197 */ 1198 $message = $this->message; 1199 $warn_msg = $this->warn_msg; 1200 $return = false; 1201 $bbcode_bitfield = $this->bbcode_bitfield; 1202 $bbcode_uid = $this->bbcode_uid; 1203 $vars = array( 1204 'allow_bbcode', 1205 'allow_magic_url', 1206 'allow_smilies', 1207 'allow_img_bbcode', 1208 'allow_flash_bbcode', 1209 'allow_quote_bbcode', 1210 'allow_url_bbcode', 1211 'update_this_message', 1212 'mode', 1213 'message', 1214 'bbcode_bitfield', 1215 'bbcode_uid', 1216 'return', 1217 'warn_msg', 1218 ); 1219 extract($phpbb_dispatcher->trigger_event('core.message_parser_check_message', compact($vars))); 1220 $this->message = $message; 1221 $this->warn_msg = $warn_msg; 1222 $this->bbcode_bitfield = $bbcode_bitfield; 1223 $this->bbcode_uid = $bbcode_uid; 1224 if ($return && !empty($this->warn_msg)) 1225 { 1226 return (!$update_this_message) ? $return_message : $this->warn_msg; 1227 } 1228 1229 // Get the parser 1230 $parser = $phpbb_container->get('text_formatter.parser'); 1231 1232 // Set the parser's options 1233 ($allow_bbcode) ? $parser->enable_bbcodes() : $parser->disable_bbcodes(); 1234 ($allow_magic_url) ? $parser->enable_magic_url() : $parser->disable_magic_url(); 1235 ($allow_smilies) ? $parser->enable_smilies() : $parser->disable_smilies(); 1236 ($allow_img_bbcode) ? $parser->enable_bbcode('img') : $parser->disable_bbcode('img'); 1237 ($allow_flash_bbcode) ? $parser->enable_bbcode('flash') : $parser->disable_bbcode('flash'); 1238 ($allow_quote_bbcode) ? $parser->enable_bbcode('quote') : $parser->disable_bbcode('quote'); 1239 ($allow_url_bbcode) ? $parser->enable_bbcode('url') : $parser->disable_bbcode('url'); 1240 1241 // Set some config values 1242 $parser->set_vars(array( 1243 'max_font_size' => $config['max_' . $this->mode . '_font_size'], 1244 'max_img_height' => $config['max_' . $this->mode . '_img_height'], 1245 'max_img_width' => $config['max_' . $this->mode . '_img_width'], 1246 'max_smilies' => $config['max_' . $this->mode . '_smilies'], 1247 'max_urls' => $config['max_' . $this->mode . '_urls'] 1248 )); 1249 1250 // Parse this message 1251 $this->message = $parser->parse(htmlspecialchars_decode($this->message, ENT_QUOTES)); 1252 1253 // Remove quotes that are nested too deep 1254 if ($config['max_quote_depth'] > 0) 1255 { 1256 $this->remove_nested_quotes($config['max_quote_depth']); 1257 } 1258 1259 // Check for "empty" message. We do not check here for maximum length, because bbcode, smilies, etc. can add to the length. 1260 // The maximum length check happened before any parsings. 1261 if ($mode === 'post' && utf8_clean_string($this->message) === '') 1262 { 1263 $this->warn_msg[] = $user->lang['TOO_FEW_CHARS']; 1264 return (!$update_this_message) ? $return_message : $this->warn_msg; 1265 } 1266 1267 // Remove quotes that are nested too deep 1268 if ($config['max_quote_depth'] > 0) 1269 { 1270 $this->message = $phpbb_container->get('text_formatter.utils')->remove_bbcode( 1271 $this->message, 1272 'quote', 1273 $config['max_quote_depth'] 1274 ); 1275 } 1276 1277 // Check for errors 1278 $errors = $parser->get_errors(); 1279 if ($errors) 1280 { 1281 foreach ($errors as $i => $args) 1282 { 1283 // Translate each error with $user->lang() 1284 $errors[$i] = call_user_func_array(array($user, 'lang'), $args); 1285 } 1286 $this->warn_msg = array_merge($this->warn_msg, $errors); 1287 1288 return (!$update_this_message) ? $return_message : $this->warn_msg; 1289 } 1290 1291 if (!$update_this_message) 1292 { 1293 unset($this->message); 1294 $this->message = $tmp_message; 1295 return $return_message; 1296 } 1297 1298 $this->message_status = 'parsed'; 1299 return false; 1300 } 1301 1302 /** 1303 * Formatting text for display 1304 */ 1305 function format_display($allow_bbcode, $allow_magic_url, $allow_smilies, $update_this_message = true) 1306 { 1307 global $phpbb_container, $phpbb_dispatcher; 1308 1309 // If false, then the parsed message get returned but internal message not processed. 1310 if (!$update_this_message) 1311 { 1312 $tmp_message = $this->message; 1313 $return_message = &$this->message; 1314 } 1315 1316 $text = $this->message; 1317 $uid = $this->bbcode_uid; 1318 1319 /** 1320 * Event to modify the text before it is parsed 1321 * 1322 * @event core.modify_format_display_text_before 1323 * @var string text The message text to parse 1324 * @var string uid The bbcode uid 1325 * @var bool allow_bbcode Do we allow bbcodes 1326 * @var bool allow_magic_url Do we allow magic urls 1327 * @var bool allow_smilies Do we allow smilies 1328 * @var bool update_this_message Do we update the internal message 1329 * with the parsed result 1330 * @since 3.1.6-RC1 1331 */ 1332 $vars = array('text', 'uid', 'allow_bbcode', 'allow_magic_url', 'allow_smilies', 'update_this_message'); 1333 extract($phpbb_dispatcher->trigger_event('core.modify_format_display_text_before', compact($vars))); 1334 1335 $this->message = $text; 1336 $this->bbcode_uid = $uid; 1337 unset($text, $uid); 1338 1339 // NOTE: message_status is unreliable for detecting unparsed text because some callers 1340 // change $this->message without resetting $this->message_status to 'plain' so we 1341 // inspect the message instead 1342 //if ($this->message_status == 'plain') 1343 if (!preg_match('/^<[rt][ >]/', $this->message)) 1344 { 1345 // Force updating message - of course. 1346 $this->parse($allow_bbcode, $allow_magic_url, $allow_smilies, $this->allow_img_bbcode, $this->allow_flash_bbcode, $this->allow_quote_bbcode, $this->allow_url_bbcode, true); 1347 } 1348 1349 // There's a bug when previewing a topic with no poll, because the empty title of the poll 1350 // gets parsed but $this->message still ends up empty. This fixes it, until a proper fix is 1351 // devised 1352 if ($this->message === '') 1353 { 1354 $this->message = $phpbb_container->get('text_formatter.parser')->parse($this->message); 1355 } 1356 1357 $this->message = $phpbb_container->get('text_formatter.renderer')->render($this->message); 1358 1359 $text = $this->message; 1360 $uid = $this->bbcode_uid; 1361 1362 /** 1363 * Event to modify the text after it is parsed 1364 * 1365 * @event core.modify_format_display_text_after 1366 * @var string text The message text to parse 1367 * @var string uid The bbcode uid 1368 * @var bool allow_bbcode Do we allow bbcodes 1369 * @var bool allow_magic_url Do we allow magic urls 1370 * @var bool allow_smilies Do we allow smilies 1371 * @var bool update_this_message Do we update the internal message 1372 * with the parsed result 1373 * @since 3.1.0-a3 1374 */ 1375 $vars = array('text', 'uid', 'allow_bbcode', 'allow_magic_url', 'allow_smilies', 'update_this_message'); 1376 extract($phpbb_dispatcher->trigger_event('core.modify_format_display_text_after', compact($vars))); 1377 1378 $this->message = $text; 1379 $this->bbcode_uid = $uid; 1380 1381 if (!$update_this_message) 1382 { 1383 unset($this->message); 1384 $this->message = $tmp_message; 1385 return $return_message; 1386 } 1387 1388 $this->message_status = 'display'; 1389 return false; 1390 } 1391 1392 /** 1393 * Decode message to be placed back into form box 1394 */ 1395 function decode_message($custom_bbcode_uid = '', $update_this_message = true) 1396 { 1397 // If false, then the parsed message get returned but internal message not processed. 1398 if (!$update_this_message) 1399 { 1400 $tmp_message = $this->message; 1401 $return_message = &$this->message; 1402 } 1403 1404 ($custom_bbcode_uid) ? decode_message($this->message, $custom_bbcode_uid) : decode_message($this->message, $this->bbcode_uid); 1405 1406 if (!$update_this_message) 1407 { 1408 unset($this->message); 1409 $this->message = $tmp_message; 1410 return $return_message; 1411 } 1412 1413 $this->message_status = 'plain'; 1414 return false; 1415 } 1416 1417 /** 1418 * Replace magic urls of form http://xxx.xxx., www.xxx. and xxx@xxx.xxx. 1419 * Cuts down displayed size of link if over 50 chars, turns absolute links 1420 * into relative versions when the server/script path matches the link 1421 */ 1422 function magic_url($server_url) 1423 { 1424 // We use the global make_clickable function 1425 $this->message = make_clickable($this->message, $server_url); 1426 } 1427 1428 /** 1429 * Parse Smilies 1430 */ 1431 function smilies($max_smilies = 0) 1432 { 1433 global $db, $user; 1434 static $match; 1435 static $replace; 1436 1437 // See if the static arrays have already been filled on an earlier invocation 1438 if (!is_array($match)) 1439 { 1440 $match = $replace = array(); 1441 1442 // NOTE: obtain_* function? chaching the table contents? 1443 1444 // For now setting the ttl to 10 minutes 1445 switch ($db->get_sql_layer()) 1446 { 1447 case 'mssql_odbc': 1448 case 'mssqlnative': 1449 $sql = 'SELECT * 1450 FROM ' . SMILIES_TABLE . ' 1451 ORDER BY LEN(code) DESC'; 1452 break; 1453 1454 // LENGTH supported by MySQL, IBM DB2, Oracle and Access for sure... 1455 default: 1456 $sql = 'SELECT * 1457 FROM ' . SMILIES_TABLE . ' 1458 ORDER BY LENGTH(code) DESC'; 1459 break; 1460 } 1461 $result = $db->sql_query($sql, 600); 1462 1463 while ($row = $db->sql_fetchrow($result)) 1464 { 1465 if (empty($row['code'])) 1466 { 1467 continue; 1468 } 1469 1470 // (assertion) 1471 $match[] = preg_quote($row['code'], '#'); 1472 $replace[] = '<!-- s' . $row['code'] . ' --><img src="{SMILIES_PATH}/' . $row['smiley_url'] . '" alt="' . $row['code'] . '" title="' . $row['emotion'] . '" /><!-- s' . $row['code'] . ' -->'; 1473 } 1474 $db->sql_freeresult($result); 1475 } 1476 1477 if (count($match)) 1478 { 1479 if ($max_smilies) 1480 { 1481 // 'u' modifier has been added to correctly parse smilies within unicode strings 1482 // For details: http://tracker.phpbb.com/browse/PHPBB3-10117 1483 $num_matches = preg_match_all('#(?<=^|[\n .])(?:' . implode('|', $match) . ')(?![^<>]*>)#u', $this->message, $matches); 1484 unset($matches); 1485 1486 if ($num_matches !== false && $num_matches > $max_smilies) 1487 { 1488 $this->warn_msg[] = sprintf($user->lang['TOO_MANY_SMILIES'], $max_smilies); 1489 return; 1490 } 1491 } 1492 1493 // Make sure the delimiter # is added in front and at the end of every element within $match 1494 // 'u' modifier has been added to correctly parse smilies within unicode strings 1495 // For details: http://tracker.phpbb.com/browse/PHPBB3-10117 1496 1497 $this->message = trim(preg_replace(explode(chr(0), '#(?<=^|[\n .])' . implode('(?![^<>]*>)#u' . chr(0) . '#(?<=^|[\n .])', $match) . '(?![^<>]*>)#u'), $replace, $this->message)); 1498 } 1499 } 1500 1501 /** 1502 * Check attachment form token depending on submit type 1503 * 1504 * @param \phpbb\language\language $language Language 1505 * @param \phpbb\request\request_interface $request Request 1506 * @param string $form_name Form name for checking form key 1507 * 1508 * @return bool True if form token is not needed or valid, false if needed and invalid 1509 */ 1510 function check_attachment_form_token(\phpbb\language\language $language, \phpbb\request\request_interface $request, $form_name) 1511 { 1512 $add_file = $request->is_set_post('add_file'); 1513 $delete_file = $request->is_set_post('delete_file'); 1514 1515 if (($add_file || $delete_file) && !check_form_key($form_name)) 1516 { 1517 $this->warn_msg[] = $language->lang('FORM_INVALID'); 1518 1519 if ($request->is_ajax() && $this->plupload) 1520 { 1521 $this->plupload->emit_error(-400, 'FORM_INVALID'); 1522 } 1523 1524 return false; 1525 } 1526 1527 return true; 1528 } 1529 1530 /** 1531 * Parse Attachments 1532 */ 1533 function parse_attachments($form_name, $mode, $forum_id, $submit, $preview, $refresh, $is_message = false) 1534 { 1535 global $config, $auth, $user, $phpbb_root_path, $phpEx, $db, $request; 1536 global $phpbb_container, $phpbb_dispatcher; 1537 1538 $error = array(); 1539 1540 $num_attachments = count($this->attachment_data); 1541 $this->filename_data['filecomment'] = $request->variable('filecomment', '', true); 1542 $upload = $request->file($form_name); 1543 $upload_file = (!empty($upload) && $upload['name'] !== 'none' && trim($upload['name'])); 1544 1545 $add_file = (isset($_POST['add_file'])) ? true : false; 1546 $delete_file = (isset($_POST['delete_file'])) ? true : false; 1547 1548 // First of all adjust comments if changed 1549 $actual_comment_list = $request->variable('comment_list', array(''), true); 1550 1551 foreach ($actual_comment_list as $comment_key => $comment) 1552 { 1553 if (!isset($this->attachment_data[$comment_key])) 1554 { 1555 continue; 1556 } 1557 1558 if ($this->attachment_data[$comment_key]['attach_comment'] != $actual_comment_list[$comment_key]) 1559 { 1560 $this->attachment_data[$comment_key]['attach_comment'] = $actual_comment_list[$comment_key]; 1561 } 1562 } 1563 1564 $cfg = array(); 1565 $cfg['max_attachments'] = ($is_message) ? $config['max_attachments_pm'] : $config['max_attachments']; 1566 $forum_id = ($is_message) ? 0 : $forum_id; 1567 1568 if ($submit && in_array($mode, array('post', 'reply', 'quote', 'edit')) && $upload_file) 1569 { 1570 if ($num_attachments < $cfg['max_attachments'] || $auth->acl_get('a_') || $auth->acl_get('m_', $forum_id)) 1571 { 1572 /** @var \phpbb\attachment\manager $attachment_manager */ 1573 $attachment_manager = $phpbb_container->get('attachment.manager'); 1574 $filedata = $attachment_manager->upload($form_name, $forum_id, false, '', $is_message); 1575 $error = $filedata['error']; 1576 1577 if ($filedata['post_attach'] && !count($error)) 1578 { 1579 $sql_ary = array( 1580 'physical_filename' => $filedata['physical_filename'], 1581 'attach_comment' => $this->filename_data['filecomment'], 1582 'real_filename' => $filedata['real_filename'], 1583 'extension' => $filedata['extension'], 1584 'mimetype' => $filedata['mimetype'], 1585 'filesize' => $filedata['filesize'], 1586 'filetime' => $filedata['filetime'], 1587 'thumbnail' => $filedata['thumbnail'], 1588 'is_orphan' => 1, 1589 'in_message' => ($is_message) ? 1 : 0, 1590 'poster_id' => $user->data['user_id'], 1591 ); 1592 1593 /** 1594 * Modify attachment sql array on submit 1595 * 1596 * @event core.modify_attachment_sql_ary_on_submit 1597 * @var array sql_ary Array containing SQL data 1598 * @since 3.2.6-RC1 1599 */ 1600 $vars = array('sql_ary'); 1601 extract($phpbb_dispatcher->trigger_event('core.modify_attachment_sql_ary_on_submit', compact($vars))); 1602 1603 $db->sql_query('INSERT INTO ' . ATTACHMENTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); 1604 1605 $new_entry = array( 1606 'attach_id' => $db->sql_nextid(), 1607 'is_orphan' => 1, 1608 'real_filename' => $filedata['real_filename'], 1609 'attach_comment'=> $this->filename_data['filecomment'], 1610 'filesize' => $filedata['filesize'], 1611 ); 1612 1613 $this->attachment_data = array_merge(array(0 => $new_entry), $this->attachment_data); 1614 1615 /** 1616 * Modify attachment data on submit 1617 * 1618 * @event core.modify_attachment_data_on_submit 1619 * @var array attachment_data Array containing attachment data 1620 * @since 3.2.2-RC1 1621 */ 1622 $attachment_data = $this->attachment_data; 1623 $vars = array('attachment_data'); 1624 extract($phpbb_dispatcher->trigger_event('core.modify_attachment_data_on_submit', compact($vars))); 1625 $this->attachment_data = $attachment_data; 1626 unset($attachment_data); 1627 1628 $this->message = preg_replace_callback('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#', function ($match) { 1629 return '[attachment='.($match[1] + 1).']' . $match[2] . '[/attachment]'; 1630 }, $this->message); 1631 1632 $this->filename_data['filecomment'] = ''; 1633 1634 // This Variable is set to false here, because Attachments are entered into the 1635 // Database in two modes, one if the id_list is 0 and the second one if post_attach is true 1636 // Since post_attach is automatically switched to true if an Attachment got added to the filesystem, 1637 // but we are assigning an id of 0 here, we have to reset the post_attach variable to false. 1638 // 1639 // This is very relevant, because it could happen that the post got not submitted, but we do not 1640 // know this circumstance here. We could be at the posting page or we could be redirected to the entered 1641 // post. :) 1642 $filedata['post_attach'] = false; 1643 } 1644 } 1645 else 1646 { 1647 $error[] = $user->lang('TOO_MANY_ATTACHMENTS', (int) $cfg['max_attachments']); 1648 } 1649 } 1650 1651 if ($preview || $refresh || count($error)) 1652 { 1653 if (isset($this->plupload) && $this->plupload->is_active()) 1654 { 1655 $json_response = new \phpbb\json_response(); 1656 } 1657 1658 // Perform actions on temporary attachments 1659 if ($delete_file) 1660 { 1661 include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx); 1662 1663 $index = array_keys($request->variable('delete_file', array(0 => 0))); 1664 $index = (!empty($index)) ? $index[0] : false; 1665 1666 if ($index !== false && !empty($this->attachment_data[$index])) 1667 { 1668 /** @var \phpbb\attachment\manager $attachment_manager */ 1669 $attachment_manager = $phpbb_container->get('attachment.manager'); 1670 1671 // delete selected attachment 1672 if ($this->attachment_data[$index]['is_orphan']) 1673 { 1674 $sql = 'SELECT attach_id, physical_filename, thumbnail 1675 FROM ' . ATTACHMENTS_TABLE . ' 1676 WHERE attach_id = ' . (int) $this->attachment_data[$index]['attach_id'] . ' 1677 AND is_orphan = 1 1678 AND poster_id = ' . $user->data['user_id']; 1679 $result = $db->sql_query($sql); 1680 $row = $db->sql_fetchrow($result); 1681 $db->sql_freeresult($result); 1682 1683 if ($row) 1684 { 1685 $attachment_manager->unlink($row['physical_filename'], 'file'); 1686 1687 if ($row['thumbnail']) 1688 { 1689 $attachment_manager->unlink($row['physical_filename'], 'thumbnail'); 1690 } 1691 1692 $db->sql_query('DELETE FROM ' . ATTACHMENTS_TABLE . ' WHERE attach_id = ' . (int) $this->attachment_data[$index]['attach_id']); 1693 } 1694 } 1695 else 1696 { 1697 $attachment_manager->delete('attach', $this->attachment_data[$index]['attach_id']); 1698 } 1699 1700 unset($this->attachment_data[$index]); 1701 $this->message = preg_replace_callback('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#', function ($match) use($index) { 1702 return ($match[1] == $index) ? '' : (($match[1] > $index) ? '[attachment=' . ($match[1] - 1) . ']' . $match[2] . '[/attachment]' : $match[0]); 1703 }, $this->message); 1704 1705 // Reindex Array 1706 $this->attachment_data = array_values($this->attachment_data); 1707 if (isset($this->plupload) && $this->plupload->is_active()) 1708 { 1709 $json_response->send($this->attachment_data); 1710 } 1711 } 1712 } 1713 else if (($add_file || $preview) && $upload_file) 1714 { 1715 if ($num_attachments < $cfg['max_attachments'] || $auth->acl_gets('m_', 'a_', $forum_id)) 1716 { 1717 /** @var \phpbb\attachment\manager $attachment_manager */ 1718 $attachment_manager = $phpbb_container->get('attachment.manager'); 1719 $filedata = $attachment_manager->upload($form_name, $forum_id, false, '', $is_message); 1720 $error = array_merge($error, $filedata['error']); 1721 1722 if (!count($error)) 1723 { 1724 $sql_ary = array( 1725 'physical_filename' => $filedata['physical_filename'], 1726 'attach_comment' => $this->filename_data['filecomment'], 1727 'real_filename' => $filedata['real_filename'], 1728 'extension' => $filedata['extension'], 1729 'mimetype' => $filedata['mimetype'], 1730 'filesize' => $filedata['filesize'], 1731 'filetime' => $filedata['filetime'], 1732 'thumbnail' => $filedata['thumbnail'], 1733 'is_orphan' => 1, 1734 'in_message' => ($is_message) ? 1 : 0, 1735 'poster_id' => $user->data['user_id'], 1736 ); 1737 1738 /** 1739 * Modify attachment sql array on upload 1740 * 1741 * @event core.modify_attachment_sql_ary_on_upload 1742 * @var array sql_ary Array containing SQL data 1743 * @since 3.2.6-RC1 1744 */ 1745 $vars = array('sql_ary'); 1746 extract($phpbb_dispatcher->trigger_event('core.modify_attachment_sql_ary_on_upload', compact($vars))); 1747 1748 $db->sql_query('INSERT INTO ' . ATTACHMENTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); 1749 1750 $new_entry = array( 1751 'attach_id' => $db->sql_nextid(), 1752 'is_orphan' => 1, 1753 'real_filename' => $filedata['real_filename'], 1754 'attach_comment'=> $this->filename_data['filecomment'], 1755 'filesize' => $filedata['filesize'], 1756 ); 1757 1758 $this->attachment_data = array_merge(array(0 => $new_entry), $this->attachment_data); 1759 1760 /** 1761 * Modify attachment data on upload 1762 * 1763 * @event core.modify_attachment_data_on_upload 1764 * @var array attachment_data Array containing attachment data 1765 * @since 3.2.2-RC1 1766 */ 1767 $attachment_data = $this->attachment_data; 1768 $vars = array('attachment_data'); 1769 extract($phpbb_dispatcher->trigger_event('core.modify_attachment_data_on_upload', compact($vars))); 1770 $this->attachment_data = $attachment_data; 1771 unset($attachment_data); 1772 1773 $this->message = preg_replace_callback('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#', function ($match) { 1774 return '[attachment=' . ($match[1] + 1) . ']' . $match[2] . '[/attachment]'; 1775 }, $this->message); 1776 $this->filename_data['filecomment'] = ''; 1777 1778 if (isset($this->plupload) && $this->plupload->is_active()) 1779 { 1780 $download_url = append_sid("{$phpbb_root_path}download/file.{$phpEx}", 'mode=view&id=' . $new_entry['attach_id']); 1781 1782 // Send the client the attachment data to maintain state 1783 $json_response->send(array('data' => $this->attachment_data, 'download_url' => $download_url)); 1784 } 1785 } 1786 } 1787 else 1788 { 1789 $error[] = $user->lang('TOO_MANY_ATTACHMENTS', (int) $cfg['max_attachments']); 1790 } 1791 1792 if (!empty($error) && isset($this->plupload) && $this->plupload->is_active()) 1793 { 1794 // If this is a plupload (and thus ajax) request, give the 1795 // client the first error we have 1796 $json_response->send(array( 1797 'jsonrpc' => '2.0', 1798 'id' => 'id', 1799 'error' => array( 1800 'code' => 105, 1801 'message' => current($error), 1802 ), 1803 )); 1804 } 1805 } 1806 } 1807 1808 foreach ($error as $error_msg) 1809 { 1810 $this->warn_msg[] = $error_msg; 1811 } 1812 } 1813 1814 /** 1815 * Get Attachment Data 1816 */ 1817 function get_submitted_attachment_data($check_user_id = false) 1818 { 1819 global $user, $db; 1820 global $request; 1821 1822 $this->filename_data['filecomment'] = $request->variable('filecomment', '', true); 1823 $attachment_data = $request->variable('attachment_data', array(0 => array('' => '')), true, \phpbb\request\request_interface::POST); 1824 $this->attachment_data = array(); 1825 1826 $check_user_id = ($check_user_id === false) ? $user->data['user_id'] : $check_user_id; 1827 1828 if (!count($attachment_data)) 1829 { 1830 return; 1831 } 1832 1833 $not_orphan = $orphan = array(); 1834 1835 foreach ($attachment_data as $pos => $var_ary) 1836 { 1837 if ($var_ary['is_orphan']) 1838 { 1839 $orphan[(int) $var_ary['attach_id']] = $pos; 1840 } 1841 else 1842 { 1843 $not_orphan[(int) $var_ary['attach_id']] = $pos; 1844 } 1845 } 1846 1847 // Regenerate already posted attachments 1848 if (count($not_orphan)) 1849 { 1850 // Get the attachment data, based on the poster id... 1851 $sql = 'SELECT attach_id, is_orphan, real_filename, attach_comment, filesize 1852 FROM ' . ATTACHMENTS_TABLE . ' 1853 WHERE ' . $db->sql_in_set('attach_id', array_keys($not_orphan)) . ' 1854 AND poster_id = ' . $check_user_id; 1855 $result = $db->sql_query($sql); 1856 1857 while ($row = $db->sql_fetchrow($result)) 1858 { 1859 $pos = $not_orphan[$row['attach_id']]; 1860 $this->attachment_data[$pos] = $row; 1861 $this->attachment_data[$pos]['attach_comment'] = $attachment_data[$pos]['attach_comment']; 1862 1863 unset($not_orphan[$row['attach_id']]); 1864 } 1865 $db->sql_freeresult($result); 1866 } 1867 1868 if (count($not_orphan)) 1869 { 1870 trigger_error('NO_ACCESS_ATTACHMENT', E_USER_ERROR); 1871 } 1872 1873 // Regenerate newly uploaded attachments 1874 if (count($orphan)) 1875 { 1876 $sql = 'SELECT attach_id, is_orphan, real_filename, attach_comment, filesize 1877 FROM ' . ATTACHMENTS_TABLE . ' 1878 WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan)) . ' 1879 AND poster_id = ' . $user->data['user_id'] . ' 1880 AND is_orphan = 1'; 1881 $result = $db->sql_query($sql); 1882 1883 while ($row = $db->sql_fetchrow($result)) 1884 { 1885 $pos = $orphan[$row['attach_id']]; 1886 $this->attachment_data[$pos] = $row; 1887 $this->attachment_data[$pos]['attach_comment'] = $attachment_data[$pos]['attach_comment']; 1888 1889 unset($orphan[$row['attach_id']]); 1890 } 1891 $db->sql_freeresult($result); 1892 } 1893 1894 if (count($orphan)) 1895 { 1896 trigger_error('NO_ACCESS_ATTACHMENT', E_USER_ERROR); 1897 } 1898 1899 ksort($this->attachment_data); 1900 } 1901 1902 /** 1903 * Parse Poll 1904 */ 1905 function parse_poll(&$poll) 1906 { 1907 global $user, $config; 1908 1909 $poll_max_options = $poll['poll_max_options']; 1910 1911 // Parse Poll Option text 1912 $tmp_message = $this->message; 1913 1914 $poll['poll_options'] = preg_split('/\s*?\n\s*/', trim($poll['poll_option_text'])); 1915 $poll['poll_options_size'] = count($poll['poll_options']); 1916 1917 foreach ($poll['poll_options'] as &$poll_option) 1918 { 1919 $this->message = $poll_option; 1920 $poll_option = $this->parse($poll['enable_bbcode'], ($config['allow_post_links']) ? $poll['enable_urls'] : false, $poll['enable_smilies'], $poll['img_status'], false, false, $config['allow_post_links'], false, 'poll'); 1921 } 1922 unset($poll_option); 1923 $poll['poll_option_text'] = implode("\n", $poll['poll_options']); 1924 1925 // Parse Poll Title 1926 $this->message = $poll['poll_title']; 1927 if (!$poll['poll_title'] && $poll['poll_options_size']) 1928 { 1929 $this->warn_msg[] = $user->lang['NO_POLL_TITLE']; 1930 } 1931 else 1932 { 1933 if (utf8_strlen(preg_replace('#\[\/?[a-z\*\+\-]+(=[\S]+)?\]#ius', ' ', $this->message)) > 100) 1934 { 1935 $this->warn_msg[] = $user->lang['POLL_TITLE_TOO_LONG']; 1936 } 1937 $poll['poll_title'] = $this->parse($poll['enable_bbcode'], ($config['allow_post_links']) ? $poll['enable_urls'] : false, $poll['enable_smilies'], $poll['img_status'], false, false, $config['allow_post_links'], false, 'poll'); 1938 if (strlen($poll['poll_title']) > 255) 1939 { 1940 $this->warn_msg[] = $user->lang['POLL_TITLE_COMP_TOO_LONG']; 1941 } 1942 } 1943 1944 if (count($poll['poll_options']) == 1) 1945 { 1946 $this->warn_msg[] = $user->lang['TOO_FEW_POLL_OPTIONS']; 1947 } 1948 else if ($poll['poll_options_size'] > (int) $config['max_poll_options']) 1949 { 1950 $this->warn_msg[] = $user->lang['TOO_MANY_POLL_OPTIONS']; 1951 } 1952 else if ($poll_max_options > $poll['poll_options_size']) 1953 { 1954 $this->warn_msg[] = $user->lang['TOO_MANY_USER_OPTIONS']; 1955 } 1956 1957 $poll['poll_max_options'] = ($poll['poll_max_options'] < 1) ? 1 : (($poll['poll_max_options'] > $config['max_poll_options']) ? $config['max_poll_options'] : $poll['poll_max_options']); 1958 1959 $this->message = $tmp_message; 1960 } 1961 1962 /** 1963 * Remove nested quotes at given depth in current parsed message 1964 * 1965 * @param integer $max_depth Depth limit 1966 * @return null 1967 */ 1968 public function remove_nested_quotes($max_depth) 1969 { 1970 global $phpbb_container; 1971 1972 if (preg_match('#^<[rt][ >]#', $this->message)) 1973 { 1974 $this->message = $phpbb_container->get('text_formatter.utils')->remove_bbcode( 1975 $this->message, 1976 'quote', 1977 $max_depth 1978 ); 1979 1980 return; 1981 } 1982 1983 // Capture all [quote] and [/quote] tags 1984 preg_match_all('(\\[/?quote(?:="(.*?)")?:' . $this->bbcode_uid . '\\])', $this->message, $matches, PREG_OFFSET_CAPTURE); 1985 1986 // Iterate over the quote tags to mark the ranges that must be removed 1987 $depth = 0; 1988 $ranges = array(); 1989 $start_pos = 0; 1990 foreach ($matches[0] as $match) 1991 { 1992 if ($match[0][1] === '/') 1993 { 1994 --$depth; 1995 if ($depth == $max_depth) 1996 { 1997 $end_pos = $match[1] + strlen($match[0]); 1998 $length = $end_pos - $start_pos; 1999 $ranges[] = array($start_pos, $length); 2000 } 2001 } 2002 else 2003 { 2004 ++$depth; 2005 if ($depth == $max_depth + 1) 2006 { 2007 $start_pos = $match[1]; 2008 } 2009 } 2010 } 2011 2012 foreach (array_reverse($ranges) as $range) 2013 { 2014 list($start_pos, $length) = $range; 2015 $this->message = substr_replace($this->message, '', $start_pos, $length); 2016 } 2017 } 2018 2019 /** 2020 * Setter function for passing the plupload object 2021 * 2022 * @param \phpbb\plupload\plupload $plupload The plupload object 2023 * 2024 * @return null 2025 */ 2026 public function set_plupload(\phpbb\plupload\plupload $plupload) 2027 { 2028 $this->plupload = $plupload; 2029 } 2030 2031 /** 2032 * Function to perform custom bbcode validation by extensions 2033 * can be used in bbcode_init() to assign regexp replacement 2034 * Example: 'regexp' => array('#\[b\](.*?)\[/b\]#uise' => "\$this->validate_bbcode_by_extension('\$1')") 2035 * 2036 * Accepts variable number of parameters 2037 * 2038 * @return mixed Validation result 2039 */ 2040 public function validate_bbcode_by_extension() 2041 { 2042 global $phpbb_dispatcher; 2043 2044 $return = false; 2045 $params_array = func_get_args(); 2046 2047 /** 2048 * Event to validate bbcode with the custom validating methods 2049 * provided by extensions 2050 * 2051 * @event core.validate_bbcode_by_extension 2052 * @var array params_array Array with the function parameters 2053 * @var mixed return Validation result to return 2054 * 2055 * @since 3.1.5-RC1 2056 */ 2057 $vars = array('params_array', 'return'); 2058 extract($phpbb_dispatcher->trigger_event('core.validate_bbcode_by_extension', compact($vars))); 2059 2060 return $return; 2061 } 2062 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Nov 11 20:33:01 2020 | Cross-referenced by PHPXref 0.7.1 |