[ Index ]

PHP Cross Reference of phpBB-3.1.12-deutsch

title

Body

[close]

/includes/ -> message_parser.php (source)

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


Generated: Thu Jan 11 00:25:41 2018 Cross-referenced by PHPXref 0.7.1