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