[ Index ]

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


Generated: Sun Feb 19 19:47:08 2017 Cross-referenced by PHPXref 0.7.1