Verzeichnisstruktur phpBB-3.0.0


Veröffentlicht
12.12.2007

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

      (Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

message_parser.php

Zuletzt modifiziert: 09.10.2024, 12:50 - Dateigröße: 46.42 KiB


 0001  <?php
 0002  /**
 0003  *
 0004  * @package phpBB3
 0005  * @version $Id$
 0006  * @copyright (c) 2005 phpBB Group
 0007  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 0008  *
 0009  */
 0010   
 0011  /**
 0012  * @ignore
 0013  */
 0014  if (!defined('IN_PHPBB'))
 0015  {
 0016      exit;
 0017  }
 0018   
 0019  if (!class_exists('bbcode'))
 0020  {
 0021      include($phpbb_root_path . 'includes/bbcode.' . $phpEx);
 0022  }
 0023   
 0024  /**
 0025  * BBCODE FIRSTPASS
 0026  * BBCODE first pass class (functions for parsing messages for db storage)
 0027  * @package phpBB3
 0028  */
 0029  class bbcode_firstpass extends bbcode
 0030  {
 0031      var $message = '';
 0032      var $warn_msg = array();
 0033      var $parsed_items = array();
 0034   
 0035      /**
 0036      * Parse BBCode
 0037      */
 0038      function parse_bbcode()
 0039      {
 0040          if (!$this->bbcodes)
 0041          {
 0042              $this->bbcode_init();
 0043          }
 0044   
 0045          global $user;
 0046   
 0047          $this->bbcode_bitfield = '';
 0048          $bitfield = new bitfield();
 0049   
 0050          foreach ($this->bbcodes as $bbcode_name => $bbcode_data)
 0051          {
 0052              if (isset($bbcode_data['disabled']) && $bbcode_data['disabled'])
 0053              {
 0054                  foreach ($bbcode_data['regexp'] as $regexp => $replacement)
 0055                  {
 0056                      if (preg_match($regexp, $this->message))
 0057                      {
 0058                          $this->warn_msg[] = sprintf($user->lang['UNAUTHORISED_BBCODE'] , '[' . $bbcode_name . ']');
 0059                          continue;
 0060                      }
 0061                  }
 0062              }
 0063              else
 0064              {
 0065                  foreach ($bbcode_data['regexp'] as $regexp => $replacement)
 0066                  {
 0067                      // The pattern gets compiled and cached by the PCRE extension,
 0068                      // it should not demand recompilation
 0069                      if (preg_match($regexp, $this->message))
 0070                      {
 0071                          $this->message = preg_replace($regexp, $replacement, $this->message);
 0072                          $bitfield->set($bbcode_data['bbcode_id']);
 0073                      }
 0074                  }
 0075              }
 0076          }
 0077   
 0078          $this->bbcode_bitfield = $bitfield->get_base64();
 0079      }
 0080   
 0081      /**
 0082      * Prepare some bbcodes for better parsing
 0083      */
 0084      function prepare_bbcodes()
 0085      {
 0086          // 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".
 0087          // Fine by me ;) Will ease our live... but do not come back and cry at us, we won't hear you.
 0088   
 0089          /* Add newline at the end and in front of each quote block to prevent parsing errors (urls, smilies, etc.)
 0090          if (strpos($this->message, '[quote') !== false && strpos($this->message, '[/quote]') !== false)
 0091          {
 0092              $this->message = str_replace("\r\n", "\n", $this->message);
 0093   
 0094              // We strip newlines and spaces after and before quotes in quotes (trimming) and then add exactly one newline
 0095              $this->message = preg_replace('#\[quote(=&quot;.*?&quot;)?\]\s*(.*?)\s*\[/quote\]#siu', '[quote\1]' . "\n" . '\2' ."\n[/quote]", $this->message);
 0096          }
 0097          */
 0098   
 0099          // Add other checks which needs to be placed before actually parsing anything (be it bbcodes, smilies, urls...)
 0100      }
 0101   
 0102      /**
 0103      * Init bbcode data for later parsing
 0104      */
 0105      function bbcode_init()
 0106      {
 0107          static $rowset;
 0108   
 0109          // This array holds all bbcode data. BBCodes will be processed in this
 0110          // order, so it is important to keep [code] in first position and
 0111          // [quote] in second position.
 0112          $this->bbcodes = array(
 0113              'code'            => array('bbcode_id' => 8,    'regexp' => array('#\[code(?:=([a-z]+))?\](.+\[/code\])#ise' => "\$this->bbcode_code('\$1', '\$2')")),
 0114              'quote'            => array('bbcode_id' => 0,    'regexp' => array('#\[quote(?:=&quot;(.*?)&quot;)?\](.+)\[/quote\]#ise' => "\$this->bbcode_quote('\$0')")),
 0115              'attachment'    => array('bbcode_id' => 12,    'regexp' => array('#\[attachment=([0-9]+)\](.*?)\[/attachment\]#ise' => "\$this->bbcode_attachment('\$1', '\$2')")),
 0116              'b'                => array('bbcode_id' => 1,    'regexp' => array('#\[b\](.*?)\[/b\]#ise' => "\$this->bbcode_strong('\$1')")),
 0117              'i'                => array('bbcode_id' => 2,    'regexp' => array('#\[i\](.*?)\[/i\]#ise' => "\$this->bbcode_italic('\$1')")),
 0118              'url'            => array('bbcode_id' => 3,    'regexp' => array('#\[url(=(.*))?\](.*)\[/url\]#iUe' => "\$this->validate_url('\$2', '\$3')")),
 0119              'img'            => array('bbcode_id' => 4,    'regexp' => array('#\[img\](.*)\[/img\]#iUe' => "\$this->bbcode_img('\$1')")),
 0120              'size'            => array('bbcode_id' => 5,    'regexp' => array('#\[size=([\-\+]?\d+)\](.*?)\[/size\]#ise' => "\$this->bbcode_size('\$1', '\$2')")),
 0121              'color'            => array('bbcode_id' => 6,    'regexp' => array('!\[color=(#[0-9a-f]{6}|[a-z\-]+)\](.*?)\[/color\]!ise' => "\$this->bbcode_color('\$1', '\$2')")),
 0122              'u'                => array('bbcode_id' => 7,    'regexp' => array('#\[u\](.*?)\[/u\]#ise' => "\$this->bbcode_underline('\$1')")),
 0123              'list'            => array('bbcode_id' => 9,    'regexp' => array('#\[list(?:=(?:[a-z0-9]|disc|circle|square))?].*\[/list]#ise' => "\$this->bbcode_parse_list('\$0')")),
 0124              'email'            => array('bbcode_id' => 10,    'regexp' => array('#\[email=?(.*?)?\](.*?)\[/email\]#ise' => "\$this->validate_email('\$1', '\$2')")),
 0125              'flash'            => array('bbcode_id' => 11,    'regexp' => array('#\[flash=([0-9]+),([0-9]+)\](.*?)\[/flash\]#ie' => "\$this->bbcode_flash('\$1', '\$2', '\$3')"))
 0126          );
 0127   
 0128          // Zero the parsed items array
 0129          $this->parsed_items = array();
 0130   
 0131          foreach ($this->bbcodes as $tag => $bbcode_data)
 0132          {
 0133              $this->parsed_items[$tag] = 0;
 0134          }
 0135   
 0136          if (!is_array($rowset))
 0137          {
 0138              global $db;
 0139              $rowset = array();
 0140   
 0141              $sql = 'SELECT *
 0142                  FROM ' . BBCODES_TABLE;
 0143              $result = $db->sql_query($sql);
 0144   
 0145              while ($row = $db->sql_fetchrow($result))
 0146              {
 0147                  $rowset[] = $row;
 0148              }
 0149              $db->sql_freeresult($result);
 0150          }
 0151   
 0152          foreach ($rowset as $row)
 0153          {
 0154              $this->bbcodes[$row['bbcode_tag']] = array(
 0155                  'bbcode_id'    => (int) $row['bbcode_id'],
 0156                  'regexp'    => array($row['first_pass_match'] => str_replace('$uid', $this->bbcode_uid, $row['first_pass_replace']))
 0157              );
 0158          }
 0159      }
 0160   
 0161      /**
 0162      * Making some pre-checks for bbcodes as well as increasing the number of parsed items
 0163      */
 0164      function check_bbcode($bbcode, &$in)
 0165      {
 0166          // when using the /e modifier, preg_replace slashes double-quotes but does not
 0167          // seem to slash anything else
 0168          $in = str_replace("\r\n", "\n", str_replace('\"', '"', $in));
 0169   
 0170          // Trimming here to make sure no empty bbcodes are parsed accidently
 0171          if (trim($in) == '')
 0172          {
 0173              return false;
 0174          }
 0175   
 0176          $this->parsed_items[$bbcode]++;
 0177   
 0178          return true;
 0179      }
 0180   
 0181      /**
 0182      * Transform some characters in valid bbcodes
 0183      */
 0184      function bbcode_specialchars($text)
 0185      {
 0186          $str_from = array('<', '>', '[', ']', '.', ':');
 0187          $str_to = array('&lt;', '&gt;', '&#91;', '&#93;', '&#46;', '&#58;');
 0188   
 0189          return str_replace($str_from, $str_to, $text);
 0190      }
 0191   
 0192      /**
 0193      * Parse size tag
 0194      */
 0195      function bbcode_size($stx, $in)
 0196      {
 0197          global $user, $config;
 0198   
 0199          if (!$this->check_bbcode('size', $in))
 0200          {
 0201              return '';
 0202          }
 0203   
 0204          if ($config['max_' . $this->mode . '_font_size'] && $config['max_' . $this->mode . '_font_size'] < $stx)
 0205          {
 0206              $this->warn_msg[] = sprintf($user->lang['MAX_FONT_SIZE_EXCEEDED'], $config['max_' . $this->mode . '_font_size']);
 0207   
 0208              return '[size=' . $stx . ']' . $in . '[/size]';
 0209          }
 0210   
 0211          // Do not allow size=0
 0212          if ($stx <= 0)
 0213          {
 0214              return '[size=' . $stx . ']' . $in . '[/size]';
 0215          }
 0216   
 0217          return '[size=' . $stx . ':' . $this->bbcode_uid . ']' . $in . '[/size:' . $this->bbcode_uid . ']';
 0218      }
 0219   
 0220      /**
 0221      * Parse color tag
 0222      */
 0223      function bbcode_color($stx, $in)
 0224      {
 0225          if (!$this->check_bbcode('color', $in))
 0226          {
 0227              return '';
 0228          }
 0229   
 0230          return '[color=' . $stx . ':' . $this->bbcode_uid . ']' . $in . '[/color:' . $this->bbcode_uid . ']';
 0231      }
 0232   
 0233      /**
 0234      * Parse u tag
 0235      */
 0236      function bbcode_underline($in)
 0237      {
 0238          if (!$this->check_bbcode('u', $in))
 0239          {
 0240              return '';
 0241          }
 0242   
 0243          return '[u:' . $this->bbcode_uid . ']' . $in . '[/u:' . $this->bbcode_uid . ']';
 0244      }
 0245   
 0246      /**
 0247      * Parse b tag
 0248      */
 0249      function bbcode_strong($in)
 0250      {
 0251          if (!$this->check_bbcode('b', $in))
 0252          {
 0253              return '';
 0254          }
 0255   
 0256          return '[b:' . $this->bbcode_uid . ']' . $in . '[/b:' . $this->bbcode_uid . ']';
 0257      }
 0258   
 0259      /**
 0260      * Parse i tag
 0261      */
 0262      function bbcode_italic($in)
 0263      {
 0264          if (!$this->check_bbcode('i', $in))
 0265          {
 0266              return '';
 0267          }
 0268   
 0269          return '[i:' . $this->bbcode_uid . ']' . $in . '[/i:' . $this->bbcode_uid . ']';
 0270      }
 0271   
 0272      /**
 0273      * Parse img tag
 0274      */
 0275      function bbcode_img($in)
 0276      {
 0277          global $user, $config;
 0278   
 0279          if (!$this->check_bbcode('img', $in))
 0280          {
 0281              return '';
 0282          }
 0283   
 0284          $in = trim($in);
 0285          $error = false;
 0286   
 0287          $in = str_replace(' ', '%20', $in);
 0288   
 0289          // Checking urls
 0290          if (!preg_match('#^' . get_preg_expression('url') . '$#i', $in) && !preg_match('#^' . get_preg_expression('www_url') . '$#i', $in))
 0291          {
 0292              return '[img]' . $in . '[/img]';
 0293          }
 0294   
 0295          // Try to cope with a common user error... not specifying a protocol but only a subdomain
 0296          if (!preg_match('#^[a-z0-9]+://#i', $in))
 0297          {
 0298              $in = 'http://' . $in;
 0299          }
 0300   
 0301          if ($config['max_' . $this->mode . '_img_height'] || $config['max_' . $this->mode . '_img_width'])
 0302          {
 0303              $stats = @getimagesize($in);
 0304   
 0305              if ($stats === false)
 0306              {
 0307                  $error = true;
 0308                  $this->warn_msg[] = $user->lang['UNABLE_GET_IMAGE_SIZE'];
 0309              }
 0310              else
 0311              {
 0312                  if ($config['max_' . $this->mode . '_img_height'] && $config['max_' . $this->mode . '_img_height'] < $stats[1])
 0313                  {
 0314                      $error = true;
 0315                      $this->warn_msg[] = sprintf($user->lang['MAX_IMG_HEIGHT_EXCEEDED'], $config['max_' . $this->mode . '_img_height']);
 0316                  }
 0317   
 0318                  if ($config['max_' . $this->mode . '_img_width'] && $config['max_' . $this->mode . '_img_width'] < $stats[0])
 0319                  {
 0320                      $error = true;
 0321                      $this->warn_msg[] = sprintf($user->lang['MAX_IMG_WIDTH_EXCEEDED'], $config['max_' . $this->mode . '_img_width']);
 0322                  }
 0323              }
 0324          }
 0325   
 0326          if ($error || $this->path_in_domain($in))
 0327          {
 0328              return '[img]' . $in . '[/img]';
 0329          }
 0330   
 0331          return '[img:' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($in) . '[/img:' . $this->bbcode_uid . ']';
 0332      }
 0333   
 0334      /**
 0335      * Parse flash tag
 0336      */
 0337      function bbcode_flash($width, $height, $in)
 0338      {
 0339          global $user, $config;
 0340   
 0341          if (!$this->check_bbcode('flash', $in))
 0342          {
 0343              return '';
 0344          }
 0345   
 0346          $in = trim($in);
 0347          $error = false;
 0348   
 0349          // Apply the same size checks on flash files as on images
 0350          if ($config['max_' . $this->mode . '_img_height'] || $config['max_' . $this->mode . '_img_width'])
 0351          {
 0352              if ($config['max_' . $this->mode . '_img_height'] && $config['max_' . $this->mode . '_img_height'] < $height)
 0353              {
 0354                  $error = true;
 0355                  $this->warn_msg[] = sprintf($user->lang['MAX_FLASH_HEIGHT_EXCEEDED'], $config['max_' . $this->mode . '_img_height']);
 0356              }
 0357   
 0358              if ($config['max_' . $this->mode . '_img_width'] && $config['max_' . $this->mode . '_img_width'] < $width)
 0359              {
 0360                  $error = true;
 0361                  $this->warn_msg[] = sprintf($user->lang['MAX_FLASH_WIDTH_EXCEEDED'], $config['max_' . $this->mode . '_img_width']);
 0362              }
 0363          }
 0364   
 0365          if ($error || $this->path_in_domain($in))
 0366          {
 0367              return '[flash=' . $width . ',' . $height . ']' . $in . '[/flash]';
 0368          }
 0369   
 0370          return '[flash=' . $width . ',' . $height . ':' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($in) . '[/flash:' . $this->bbcode_uid . ']';
 0371      }
 0372   
 0373      /**
 0374      * Parse inline attachments [ia]
 0375      */
 0376      function bbcode_attachment($stx, $in)
 0377      {
 0378          if (!$this->check_bbcode('attachment', $in))
 0379          {
 0380              return '';
 0381          }
 0382   
 0383          return '[attachment=' . $stx . ':' . $this->bbcode_uid . ']<!-- ia' . $stx . ' -->' . trim($in) . '<!-- ia' . $stx . ' -->[/attachment:' . $this->bbcode_uid . ']';
 0384      }
 0385   
 0386      /**
 0387      * Parse code text from code tag
 0388      * @private
 0389      */
 0390      function bbcode_parse_code($stx, &$code)
 0391      {
 0392          switch (strtolower($stx))
 0393          {
 0394              case 'php':
 0395   
 0396                  $remove_tags = false;
 0397                  $code = str_replace(array('&lt;', '&gt;'), array('<', '>'), $code);
 0398   
 0399                  if (!preg_match('/\<\?.*?\?\>/is', $code))
 0400                  {
 0401                      $remove_tags = true;
 0402                      $code = "<?php $code ?>";
 0403                  }
 0404   
 0405                  $conf = array('highlight.bg', 'highlight.comment', 'highlight.default', 'highlight.html', 'highlight.keyword', 'highlight.string');
 0406                  foreach ($conf as $ini_var)
 0407                  {
 0408                      @ini_set($ini_var, str_replace('highlight.', 'syntax', $ini_var));
 0409                  }
 0410   
 0411                  // Because highlight_string is specialcharing the text (but we already did this before), we have to reverse this in order to get correct results
 0412                  $code = htmlspecialchars_decode($code);
 0413                  $code = highlight_string($code, true);
 0414   
 0415                  $str_from = array('<span style="color: ', '<font color="syntax', '</font>', '<code>', '</code>','[', ']', '.', ':');
 0416                  $str_to = array('<span class="', '<span class="syntax', '</span>', '', '', '&#91;', '&#93;', '&#46;', '&#58;');
 0417   
 0418                  if ($remove_tags)
 0419                  {
 0420                      $str_from[] = '<span class="syntaxdefault">&lt;?php </span>';
 0421                      $str_to[] = '';
 0422                      $str_from[] = '<span class="syntaxdefault">&lt;?php&nbsp;';
 0423                      $str_to[] = '<span class="syntaxdefault">';
 0424                  }
 0425   
 0426                  $code = str_replace($str_from, $str_to, $code);
 0427                  $code = preg_replace('#^(<span class="[a-z_]+">)\n?(.*?)\n?(</span>)$#is', '$1$2$3', $code);
 0428   
 0429                  if ($remove_tags)
 0430                  {
 0431                      $code = preg_replace('#(<span class="[a-z]+">)?\?&gt;(</span>)#', '$1&nbsp;$2', $code);
 0432                  }
 0433   
 0434                  $code = preg_replace('#^<span class="[a-z]+"><span class="([a-z]+)">(.*)</span></span>#s', '<span class="$1">$2</span>', $code);
 0435                  $code = preg_replace('#(?:\s++|&nbsp;)*+</span>$#u', '</span>', $code);
 0436   
 0437                  // remove newline at the end
 0438                  if (!empty($code) && substr($code, -1) == "\n")
 0439                  {
 0440                      $code = substr($code, 0, -1);
 0441                  }
 0442   
 0443                  return "[code=$stx:" . $this->bbcode_uid . ']' . $code . '[/code:' . $this->bbcode_uid . ']';
 0444              break;
 0445   
 0446              default:
 0447                  return '[code:' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($code) . '[/code:' . $this->bbcode_uid . ']';
 0448              break;
 0449          }
 0450      }
 0451   
 0452      /**
 0453      * Parse code tag
 0454      * Expects the argument to start right after the opening [code] tag and to end with [/code]
 0455      */
 0456      function bbcode_code($stx, $in)
 0457      {
 0458          if (!$this->check_bbcode('code', $in))
 0459          {
 0460              return '';
 0461          }
 0462   
 0463          // We remove the hardcoded elements from the code block here because it is not used in code blocks
 0464          // Having it here saves us one preg_replace per message containing [code] blocks
 0465          // Additionally, magic url parsing should go after parsing bbcodes, but for safety those are stripped out too...
 0466          $htm_match = get_preg_expression('bbcode_htm');
 0467          unset($htm_match[4], $htm_match[5]);
 0468          $htm_replace = array('\1', '\1', '\2', '\1');
 0469   
 0470          $out = $code_block = '';
 0471          $open = 1;
 0472   
 0473          while ($in)
 0474          {
 0475              // Determine position and tag length of next code block
 0476              preg_match('#(.*?)(\[code(?:=([a-z]+))?\])(.+)#is', $in, $buffer);
 0477              $pos = (isset($buffer[1])) ? strlen($buffer[1]) : false;
 0478              $tag_length = (isset($buffer[2])) ? strlen($buffer[2]) : false;
 0479   
 0480              // Determine position of ending code tag
 0481              $pos2 = stripos($in, '[/code]');
 0482   
 0483              // Which is the next block, ending code or code block
 0484              if ($pos !== false && $pos < $pos2)
 0485              {
 0486                  // Open new block
 0487                  if (!$open)
 0488                  {
 0489                      $out .= substr($in, 0, $pos);
 0490                      $in = substr($in, $pos);
 0491                      $stx = (isset($buffer[3])) ? $buffer[3] : '';
 0492                      $code_block = '';
 0493                  }
 0494                  else
 0495                  {
 0496                      // Already opened block, just append to the current block
 0497                      $code_block .= substr($in, 0, $pos) . ((isset($buffer[2])) ? $buffer[2] : '');
 0498                      $in = substr($in, $pos);
 0499                  }
 0500   
 0501                  $in = substr($in, $tag_length);
 0502                  $open++;
 0503              }
 0504              else
 0505              {
 0506                  // Close the block
 0507                  if ($open == 1)
 0508                  {
 0509                      $code_block .= substr($in, 0, $pos2);
 0510                      $code_block = preg_replace($htm_match, $htm_replace, $code_block);
 0511   
 0512                      // Parse this code block
 0513                      $out .= $this->bbcode_parse_code($stx, $code_block);
 0514                      $code_block = '';
 0515                      $open--;
 0516                  }
 0517                  else if ($open)
 0518                  {
 0519                      // Close one open tag... add to the current code block
 0520                      $code_block .= substr($in, 0, $pos2 + 7);
 0521                      $open--;
 0522                  }
 0523                  else
 0524                  {
 0525                      // end code without opening code... will be always outside code block
 0526                      $out .= substr($in, 0, $pos2 + 7);
 0527                  }
 0528   
 0529                  $in = substr($in, $pos2 + 7);
 0530              }
 0531          }
 0532   
 0533          // if now $code_block has contents we need to parse the remaining code while removing the last closing tag to match up.
 0534          if ($code_block)
 0535          {
 0536              $code_block = substr($code_block, 0, -7);
 0537              $code_block = preg_replace($htm_match, $htm_replace, $code_block);
 0538   
 0539              $out .= $this->bbcode_parse_code($stx, $code_block);
 0540          }
 0541   
 0542          return $out;
 0543      }
 0544   
 0545      /**
 0546      * Parse list bbcode
 0547      * Expects the argument to start with a tag
 0548      */
 0549      function bbcode_parse_list($in)
 0550      {
 0551          if (!$this->check_bbcode('list', $in))
 0552          {
 0553              return '';
 0554          }
 0555   
 0556          // $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
 0557          $tok = ']';
 0558          $out = '[';
 0559   
 0560          // First character is [
 0561          $in = substr($in, 1);
 0562          $list_end_tags = $item_end_tags = array();
 0563   
 0564          do
 0565          {
 0566              $pos = strlen($in);
 0567   
 0568              for ($i = 0, $tok_len = strlen($tok); $i < $tok_len; ++$i)
 0569              {
 0570                  $tmp_pos = strpos($in, $tok[$i]);
 0571   
 0572                  if ($tmp_pos !== false && $tmp_pos < $pos)
 0573                  {
 0574                      $pos = $tmp_pos;
 0575                  }
 0576              }
 0577   
 0578              $buffer = substr($in, 0, $pos);
 0579              $tok = $in[$pos];
 0580   
 0581              $in = substr($in, $pos + 1);
 0582   
 0583              if ($tok == ']')
 0584              {
 0585                  // if $tok is ']' the buffer holds a tag
 0586                  if (strtolower($buffer) == '/list' && sizeof($list_end_tags))
 0587                  {
 0588                      // valid [/list] tag, check nesting so that we don't hit false positives
 0589                      if (sizeof($item_end_tags) && sizeof($item_end_tags) >= sizeof($list_end_tags))
 0590                      {
 0591                          // current li tag has not been closed
 0592                          $out = preg_replace('/\n?\[$/', '[', $out) . array_pop($item_end_tags) . '][';
 0593                      }
 0594   
 0595                      $out .= array_pop($list_end_tags) . ']';
 0596                      $tok = '[';
 0597                  }
 0598                  else if (preg_match('#^list(=[0-9a-z])?$#i', $buffer, $m))
 0599                  {
 0600                      // sub-list, add a closing tag
 0601                      if (empty($m[1]) || preg_match('/^(?:disc|square|circle)$/i', $m[1]))
 0602                      {
 0603                          array_push($list_end_tags, '/list:u:' . $this->bbcode_uid);
 0604                      }
 0605                      else
 0606                      {
 0607                          array_push($list_end_tags, '/list:o:' . $this->bbcode_uid);
 0608                      }
 0609                      $out .= 'list' . substr($buffer, 4) . ':' . $this->bbcode_uid . ']';
 0610                      $tok = '[';
 0611                  }
 0612                  else
 0613                  {
 0614                      if (($buffer == '*' || substr($buffer, -2) == '[*') && sizeof($list_end_tags))
 0615                      {
 0616                          // the buffer holds a bullet tag and we have a [list] tag open
 0617                          if (sizeof($item_end_tags) >= sizeof($list_end_tags))
 0618                          {
 0619                              if (substr($buffer, -2) == '[*')
 0620                              {
 0621                                  $out .= substr($buffer, 0, -2) . '[';
 0622                              }
 0623                              // current li tag has not been closed
 0624                              if (preg_match('/\n\[$/', $out, $m))
 0625                              {
 0626                                  $out = preg_replace('/\n\[$/', '[', $out);
 0627                                  $buffer = array_pop($item_end_tags) . "]\n[*:" . $this->bbcode_uid;
 0628                              }
 0629                              else
 0630                              {
 0631                                  $buffer = array_pop($item_end_tags) . '][*:' . $this->bbcode_uid;
 0632                              }
 0633                          }
 0634                          else
 0635                          {
 0636                              $buffer = '*:' . $this->bbcode_uid;
 0637                          }
 0638   
 0639                          $item_end_tags[] = '/*:m:' . $this->bbcode_uid;
 0640                      }
 0641                      else if ($buffer == '/*')
 0642                      {
 0643                          array_pop($item_end_tags);
 0644                          $buffer = '/*:' . $this->bbcode_uid;
 0645                      }
 0646   
 0647                      $out .= $buffer . $tok;
 0648                      $tok = '[]';
 0649                  }
 0650              }
 0651              else
 0652              {
 0653                  // Not within a tag, just add buffer to the return string
 0654                  $out .= $buffer . $tok;
 0655                  $tok = ($tok == '[') ? ']' : '[]';
 0656              }
 0657          }
 0658          while ($in);
 0659   
 0660          // do we have some tags open? close them now
 0661          if (sizeof($item_end_tags))
 0662          {
 0663              $out .= '[' . implode('][', $item_end_tags) . ']';
 0664          }
 0665          if (sizeof($list_end_tags))
 0666          {
 0667              $out .= '[' . implode('][', $list_end_tags) . ']';
 0668          }
 0669   
 0670          return $out;
 0671      }
 0672   
 0673      /**
 0674      * Parse quote bbcode
 0675      * Expects the argument to start with a tag
 0676      */
 0677      function bbcode_quote($in)
 0678      {
 0679          global $config, $user;
 0680   
 0681          /**
 0682          * If you change this code, make sure the cases described within the following reports are still working:
 0683          * #3572 - [quote="[test]test"]test [ test[/quote] - (correct: parsed)
 0684          * #14667 - [quote]test[/quote] test ] and [ test [quote]test[/quote] (correct: parsed)
 0685          * #14770 - [quote="["]test[/quote] (correct: parsed)
 0686          * [quote="[i]test[/i]"]test[/quote] (correct: parsed)
 0687          * [quote="[quote]test[/quote]"]test[/quote] (correct: NOT parsed)
 0688          */
 0689   
 0690          $in = str_replace("\r\n", "\n", str_replace('\"', '"', trim($in)));
 0691   
 0692          if (!$in)
 0693          {
 0694              return '';
 0695          }
 0696   
 0697          // To let the parser not catch tokens within quote_username quotes we encode them before we start this...
 0698          $in = preg_replace('#quote=&quot;(.*?)&quot;\]#ie', "'quote=&quot;' . str_replace(array('[', ']'), array('&#91;', '&#93;'), '\$1') . '&quot;]'", $in);
 0699   
 0700          $tok = ']';
 0701          $out = '[';
 0702   
 0703          $in = substr($in, 1);
 0704          $close_tags = $error_ary = array();
 0705          $buffer = '';
 0706   
 0707          do
 0708          {
 0709              $pos = strlen($in);
 0710              for ($i = 0, $tok_len = strlen($tok); $i < $tok_len; ++$i)
 0711              {
 0712                  $tmp_pos = strpos($in, $tok[$i]);
 0713                  if ($tmp_pos !== false && $tmp_pos < $pos)
 0714                  {
 0715                      $pos = $tmp_pos;
 0716                  }
 0717              }
 0718   
 0719              $buffer .= substr($in, 0, $pos);
 0720              $tok = $in[$pos];
 0721              $in = substr($in, $pos + 1);
 0722   
 0723              if ($tok == ']')
 0724              {
 0725                  if (strtolower($buffer) == '/quote' && sizeof($close_tags) && substr($out, -1, 1) == '[')
 0726                  {
 0727                      // we have found a closing tag
 0728                      $out .= array_pop($close_tags) . ']';
 0729                      $tok = '[';
 0730                      $buffer = '';
 0731   
 0732                      /* Add space at the end of the closing tag if not happened before to allow following urls/smilies to be parsed correctly
 0733                      * 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.
 0734                      * Also, we won't have any spaces within $in anyway, only adding up spaces -> #10982
 0735                      if (!$in || $in[0] !== ' ')
 0736                      {
 0737                          $out .= ' ';
 0738                      }*/
 0739                  }
 0740                  else if (preg_match('#^quote(?:=&quot;(.*?)&quot;)?$#is', $buffer, $m))
 0741                  {
 0742                      $this->parsed_items['quote']++;
 0743   
 0744                      // the buffer holds a valid opening tag
 0745                      if ($config['max_quote_depth'] && sizeof($close_tags) >= $config['max_quote_depth'])
 0746                      {
 0747                          // there are too many nested quotes
 0748                          $error_ary['quote_depth'] = sprintf($user->lang['QUOTE_DEPTH_EXCEEDED'], $config['max_quote_depth']);
 0749   
 0750                          $out .= $buffer . $tok;
 0751                          $tok = '[]';
 0752                          $buffer = '';
 0753   
 0754                          continue;
 0755                      }
 0756   
 0757                      array_push($close_tags, '/quote:' . $this->bbcode_uid);
 0758   
 0759                      if (isset($m[1]) && $m[1])
 0760                      {
 0761                          $username = str_replace(array('&#91;', '&#93;'), array('[', ']'), $m[1]);
 0762                          $username = preg_replace('#\[(?!b|i|u|color|url|email|/b|/i|/u|/color|/url|/email)#iU', '&#91;$1', $username);
 0763   
 0764                          $end_tags = array();
 0765                          $error = false;
 0766   
 0767                          preg_match_all('#\[((?:/)?(?:[a-z]+))#i', $username, $tags);
 0768                          foreach ($tags[1] as $tag)
 0769                          {
 0770                              if ($tag[0] != '/')
 0771                              {
 0772                                  $end_tags[] = '/' . $tag;
 0773                              }
 0774                              else
 0775                              {
 0776                                  $end_tag = array_pop($end_tags);
 0777                                  $error = ($end_tag != $tag) ? true : false;
 0778                              }
 0779                          }
 0780   
 0781                          if ($error)
 0782                          {
 0783                              $username = $m[1];
 0784                          }
 0785   
 0786                          $out .= 'quote=&quot;' . $username . '&quot;:' . $this->bbcode_uid . ']';
 0787                      }
 0788                      else
 0789                      {
 0790                          $out .= 'quote:' . $this->bbcode_uid . ']';
 0791                      }
 0792   
 0793                      $tok = '[';
 0794                      $buffer = '';
 0795                  }
 0796                  else if (preg_match('#^quote=&quot;(.*?)#is', $buffer, $m))
 0797                  {
 0798                      // the buffer holds an invalid opening tag
 0799                      $buffer .= ']';
 0800                  }
 0801                  else
 0802                  {
 0803                      $out .= $buffer . $tok;
 0804                      $tok = '[]';
 0805                      $buffer = '';
 0806                  }
 0807              }
 0808              else
 0809              {
 0810  /**
 0811  *                Old quote code working fine, but having errors listed in bug #3572
 0812  *
 0813  *                $out .= $buffer . $tok;
 0814  *                $tok = ($tok == '[') ? ']' : '[]';
 0815  *                $buffer = '';
 0816  */
 0817   
 0818                  $out .= $buffer . $tok;
 0819   
 0820                  if ($tok == '[')
 0821                  {
 0822                      // Search the text for the next tok... if an ending quote comes first, then change tok to []
 0823                      $pos1 = stripos($in, '[/quote');
 0824                      // If the token ] comes first, we change it to ]
 0825                      $pos2 = strpos($in, ']');
 0826                      // If the token [ comes first, we change it to [
 0827                      $pos3 = strpos($in, '[');
 0828   
 0829                      if ($pos1 !== false && ($pos2 === false || $pos1 < $pos2) && ($pos3 === false || $pos1 < $pos3))
 0830                      {
 0831                          $tok = '[]';
 0832                      }
 0833                      else if ($pos3 !== false && ($pos2 === false || $pos3 < $pos2))
 0834                      {
 0835                          $tok = '[';
 0836                      }
 0837                      else
 0838                      {
 0839                          $tok = ']';
 0840                      }
 0841                  }
 0842                  else
 0843                  {
 0844                      $tok = '[]';
 0845                  }
 0846                  $buffer = '';
 0847              }
 0848          }
 0849          while ($in);
 0850   
 0851          if (sizeof($close_tags))
 0852          {
 0853              $out .= '[' . implode('][', $close_tags) . ']';
 0854          }
 0855   
 0856          foreach ($error_ary as $error_msg)
 0857          {
 0858              $this->warn_msg[] = $error_msg;
 0859          }
 0860   
 0861          return $out;
 0862      }
 0863   
 0864      /**
 0865      * Validate email
 0866      */
 0867      function validate_email($var1, $var2)
 0868      {
 0869          $var1 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var1)));
 0870          $var2 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var2)));
 0871   
 0872          $txt = $var2;
 0873          $email = ($var1) ? $var1 : $var2;
 0874   
 0875          $validated = true;
 0876   
 0877          if (!preg_match('/^' . get_preg_expression('email') . '$/i', $email))
 0878          {
 0879              $validated = false;
 0880          }
 0881   
 0882          if (!$validated)
 0883          {
 0884              return '[email' . (($var1) ? "=$var1" : '') . ']' . $var2 . '[/email]';
 0885          }
 0886   
 0887          $this->parsed_items['email']++;
 0888   
 0889          if ($var1)
 0890          {
 0891              $retval = '[email=' . $this->bbcode_specialchars($email) . ':' . $this->bbcode_uid . ']' . $txt . '[/email:' . $this->bbcode_uid . ']';
 0892          }
 0893          else
 0894          {
 0895              $retval = '[email:' . $this->bbcode_uid . ']' . $this->bbcode_specialchars($email) . '[/email:' . $this->bbcode_uid . ']';
 0896          }
 0897   
 0898          return $retval;
 0899      }
 0900   
 0901      /**
 0902      * Validate url
 0903      *
 0904      * @param string $var1 optional url parameter for url bbcode: [url(=$var1)]$var2[/url]
 0905      * @param string $var2 url bbcode content: [url(=$var1)]$var2[/url]
 0906      */
 0907      function validate_url($var1, $var2)
 0908      {
 0909          global $config;
 0910   
 0911          $var1 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var1)));
 0912          $var2 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var2)));
 0913   
 0914          $url = ($var1) ? $var1 : $var2;
 0915   
 0916          if (!$url || ($var1 && !$var2))
 0917          {
 0918              return '';
 0919          }
 0920   
 0921          $valid = false;
 0922   
 0923          $url = str_replace(' ', '%20', $url);
 0924   
 0925          // Checking urls
 0926          if (preg_match('#^' . get_preg_expression('url') . '$#i', $url) ||
 0927              preg_match('#^' . get_preg_expression('www_url') . '$#i', $url) ||
 0928              preg_match('#^' . preg_quote(generate_board_url(), '#') . get_preg_expression('relative_url') . '$#i', $url))
 0929          {
 0930              $valid = true;
 0931          }
 0932   
 0933          if ($valid)
 0934          {
 0935              $this->parsed_items['url']++;
 0936   
 0937              // if there is no scheme, then add http schema
 0938              if (!preg_match('#^[a-z][a-z\d+\-.]*:/{2}#i', $url))
 0939              {
 0940                  $url = 'http://' . $url;
 0941              }
 0942   
 0943              // Is this a link to somewhere inside this board? If so then remove the session id from the url
 0944              if (strpos($url, generate_board_url()) !== false && strpos($url, 'sid=') !== false)
 0945              {
 0946                  $url = preg_replace('/(&amp;|\?)sid=[0-9a-f]{32}&amp;/', '\1', $url);
 0947                  $url = preg_replace('/(&amp;|\?)sid=[0-9a-f]{32}$/', '', $url);
 0948                  $url = append_sid($url);
 0949              }
 0950   
 0951              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 . ']';
 0952          }
 0953   
 0954          return '[url' . (($var1) ? '=' . $var1 : '') . ']' . $var2 . '[/url]';
 0955      }
 0956   
 0957      /**
 0958      * Check if url is pointing to this domain/script_path/php-file
 0959      *
 0960      * @param string $url the url to check
 0961      * @return true if the url is pointing to this domain/script_path/php-file, false if not
 0962      *
 0963      * @access private
 0964      */
 0965      function path_in_domain($url)
 0966      {
 0967          global $config, $phpEx, $user;
 0968   
 0969          if ($config['force_server_vars'])
 0970          {
 0971              $check_path = $config['script_path'];
 0972          }
 0973          else
 0974          {
 0975              $check_path = ($user->page['root_script_path'] != '/') ? substr($user->page['root_script_path'], 0, -1) : '/';
 0976          }
 0977   
 0978          // Is the user trying to link to a php file in this domain and script path?
 0979          if (strpos($url, ".{$phpEx}") !== false && strpos($url, $check_path) !== false)
 0980          {
 0981              $server_name = (!empty($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : getenv('SERVER_NAME');
 0982   
 0983              // Forcing server vars is the only way to specify/override the protocol
 0984              if ($config['force_server_vars'] || !$server_name)
 0985              {
 0986                  $server_name = $config['server_name'];
 0987              }
 0988   
 0989              // Check again in correct order...
 0990              $pos_ext = strpos($url, ".{$phpEx}");
 0991              $pos_path = strpos($url, $check_path);
 0992              $pos_domain = strpos($url, $server_name);
 0993   
 0994              if ($pos_domain !== false && $pos_path >= $pos_domain && $pos_ext >= $pos_path)
 0995              {
 0996                  // Ok, actually we allow linking to some files (this may be able to be extended in some way later...)
 0997                  if (strpos($url, '/' . $check_path . '/download/file.' . $phpEx) !== 0)
 0998                  {
 0999                      return false;
 1000                  }
 1001   
 1002                  return true;
 1003              }
 1004          }
 1005   
 1006          return false;
 1007      }
 1008  }
 1009   
 1010  /**
 1011  * Main message parser for posting, pm, etc. takes raw message
 1012  * and parses it for attachments, bbcode and smilies
 1013  * @package phpBB3
 1014  */
 1015  class parse_message extends bbcode_firstpass
 1016  {
 1017      var $attachment_data = array();
 1018      var $filename_data = array();
 1019   
 1020      // Helps ironing out user error
 1021      var $message_status = '';
 1022   
 1023      var $allow_img_bbcode = true;
 1024      var $allow_flash_bbcode = true;
 1025      var $allow_quote_bbcode = true;
 1026      var $allow_url_bbcode = true;
 1027   
 1028      var $mode;
 1029   
 1030      /**
 1031      * Init - give message here or manually
 1032      */
 1033      function parse_message($message = '')
 1034      {
 1035          // Init BBCode UID
 1036          $this->bbcode_uid = substr(base_convert(unique_id(), 16, 36), 0, BBCODE_UID_LEN);
 1037   
 1038          if ($message)
 1039          {
 1040              $this->message = $message;
 1041          }
 1042      }
 1043   
 1044      /**
 1045      * Parse Message
 1046      */
 1047      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')
 1048      {
 1049          global $config, $db, $user;
 1050   
 1051          $mode = ($mode != 'post') ? 'sig' : 'post';
 1052   
 1053          $this->mode = $mode;
 1054   
 1055          $this->allow_img_bbcode = $allow_img_bbcode;
 1056          $this->allow_flash_bbcode = $allow_flash_bbcode;
 1057          $this->allow_quote_bbcode = $allow_quote_bbcode;
 1058          $this->allow_url_bbcode = $allow_url_bbcode;
 1059   
 1060          // If false, then $this->message won't be altered, the text will be returned instead.
 1061          if (!$update_this_message)
 1062          {
 1063              $tmp_message = $this->message;
 1064              $return_message = &$this->message;
 1065          }
 1066   
 1067          if ($this->message_status == 'display')
 1068          {
 1069              $this->decode_message();
 1070          }
 1071   
 1072          // Do some general 'cleanup' first before processing message,
 1073          // e.g. remove excessive newlines(?), smilies(?)
 1074          $match = array('#(script|about|applet|activex|chrome):#i');
 1075          $replace = array("\\1&#058;");
 1076          $this->message = preg_replace($match, $replace, trim($this->message));
 1077   
 1078          // Message length check. 0 disables this check completely.
 1079          if ($config['max_' . $mode . '_chars'] > 0)
 1080          {
 1081              $msg_len = ($mode == 'post') ? utf8_strlen($this->message) : utf8_strlen(preg_replace('#\[\/?[a-z\*\+\-]+(=[\S]+)?\]#ius', ' ', $this->message));
 1082      
 1083              if ((!$msg_len && $mode !== 'sig') || $config['max_' . $mode . '_chars'] && $msg_len > $config['max_' . $mode . '_chars'])
 1084              {
 1085                  $this->warn_msg[] = (!$msg_len) ? $user->lang['TOO_FEW_CHARS'] : sprintf($user->lang['TOO_MANY_CHARS_' . strtoupper($mode)], $msg_len, $config['max_' . $mode . '_chars']);
 1086                  return $this->warn_msg;
 1087              }
 1088          }
 1089   
 1090          // Check for "empty" message
 1091          if ($mode !== 'sig' && !utf8_clean_string($this->message))
 1092          {
 1093              $this->warn_msg[] = $user->lang['TOO_FEW_CHARS'];
 1094              return $this->warn_msg;
 1095          }
 1096   
 1097          // Prepare BBcode (just prepares some tags for better parsing)
 1098          if ($allow_bbcode && strpos($this->message, '[') !== false)
 1099          {
 1100              $this->bbcode_init();
 1101              $disallow = array('img', 'flash', 'quote', 'url');
 1102              foreach ($disallow as $bool)
 1103              {
 1104                  if (!${'allow_' . $bool . '_bbcode'})
 1105                  {
 1106                      $this->bbcodes[$bool]['disabled'] = true;
 1107                  }
 1108              }
 1109   
 1110              $this->prepare_bbcodes();
 1111          }
 1112   
 1113          // Parse smilies
 1114          if ($allow_smilies)
 1115          {
 1116              $this->smilies($config['max_' . $mode . '_smilies']);
 1117          }
 1118   
 1119          $num_urls = 0;
 1120   
 1121          // Parse BBCode
 1122          if ($allow_bbcode && strpos($this->message, '[') !== false)
 1123          {
 1124              $this->parse_bbcode();
 1125              $num_urls += $this->parsed_items['url'];
 1126          }
 1127   
 1128          // Parse URL's
 1129          if ($allow_magic_url)
 1130          {
 1131              $this->magic_url(generate_board_url());
 1132   
 1133              if ($config['max_' . $mode . '_urls'])
 1134              {
 1135                  $num_urls += preg_match_all('#\<!-- ([lmwe]) --\>.*?\<!-- \1 --\>#', $this->message, $matches);
 1136              }
 1137          }
 1138   
 1139          // Check number of links
 1140          if ($config['max_' . $mode . '_urls'] && $num_urls > $config['max_' . $mode . '_urls'])
 1141          {
 1142              $this->warn_msg[] = sprintf($user->lang['TOO_MANY_URLS'], $config['max_' . $mode . '_urls']);
 1143              return $this->warn_msg;
 1144          }
 1145   
 1146          if (!$update_this_message)
 1147          {
 1148              unset($this->message);
 1149              $this->message = $tmp_message;
 1150              return $return_message;
 1151          }
 1152   
 1153          $this->message_status = 'parsed';
 1154          return false;
 1155      }
 1156   
 1157      /**
 1158      * Formatting text for display
 1159      */
 1160      function format_display($allow_bbcode, $allow_magic_url, $allow_smilies, $update_this_message = true)
 1161      {
 1162          // If false, then the parsed message get returned but internal message not processed.
 1163          if (!$update_this_message)
 1164          {
 1165              $tmp_message = $this->message;
 1166              $return_message = &$this->message;
 1167          }
 1168   
 1169          if ($this->message_status == 'plain')
 1170          {
 1171              // Force updating message - of course.
 1172              $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);
 1173          }
 1174   
 1175          // Replace naughty words such as farty pants
 1176          $this->message = censor_text($this->message);
 1177   
 1178          // Parse BBcode
 1179          if ($allow_bbcode)
 1180          {
 1181              $this->bbcode_cache_init();
 1182   
 1183              // We are giving those parameters to be able to use the bbcode class on its own
 1184              $this->bbcode_second_pass($this->message, $this->bbcode_uid);
 1185          }
 1186   
 1187          $this->message = bbcode_nl2br($this->message);
 1188          $this->message = smiley_text($this->message, !$allow_smilies);
 1189   
 1190          if (!$update_this_message)
 1191          {
 1192              unset($this->message);
 1193              $this->message = $tmp_message;
 1194              return $return_message;
 1195          }
 1196   
 1197          $this->message_status = 'display';
 1198          return false;
 1199      }
 1200   
 1201      /**
 1202      * Decode message to be placed back into form box
 1203      */
 1204      function decode_message($custom_bbcode_uid = '', $update_this_message = true)
 1205      {
 1206          // If false, then the parsed message get returned but internal message not processed.
 1207          if (!$update_this_message)
 1208          {
 1209              $tmp_message = $this->message;
 1210              $return_message = &$this->message;
 1211          }
 1212   
 1213          ($custom_bbcode_uid) ? decode_message($this->message, $custom_bbcode_uid) : decode_message($this->message, $this->bbcode_uid);
 1214   
 1215          if (!$update_this_message)
 1216          {
 1217              unset($this->message);
 1218              $this->message = $tmp_message;
 1219              return $return_message;
 1220          }
 1221   
 1222          $this->message_status = 'plain';
 1223          return false;
 1224      }
 1225   
 1226      /**
 1227      * Replace magic urls of form http://xxx.xxx., www.xxx. and xxx@xxx.xxx.
 1228      * Cuts down displayed size of link if over 50 chars, turns absolute links
 1229      * into relative versions when the server/script path matches the link
 1230      */
 1231      function magic_url($server_url)
 1232      {
 1233          // We use the global make_clickable function
 1234          $this->message = make_clickable($this->message, $server_url);
 1235      }
 1236   
 1237      /**
 1238      * Parse Smilies
 1239      */
 1240      function smilies($max_smilies = 0)
 1241      {
 1242          global $db, $user;
 1243          static $match;
 1244          static $replace;
 1245   
 1246          // See if the static arrays have already been filled on an earlier invocation
 1247          if (!is_array($match))
 1248          {
 1249              $match = $replace = array();
 1250   
 1251              // NOTE: obtain_* function? chaching the table contents?
 1252      
 1253              // For now setting the ttl to 10 minutes
 1254              switch ($db->sql_layer)
 1255              {
 1256                  case 'mssql':
 1257                  case 'mssql_odbc':
 1258                      $sql = 'SELECT *
 1259                          FROM ' . SMILIES_TABLE . '
 1260                          ORDER BY LEN(code) DESC';
 1261                  break;
 1262      
 1263                  case 'firebird':
 1264                      $sql = 'SELECT *
 1265                          FROM ' . SMILIES_TABLE . '
 1266                          ORDER BY CHAR_LENGTH(code) DESC';
 1267                  break;
 1268   
 1269                  // LENGTH supported by MySQL, IBM DB2, Oracle and Access for sure...
 1270                  default:
 1271                      $sql = 'SELECT *
 1272                          FROM ' . SMILIES_TABLE . '
 1273                          ORDER BY LENGTH(code) DESC';
 1274                  break;
 1275              }
 1276              $result = $db->sql_query($sql, 600);
 1277   
 1278              while ($row = $db->sql_fetchrow($result))
 1279              {
 1280                  if (empty($row['code']))
 1281                  {
 1282                      continue;
 1283                  }
 1284   
 1285                  // (assertion)
 1286                  $match[] = '(?<=^|[\n .])' . preg_quote($row['code'], '#') . '(?![^<>]*>)';
 1287                  $replace[] = '<!-- s' . $row['code'] . ' --><img src="{SMILIES_PATH}/' . $row['smiley_url'] . '" alt="' . $row['code'] . '" title="' . $row['emotion'] . '" /><!-- s' . $row['code'] . ' -->';
 1288              }
 1289              $db->sql_freeresult($result);
 1290          }
 1291   
 1292          if (sizeof($match))
 1293          {
 1294              if ($max_smilies)
 1295              {
 1296                  $num_matches = preg_match_all('#' . implode('|', $match) . '#', $this->message, $matches);
 1297                  unset($matches);
 1298   
 1299                  if ($num_matches !== false && $num_matches > $max_smilies)
 1300                  {
 1301                      $this->warn_msg[] = sprintf($user->lang['TOO_MANY_SMILIES'], $max_smilies);
 1302                      return;
 1303                  }
 1304              }
 1305   
 1306              // Make sure the delimiter # is added in front and at the end of every element within $match
 1307              $this->message = trim(preg_replace(explode(chr(0), '#' . implode('#' . chr(0) . '#', $match) . '#'), $replace, $this->message));
 1308          }
 1309      }
 1310   
 1311      /**
 1312      * Parse Attachments
 1313      */
 1314      function parse_attachments($form_name, $mode, $forum_id, $submit, $preview, $refresh, $is_message = false)
 1315      {
 1316          global $config, $auth, $user, $phpbb_root_path, $phpEx, $db;
 1317   
 1318          $error = array();
 1319   
 1320          $num_attachments = sizeof($this->attachment_data);
 1321          $this->filename_data['filecomment'] = utf8_normalize_nfc(request_var('filecomment', '', true));
 1322          $upload_file = (isset($_FILES[$form_name]) && $_FILES[$form_name]['name'] != 'none' && trim($_FILES[$form_name]['name'])) ? true : false;
 1323   
 1324          $add_file        = (isset($_POST['add_file'])) ? true : false;
 1325          $delete_file    = (isset($_POST['delete_file'])) ? true : false;
 1326   
 1327          // First of all adjust comments if changed
 1328          $actual_comment_list = utf8_normalize_nfc(request_var('comment_list', array(''), true));
 1329   
 1330          foreach ($actual_comment_list as $comment_key => $comment)
 1331          {
 1332              if (!isset($this->attachment_data[$comment_key]))
 1333              {
 1334                  continue;
 1335              }
 1336   
 1337              if ($this->attachment_data[$comment_key]['attach_comment'] != $actual_comment_list[$comment_key])
 1338              {
 1339                  $this->attachment_data[$comment_key]['attach_comment'] = $actual_comment_list[$comment_key];
 1340              }
 1341          }
 1342   
 1343          $cfg = array();
 1344          $cfg['max_attachments'] = ($is_message) ? $config['max_attachments_pm'] : $config['max_attachments'];
 1345          $forum_id = ($is_message) ? 0 : $forum_id;
 1346   
 1347          if ($submit && in_array($mode, array('post', 'reply', 'quote', 'edit')) && $upload_file)
 1348          {
 1349              if ($num_attachments < $cfg['max_attachments'] || $auth->acl_get('a_') || $auth->acl_get('m_', $forum_id))
 1350              {
 1351                  $filedata = upload_attachment($form_name, $forum_id, false, '', $is_message);
 1352                  $error = $filedata['error'];
 1353   
 1354                  if ($filedata['post_attach'] && !sizeof($error))
 1355                  {
 1356                      $sql_ary = array(
 1357                          'physical_filename'    => $filedata['physical_filename'],
 1358                          'attach_comment'    => $this->filename_data['filecomment'],
 1359                          'real_filename'        => $filedata['real_filename'],
 1360                          'extension'            => $filedata['extension'],
 1361                          'mimetype'            => $filedata['mimetype'],
 1362                          'filesize'            => $filedata['filesize'],
 1363                          'filetime'            => $filedata['filetime'],
 1364                          'thumbnail'            => $filedata['thumbnail'],
 1365                          'is_orphan'            => 1,
 1366                          'in_message'        => ($is_message) ? 1 : 0,
 1367                          'poster_id'            => $user->data['user_id'],
 1368                      );
 1369   
 1370                      $db->sql_query('INSERT INTO ' . ATTACHMENTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
 1371   
 1372                      $new_entry = array(
 1373                          'attach_id'        => $db->sql_nextid(),
 1374                          'is_orphan'        => 1,
 1375                          'real_filename'    => $filedata['real_filename'],
 1376                          'attach_comment'=> $this->filename_data['filecomment'],
 1377                      );
 1378   
 1379                      $this->attachment_data = array_merge(array(0 => $new_entry), $this->attachment_data);
 1380                      $this->message = preg_replace('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#e', "'[attachment='.(\\1 + 1).']\\2[/attachment]'", $this->message);
 1381   
 1382                      $this->filename_data['filecomment'] = '';
 1383   
 1384                      // This Variable is set to false here, because Attachments are entered into the
 1385                      // Database in two modes, one if the id_list is 0 and the second one if post_attach is true
 1386                      // Since post_attach is automatically switched to true if an Attachment got added to the filesystem,
 1387                      // but we are assigning an id of 0 here, we have to reset the post_attach variable to false.
 1388                      //
 1389                      // This is very relevant, because it could happen that the post got not submitted, but we do not
 1390                      // know this circumstance here. We could be at the posting page or we could be redirected to the entered
 1391                      // post. :)
 1392                      $filedata['post_attach'] = false;
 1393                  }
 1394              }
 1395              else
 1396              {
 1397                  $error[] = sprintf($user->lang['TOO_MANY_ATTACHMENTS'], $cfg['max_attachments']);
 1398              }
 1399          }
 1400   
 1401          if ($preview || $refresh || sizeof($error))
 1402          {
 1403              // Perform actions on temporary attachments
 1404              if ($delete_file)
 1405              {
 1406                  include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
 1407   
 1408                  $index = array_keys(request_var('delete_file', array(0 => 0)));
 1409                  $index = (!empty($index)) ? $index[0] : false;
 1410   
 1411                  if ($index !== false && !empty($this->attachment_data[$index]))
 1412                  {
 1413                      // delete selected attachment
 1414                      if ($this->attachment_data[$index]['is_orphan'])
 1415                      {
 1416                          $sql = 'SELECT attach_id, physical_filename, thumbnail
 1417                              FROM ' . ATTACHMENTS_TABLE . '
 1418                              WHERE attach_id = ' . (int) $this->attachment_data[$index]['attach_id'] . '
 1419                                  AND is_orphan = 1
 1420                                  AND poster_id = ' . $user->data['user_id'];
 1421                          $result = $db->sql_query($sql);
 1422                          $row = $db->sql_fetchrow($result);
 1423                          $db->sql_freeresult($result);
 1424   
 1425                          if ($row)
 1426                          {
 1427                              phpbb_unlink($row['physical_filename'], 'file');
 1428   
 1429                              if ($row['thumbnail'])
 1430                              {
 1431                                  phpbb_unlink($row['physical_filename'], 'thumbnail');
 1432                              }
 1433   
 1434                              $db->sql_query('DELETE FROM ' . ATTACHMENTS_TABLE . ' WHERE attach_id = ' . (int) $this->attachment_data[$index]['attach_id']);
 1435                          }
 1436                      }
 1437                      else
 1438                      {
 1439                          delete_attachments('attach', array(intval($this->attachment_data[$index]['attach_id'])));
 1440                      }
 1441   
 1442                      unset($this->attachment_data[$index]);
 1443                      $this->message = preg_replace('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#e', "(\\1 == \$index) ? '' : ((\\1 > \$index) ? '[attachment=' . (\\1 - 1) . ']\\2[/attachment]' : '\\0')", $this->message);
 1444   
 1445                      // Reindex Array
 1446                      $this->attachment_data = array_values($this->attachment_data);
 1447                  }
 1448              }
 1449              else if (($add_file || $preview) && $upload_file)
 1450              {
 1451                  if ($num_attachments < $cfg['max_attachments'] || $auth->acl_gets('m_', 'a_', $forum_id))
 1452                  {
 1453                      $filedata = upload_attachment($form_name, $forum_id, false, '', $is_message);
 1454                      $error = array_merge($error, $filedata['error']);
 1455   
 1456                      if (!sizeof($error))
 1457                      {
 1458                          $sql_ary = array(
 1459                              'physical_filename'    => $filedata['physical_filename'],
 1460                              'attach_comment'    => $this->filename_data['filecomment'],
 1461                              'real_filename'        => $filedata['real_filename'],
 1462                              'extension'            => $filedata['extension'],
 1463                              'mimetype'            => $filedata['mimetype'],
 1464                              'filesize'            => $filedata['filesize'],
 1465                              'filetime'            => $filedata['filetime'],
 1466                              'thumbnail'            => $filedata['thumbnail'],
 1467                              'is_orphan'            => 1,
 1468                              'in_message'        => ($is_message) ? 1 : 0,
 1469                              'poster_id'            => $user->data['user_id'],
 1470                          );
 1471   
 1472                          $db->sql_query('INSERT INTO ' . ATTACHMENTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
 1473   
 1474                          $new_entry = array(
 1475                              'attach_id'        => $db->sql_nextid(),
 1476                              'is_orphan'        => 1,
 1477                              'real_filename'    => $filedata['real_filename'],
 1478                              'attach_comment'=> $this->filename_data['filecomment'],
 1479                          );
 1480   
 1481                          $this->attachment_data = array_merge(array(0 => $new_entry), $this->attachment_data);
 1482                          $this->message = preg_replace('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#e', "'[attachment='.(\\1 + 1).']\\2[/attachment]'", $this->message);
 1483                          $this->filename_data['filecomment'] = '';
 1484                      }
 1485                  }
 1486                  else
 1487                  {
 1488                      $error[] = sprintf($user->lang['TOO_MANY_ATTACHMENTS'], $cfg['max_attachments']);
 1489                  }
 1490              }
 1491          }
 1492   
 1493          foreach ($error as $error_msg)
 1494          {
 1495              $this->warn_msg[] = $error_msg;
 1496          }
 1497      }
 1498   
 1499      /**
 1500      * Get Attachment Data
 1501      */
 1502      function get_submitted_attachment_data($check_user_id = false)
 1503      {
 1504          global $user, $db, $phpbb_root_path, $phpEx, $config;
 1505   
 1506          $this->filename_data['filecomment'] = utf8_normalize_nfc(request_var('filecomment', '', true));
 1507          $attachment_data = (isset($_POST['attachment_data'])) ? $_POST['attachment_data'] : array();
 1508          $this->attachment_data = array();
 1509   
 1510          $check_user_id = ($check_user_id === false) ? $user->data['user_id'] : $check_user_id;
 1511   
 1512          if (!sizeof($attachment_data))
 1513          {
 1514              return;
 1515          }
 1516   
 1517          $not_orphan = $orphan = array();
 1518   
 1519          foreach ($attachment_data as $pos => $var_ary)
 1520          {
 1521              if ($var_ary['is_orphan'])
 1522              {
 1523                  $orphan[(int) $var_ary['attach_id']] = $pos;
 1524              }
 1525              else
 1526              {
 1527                  $not_orphan[(int) $var_ary['attach_id']] = $pos;
 1528              }
 1529          }
 1530   
 1531          // Regenerate already posted attachments
 1532          if (sizeof($not_orphan))
 1533          {
 1534              // Get the attachment data, based on the poster id...
 1535              $sql = 'SELECT attach_id, is_orphan, real_filename, attach_comment
 1536                  FROM ' . ATTACHMENTS_TABLE . '
 1537                  WHERE ' . $db->sql_in_set('attach_id', array_keys($not_orphan)) . '
 1538                      AND poster_id = ' . $check_user_id;
 1539              $result = $db->sql_query($sql);
 1540   
 1541              while ($row = $db->sql_fetchrow($result))
 1542              {
 1543                  $pos = $not_orphan[$row['attach_id']];
 1544                  $this->attachment_data[$pos] = $row;
 1545                  set_var($this->attachment_data[$pos]['attach_comment'], $_POST['attachment_data'][$pos]['attach_comment'], 'string', true);
 1546   
 1547                  unset($not_orphan[$row['attach_id']]);
 1548              }
 1549              $db->sql_freeresult($result);
 1550          }
 1551   
 1552          if (sizeof($not_orphan))
 1553          {
 1554              trigger_error('NO_ACCESS_ATTACHMENT', E_USER_ERROR);
 1555          }
 1556   
 1557          // Regenerate newly uploaded attachments
 1558          if (sizeof($orphan))
 1559          {
 1560              $sql = 'SELECT attach_id, is_orphan, real_filename, attach_comment
 1561                  FROM ' . ATTACHMENTS_TABLE . '
 1562                  WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan)) . '
 1563                      AND poster_id = ' . $user->data['user_id'] . '
 1564                      AND is_orphan = 1';
 1565              $result = $db->sql_query($sql);
 1566   
 1567              while ($row = $db->sql_fetchrow($result))
 1568              {
 1569                  $pos = $orphan[$row['attach_id']];
 1570                  $this->attachment_data[$pos] = $row;
 1571                  set_var($this->attachment_data[$pos]['attach_comment'], $_POST['attachment_data'][$pos]['attach_comment'], 'string', true);
 1572   
 1573                  unset($orphan[$row['attach_id']]);
 1574              }
 1575              $db->sql_freeresult($result);
 1576          }
 1577   
 1578          if (sizeof($orphan))
 1579          {
 1580              trigger_error('NO_ACCESS_ATTACHMENT', E_USER_ERROR);
 1581          }
 1582   
 1583          ksort($this->attachment_data);
 1584      }
 1585   
 1586      /**
 1587      * Parse Poll
 1588      */
 1589      function parse_poll(&$poll)
 1590      {
 1591          global $auth, $user, $config;
 1592   
 1593          $poll_max_options = $poll['poll_max_options'];
 1594   
 1595          // Parse Poll Option text ;)
 1596          $tmp_message = $this->message;
 1597          $this->message = $poll['poll_option_text'];
 1598          $bbcode_bitfield = $this->bbcode_bitfield;
 1599   
 1600   
 1601          $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);
 1602   
 1603          $bbcode_bitfield = base64_encode(base64_decode($bbcode_bitfield) | base64_decode($this->bbcode_bitfield));
 1604          $this->message = $tmp_message;
 1605   
 1606          // Parse Poll Title
 1607          $tmp_message = $this->message;
 1608          $this->message = $poll['poll_title'];
 1609          $this->bbcode_bitfield = $bbcode_bitfield;
 1610   
 1611          $poll['poll_options'] = explode("\n", trim($poll['poll_option_text']));
 1612          $poll['poll_options_size'] = sizeof($poll['poll_options']);
 1613   
 1614          if (!$poll['poll_title'] && $poll['poll_options_size'])
 1615          {
 1616              $this->warn_msg[] = $user->lang['NO_POLL_TITLE'];
 1617          }
 1618          else
 1619          {
 1620              if (utf8_strlen(preg_replace('#\[\/?[a-z\*\+\-]+(=[\S]+)?\]#ius', ' ', $this->message)) > 100)
 1621              {
 1622                  $this->warn_msg[] = $user->lang['POLL_TITLE_TOO_LONG'];
 1623              }
 1624              $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);
 1625              if (strlen($poll['poll_title']) > 255)
 1626              {
 1627                  $this->warn_msg[] = $user->lang['POLL_TITLE_COMP_TOO_LONG'];
 1628              }
 1629          }
 1630   
 1631          $this->bbcode_bitfield = base64_encode(base64_decode($bbcode_bitfield) | base64_decode($this->bbcode_bitfield));
 1632          $this->message = $tmp_message;
 1633          unset($tmp_message);
 1634   
 1635          if (sizeof($poll['poll_options']) == 1)
 1636          {
 1637              $this->warn_msg[] = $user->lang['TOO_FEW_POLL_OPTIONS'];
 1638          }
 1639          else if ($poll['poll_options_size'] > (int) $config['max_poll_options'])
 1640          {
 1641              $this->warn_msg[] = $user->lang['TOO_MANY_POLL_OPTIONS'];
 1642          }
 1643          else if ($poll_max_options > $poll['poll_options_size'])
 1644          {
 1645              $this->warn_msg[] = $user->lang['TOO_MANY_USER_OPTIONS'];
 1646          }
 1647   
 1648          $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']);
 1649      }
 1650  }
 1651   
 1652  ?>