[ Index ]

PHP Cross Reference of MyBB 1.6.5

title

Body

[close]

/inc/ -> class_parser.php (source)

   1  <?php
   2  /**
   3   * MyBB 1.6
   4   * Copyright 2010 MyBB Group, All Rights Reserved
   5   *
   6   * Website: http://mybb.com
   7   * License: http://mybb.com/about/license
   8   *
   9   * $Id: class_parser.php 5616 2011-09-20 13:24:59Z Tomm $
  10   */
  11  
  12  /*
  13  options = array(
  14      allow_html
  15      allow_smilies
  16      allow_mycode
  17      nl2br
  18      filter_badwords
  19      me_username
  20      shorten_urls
  21      highlight
  22  )
  23  */
  24  
  25  class postParser
  26  {
  27      /**
  28       * Internal cache of MyCode.
  29       *
  30       * @access public
  31       * @var mixed
  32       */
  33      public $mycode_cache = 0;
  34  
  35      /**
  36       * Internal cache of smilies
  37       *
  38       * @access public
  39       * @var mixed
  40       */
  41      public $smilies_cache = 0;
  42  
  43      /**
  44       * Internal cache of badwords filters
  45       *
  46       * @access public
  47       * @var mixed
  48       */
  49      public $badwords_cache = 0;
  50  
  51      /**
  52       * Base URL for smilies
  53       *
  54       * @access public
  55       * @var string
  56       */
  57      public $base_url;
  58      
  59      /**
  60       * Parsed Highlights cache
  61       *
  62       * @access public
  63       * @var array
  64       */
  65      public $highlight_cache = array();
  66      
  67      /**
  68       * Options for this parsed message (Private - set by parse_message argument)
  69       *
  70       * @access public
  71       * @var array
  72       */
  73      public $options;
  74  
  75      /**
  76       * Parses a message with the specified options.
  77       *
  78       * @param string The message to be parsed.
  79       * @param array Array of yes/no options - allow_html,filter_badwords,allow_mycode,allow_smilies,nl2br,me_username.
  80       * @return string The parsed message.
  81       */
  82  	function parse_message($message, $options=array())
  83      {
  84          global $plugins, $mybb;
  85  
  86          // Set base URL for parsing smilies
  87          $this->base_url = $mybb->settings['bburl'];
  88  
  89          if($this->base_url != "")
  90          {
  91              if(my_substr($this->base_url, my_strlen($this->base_url) -1) != "/")
  92              {
  93                  $this->base_url = $this->base_url."/";
  94              }
  95          }
  96          
  97          // Set the options        
  98          $this->options = $options;
  99  
 100          $message = $plugins->run_hooks("parse_message_start", $message);
 101  
 102          // Get rid of cartridge returns for they are the workings of the devil
 103          $message = str_replace("\r", "", $message);
 104          
 105          // Filter bad words if requested.
 106          if($this->options['filter_badwords'])
 107          {
 108              $message = $this->parse_badwords($message);
 109          }
 110  
 111          if($this->options['allow_html'] != 1)
 112          {
 113              $message = $this->parse_html($message);
 114          }
 115          else
 116          {        
 117              while(preg_match("#<script(.*)>(.*)</script(.*)>#is", $message))
 118              {
 119                  $message = preg_replace("#<script(.*)>(.*)</script(.*)>#is", "&lt;script$1&gt;$2&lt;/script$3&gt;", $message);
 120              }
 121  
 122              $message = str_replace(array('<?php', '<!--', '-->', '?>', "<br />\n", "<br>\n"), array('&lt;?php', '&lt;!--', '--&gt;', '?&gt;', "\n", "\n"), $message);
 123          }
 124          
 125          // If MyCode needs to be replaced, first filter out [code] and [php] tags.
 126          if($this->options['allow_mycode'])
 127          {
 128              preg_match_all("#\[(code|php)\](.*?)\[/\\1\](\r\n?|\n?)#si", $message, $code_matches, PREG_SET_ORDER);
 129              $message = preg_replace("#\[(code|php)\](.*?)\[/\\1\](\r\n?|\n?)#si", "<mybb-code>\n", $message);
 130          }
 131  
 132          // Always fix bad Javascript in the message.
 133          $message = $this->fix_javascript($message);
 134          
 135          // Replace "me" code and slaps if we have a username
 136          if($this->options['me_username'])
 137          {
 138              global $lang;
 139              
 140              $message = preg_replace('#(>|^|\r|\n)/me ([^\r\n<]*)#i', "\\1<span style=\"color: red;\">* {$this->options['me_username']} \\2</span>", $message);
 141              $message = preg_replace('#(>|^|\r|\n)/slap ([^\r\n<]*)#i', "\\1<span style=\"color: red;\">* {$this->options['me_username']} {$lang->slaps} \\2 {$lang->with_trout}</span>", $message);
 142          }
 143          
 144          // If we can, parse smilies
 145          if($this->options['allow_smilies'])
 146          {
 147              $message = $this->parse_smilies($message, $this->options['allow_html']);
 148          }
 149  
 150          // Replace MyCode if requested.
 151          if($this->options['allow_mycode'])
 152          {
 153              $message = $this->parse_mycode($message, $this->options);
 154          }
 155          
 156          // Parse Highlights
 157          if($this->options['highlight'])
 158          {
 159              $message = $this->highlight_message($message, $this->options['highlight']);
 160          }
 161  
 162          // Run plugin hooks
 163          $message = $plugins->run_hooks("parse_message", $message);
 164          
 165          if($this->options['allow_mycode'])
 166          {
 167              // Now that we're done, if we split up any code tags, parse them and glue it all back together
 168              if(count($code_matches) > 0)
 169              {
 170                  foreach($code_matches as $text)
 171                  {
 172                      // Fix up HTML inside the code tags so it is clean
 173                      if($options['allow_html'] != 0)
 174                      {
 175                          $text[2] = $this->parse_html($text[2]);
 176                      }
 177  
 178                      if(my_strtolower($text[1]) == "code")
 179                      {
 180                          $code = $this->mycode_parse_code($text[2]);
 181                      }
 182                      elseif(my_strtolower($text[1]) == "php")
 183                      {
 184                          $code = $this->mycode_parse_php($text[2]);
 185                      }
 186                      $message = preg_replace("#\<mybb-code>\n?#", $code, $message, 1);
 187                  }
 188              }
 189          }
 190  
 191          // Replace meta and base tags in our post - these are > dangerous <
 192          if($this->options['allow_html'])
 193          {
 194              $message = preg_replace_callback("#<((m[^a])|(b[^diloru>])|(s[^aemptu>]))(\s*[^>]*)>#si", create_function(
 195                  '$matches',
 196                  'return htmlspecialchars($matches[0]);'
 197              ), $message);
 198          }
 199  
 200          if($options['nl2br'] !== 0)
 201          {
 202              $message = nl2br($message);
 203              // Fix up new lines and block level elements
 204              $message = preg_replace("#(</?(?:html|head|body|div|p|form|table|thead|tbody|tfoot|tr|td|th|ul|ol|li|div|p|blockquote|cite|hr)[^>]*>)\s*<br />#i", "$1", $message);
 205              $message = preg_replace("#(&nbsp;)+(</?(?:html|head|body|div|p|form|table|thead|tbody|tfoot|tr|td|th|ul|ol|li|div|p|blockquote|cite|hr)[^>]*>)#i", "$2", $message);
 206          }
 207  
 208          $message = my_wordwrap($message);
 209      
 210          $message = $plugins->run_hooks("parse_message_end", $message);
 211                  
 212          return $message;
 213      }
 214  
 215      /**
 216       * Converts HTML in a message to their specific entities whilst allowing unicode characters.
 217       *
 218       * @param string The message to be parsed.
 219       * @return string The formatted message.
 220       */
 221  	function parse_html($message)
 222      {
 223          $message = preg_replace("#&(?!\#[0-9]+;)#si", "&amp;", $message); // fix & but allow unicode
 224          $message = str_replace("<","&lt;",$message);
 225          $message = str_replace(">","&gt;",$message);
 226          return $message;
 227      }
 228  
 229      /**
 230       * Generates a cache of MyCode, both standard and custom.
 231       *
 232       * @access private
 233       */
 234  	private function cache_mycode()
 235      {
 236          global $cache, $lang;
 237          $this->mycode_cache = array();
 238  
 239          $standard_mycode['b']['regex'] = "#\[b\](.*?)\[/b\]#si";
 240          $standard_mycode['b']['replacement'] = "<span style=\"font-weight: bold;\">$1</span>";
 241  
 242          $standard_mycode['u']['regex'] = "#\[u\](.*?)\[/u\]#si";
 243          $standard_mycode['u']['replacement'] = "<span style=\"text-decoration: underline;\">$1</span>";
 244  
 245          $standard_mycode['i']['regex'] = "#\[i\](.*?)\[/i\]#si";
 246          $standard_mycode['i']['replacement'] = "<span style=\"font-style: italic;\">$1</span>";
 247  
 248          $standard_mycode['s']['regex'] = "#\[s\](.*?)\[/s\]#si";
 249          $standard_mycode['s']['replacement'] = "<del>$1</del>";
 250  
 251          $standard_mycode['copy']['regex'] = "#\(c\)#i";
 252          $standard_mycode['copy']['replacement'] = "&copy;";
 253  
 254          $standard_mycode['tm']['regex'] = "#\(tm\)#i";
 255          $standard_mycode['tm']['replacement'] = "&#153;";
 256  
 257          $standard_mycode['reg']['regex'] = "#\(r\)#i";
 258          $standard_mycode['reg']['replacement'] = "&reg;";
 259  
 260          $standard_mycode['url_simple']['regex'] = "#\[url\]([a-z]+?://)([^\r\n\"<]+?)\[/url\]#sei";
 261          $standard_mycode['url_simple']['replacement'] = "\$this->mycode_parse_url(\"$1$2\")";
 262  
 263          $standard_mycode['url_simple2']['regex'] = "#\[url\]([^\r\n\"<]+?)\[/url\]#ei";
 264          $standard_mycode['url_simple2']['replacement'] = "\$this->mycode_parse_url(\"$1\")";
 265  
 266          $standard_mycode['url_complex']['regex'] = "#\[url=([a-z]+?://)([^\r\n\"<]+?)\](.+?)\[/url\]#esi";
 267          $standard_mycode['url_complex']['replacement'] = "\$this->mycode_parse_url(\"$1$2\", \"$3\")";
 268  
 269          $standard_mycode['url_complex2']['regex'] = "#\[url=([^\r\n\"<&\(\)]+?)\](.+?)\[/url\]#esi";
 270          $standard_mycode['url_complex2']['replacement'] = "\$this->mycode_parse_url(\"$1\", \"$2\")";
 271  
 272          $standard_mycode['email_simple']['regex'] = "#\[email\](.*?)\[/email\]#ei";
 273          $standard_mycode['email_simple']['replacement'] = "\$this->mycode_parse_email(\"$1\")";
 274  
 275          $standard_mycode['email_complex']['regex'] = "#\[email=(.*?)\](.*?)\[/email\]#ei";
 276          $standard_mycode['email_complex']['replacement'] = "\$this->mycode_parse_email(\"$1\", \"$2\")";
 277          
 278          $standard_mycode['hr']['regex'] = "#\[hr\]#si";
 279          $standard_mycode['hr']['replacement'] = "<hr />";
 280  
 281          $nestable_mycode['color']['regex'] = "#\[color=([a-zA-Z]*|\#?[0-9a-fA-F]{6})](.*?)\[/color\]#si";
 282          $nestable_mycode['color']['replacement'] = "<span style=\"color: $1;\">$2</span>";
 283  
 284          $nestable_mycode['size']['regex'] = "#\[size=(xx-small|x-small|small|medium|large|x-large|xx-large)\](.*?)\[/size\]#si";
 285          $nestable_mycode['size']['replacement'] = "<span style=\"font-size: $1;\">$2</span>";
 286  
 287          $nestable_mycode['size_int']['regex'] = "#\[size=([0-9\+\-]+?)\](.*?)\[/size\]#esi";
 288          $nestable_mycode['size_int']['replacement'] = "\$this->mycode_handle_size(\"$1\", \"$2\")";
 289  
 290          $nestable_mycode['font']['regex'] = "#\[font=([a-z ]+?)\](.+?)\[/font\]#si";
 291          $nestable_mycode['font']['replacement'] = "<span style=\"font-family: $1;\">$2</span>";
 292  
 293          $nestable_mycode['align']['regex'] = "#\[align=(left|center|right|justify)\](.*?)\[/align\]#si";
 294          $nestable_mycode['align']['replacement'] = "<div style=\"text-align: $1;\">$2</div>";
 295  
 296          $custom_mycode = $cache->read("mycode");
 297  
 298          // If there is custom MyCode, load it.
 299          if(is_array($custom_mycode))
 300          {
 301              foreach($custom_mycode as $key => $mycode)
 302              {
 303                  $mycode['regex'] = str_replace("\x0", "", $mycode['regex']);
 304                  $custom_mycode[$key]['regex'] = "#".$mycode['regex']."#si";
 305              }
 306              $mycode = array_merge($standard_mycode, $custom_mycode);
 307          }
 308          else
 309          {
 310              $mycode = $standard_mycode;
 311          }
 312  
 313          // Assign the MyCode to the cache.
 314          foreach($mycode as $code)
 315          {
 316              $this->mycode_cache['standard']['find'][] = $code['regex'];
 317              $this->mycode_cache['standard']['replacement'][] = $code['replacement'];
 318          }
 319          
 320          // Assign the nestable MyCode to the cache.
 321          foreach($nestable_mycode as $code)
 322          {
 323              $this->mycode_cache['nestable'][] = array('find' => $code['regex'], 'replacement' => $code['replacement']);
 324          }
 325      }
 326  
 327      /**
 328       * Parses MyCode tags in a specific message with the specified options.
 329       *
 330       * @param string The message to be parsed.
 331       * @param array Array of options in yes/no format. Options are allow_imgcode.
 332       * @return string The parsed message.
 333       */
 334  	function parse_mycode($message, $options=array())
 335      {
 336          global $lang;
 337  
 338          // Cache the MyCode globally if needed.
 339          if($this->mycode_cache == 0)
 340          {
 341              $this->cache_mycode();
 342          }
 343          
 344          // Parse quotes first
 345          $message = $this->mycode_parse_quotes($message);
 346          
 347          $message = $this->mycode_auto_url($message);
 348  
 349          $message = str_replace('$', '&#36;', $message);
 350          
 351          // Replace the rest
 352          $message = preg_replace($this->mycode_cache['standard']['find'], $this->mycode_cache['standard']['replacement'], $message);
 353          
 354          // Replace the nestable mycode's
 355          foreach($this->mycode_cache['nestable'] as $mycode)
 356          {
 357              while(preg_match($mycode['find'], $message))
 358              {
 359                  $message = preg_replace($mycode['find'], $mycode['replacement'], $message);
 360              }
 361          }
 362  
 363          // Special code requiring special attention
 364          while(preg_match("#\[list\](.*?)\[/list\]#esi", $message))
 365          {
 366              $message = preg_replace("#\s?\[list\](.*?)\[/list\](\r\n?|\n?)#esi", "\$this->mycode_parse_list('$1')\n", $message);
 367          }
 368  
 369          // Replace lists.
 370          while(preg_match("#\[list=(a|A|i|I|1)\](.*?)\[/list\](\r\n?|\n?)#esi", $message))
 371          {
 372              $message = preg_replace("#\s?\[list=(a|A|i|I|1)\](.*?)\[/list\]#esi", "\$this->mycode_parse_list('$2', '$1')\n", $message);
 373          }
 374  
 375          // Convert images when allowed.
 376          if($options['allow_imgcode'] != 0)
 377          {
 378              $message = preg_replace("#\[img\](\r\n?|\n?)(https?://([^<>\"']+?))\[/img\]#ise", "\$this->mycode_parse_img('$2')\n", $message);
 379              $message = preg_replace("#\[img=([0-9]{1,3})x([0-9]{1,3})\](\r\n?|\n?)(https?://([^<>\"']+?))\[/img\]#ise", "\$this->mycode_parse_img('$4', array('$1', '$2'));", $message);
 380              $message = preg_replace("#\[img align=([a-z]+)\](\r\n?|\n?)(https?://([^<>\"']+?))\[/img\]#ise", "\$this->mycode_parse_img('$3', array(), '$1');", $message);
 381              $message = preg_replace("#\[img=([0-9]{1,3})x([0-9]{1,3}) align=([a-z]+)\](\r\n?|\n?)(https?://([^<>\"']+?))\[/img\]#ise", "\$this->mycode_parse_img('$5', array('$1', '$2'), '$3');", $message);
 382          }
 383          
 384          // Convert videos when allow.
 385          if($options['allow_videocode'] != 0)
 386          {
 387              $message = preg_replace("#\[video=(.*?)\](.*?)\[/video\]#ei", "\$this->mycode_parse_video('$1', '$2');", $message);
 388          }
 389  
 390          return $message;
 391      }
 392  
 393      /**
 394       * Generates a cache of smilies
 395       *
 396       * @access private
 397       */
 398  	private function cache_smilies()
 399      {
 400          global $cache, $mybb;
 401          $this->smilies_cache = array();
 402  
 403          $smilies = $cache->read("smilies");
 404          if(is_array($smilies))
 405          {
 406              foreach($smilies as $sid => $smilie)
 407              {
 408                  if(defined("IN_ARCHIVE") && substr($smilie['image'], 0, 4) != "http")
 409                  {
 410                      // We're in the archive and not using an outside image, add in our address
 411                      $smilie['image'] = $mybb->settings['bburl']."/".$smilie['image'];
 412                  }
 413  
 414                  $this->smilies_cache[$smilie['find']] = "<img src=\"{$smilie['image']}\" style=\"vertical-align: middle;\" border=\"0\" alt=\"{$smilie['name']}\" title=\"{$smilie['name']}\" />";
 415              }
 416          }
 417      }
 418  
 419      /**
 420       * Parses smilie code in the specified message.
 421       *
 422       * @param string The message being parsed.
 423       * @param string Base URL for the image tags created by smilies.
 424       * @param string Yes/No if HTML is allowed in the post
 425       * @return string The parsed message.
 426       */
 427  	function parse_smilies($message, $allow_html=0)
 428      {
 429          if($this->smilies_cache == 0)
 430          {
 431              $this->cache_smilies();
 432          }
 433          
 434          $message = ' ' . $message . ' ';
 435          
 436          // First we take out any of the tags we don't want parsed between (url= etc)
 437          preg_match_all("#\[(url(=[^\]]*)?\]|quote=([^\]]*)?\])#i", $message, $bad_matches, PREG_PATTERN_ORDER);
 438          $message = preg_replace("#\[(url(=[^\]]*)?\]|quote=([^\]]*)?\])#si", "<mybb-bad-sm>", $message);
 439          
 440          // Impose a hard limit of 500 smilies per message as to not overload the parser
 441          $remaining = 500;
 442  
 443          if(is_array($this->smilies_cache))
 444          {
 445              foreach($this->smilies_cache as $find => $replace)
 446              {
 447                  $orig_message = $message;
 448                  $find = $this->parse_html($find);
 449                  $find = preg_quote($find, "#");
 450  
 451                  $replace = strip_tags($replace, "<img>");
 452                  
 453                  // Fix issues for smileys starting with a ";"
 454                  $orig_find = $find;
 455                  if(substr($find, 0, 1) == ";")
 456                  {
 457                      $find = "(?<!&gt|&lt|&amp)".$find;
 458                  }
 459                  
 460                  $message = @preg_replace("#(?<=[^\"])".$find."(?=.\W|\"|\W.|\W$)#si", $replace, $message, $remaining, $replacements);
 461                  
 462                  if($message == null)
 463                  {
 464                      $message = preg_replace("#(?<=[^&;\"])".$orig_find."(?=.\W|\"|\W.|\W$)#si", $replace, $orig_message, $remaining);
 465                  }
 466                  
 467                  $remaining -= $replacements;
 468                  if($remaining <= 0)
 469                  {
 470                      break; // Reached the limit
 471                  }
 472              }
 473              unset($orig_message, $orig_find);
 474          }
 475  
 476          // If we matched any tags previously, swap them back in
 477          if(count($bad_matches[0]) > 0)
 478          {
 479              foreach($bad_matches[0] as $match)
 480              {
 481                  $match = str_replace('$', '\$', $match);
 482                  $message = preg_replace("#<mybb-bad-sm>#", $match, $message, 1);
 483              }
 484          }
 485  
 486          return trim($message);
 487      }
 488  
 489      /**
 490       * Generates a cache of badwords filters.
 491       *
 492       * @access private
 493       */
 494  	private function cache_badwords()
 495      {
 496          global $cache;
 497          $this->badwords_cache = array();
 498          $this->badwords_cache = $cache->read("badwords");
 499      }
 500  
 501      /**
 502       * Parses a list of filtered/badwords in the specified message.
 503       *
 504       * @param string The message to be parsed.
 505       * @param array Array of parser options in yes/no format.
 506       * @return string The parsed message.
 507       */
 508  	function parse_badwords($message, $options=array())
 509      {
 510          if($this->badwords_cache == 0)
 511          {
 512              $this->cache_badwords();
 513          }
 514          if(is_array($this->badwords_cache))
 515          {
 516              reset($this->badwords_cache);
 517              foreach($this->badwords_cache as $bid => $badword)
 518              {
 519                  if(!$badword['replacement'])
 520                  {
 521                      $badword['replacement'] = "*****";
 522                  }
 523                  
 524                  // Take into account the position offset for our last replacement.
 525                  $index = substr_count($badword['badword'], '*')+2;
 526                  $badword['badword'] = str_replace('\*', '([a-zA-Z0-9_]{1})', preg_quote($badword['badword'], "#"));
 527                  
 528                  // Ensure we run the replacement enough times but not recursively (i.e. not while(preg_match..))
 529                  $count = preg_match_all("#(^|\W)".$badword['badword']."(\W|$)#i", $message, $matches);
 530                  for($i=0; $i < $count; ++$i)
 531                  {
 532                      $message = preg_replace("#(^|\W)".$badword['badword']."(\W|$)#i", "\\1".$badword['replacement'].'\\'.$index, $message);
 533                  }
 534              }
 535          }
 536          if($options['strip_tags'] == 1)
 537          {
 538              $message = strip_tags($message);
 539          }
 540          return $message;
 541      }
 542  
 543      /**
 544       * Attempts to move any javascript references in the specified message.
 545       *
 546       * @param string The message to be parsed.
 547       * @return string The parsed message.
 548       */
 549  	function fix_javascript($message)
 550      {
 551          $js_array = array(
 552              "#(&\#(0*)106;?|&\#(0*)74;?|&\#x(0*)4a;?|&\#x(0*)6a;?|j)((&\#(0*)97;?|&\#(0*)65;?|a)(&\#(0*)118;?|&\#(0*)86;?|v)(&\#(0*)97;?|&\#(0*)65;?|a)(\s)?(&\#(0*)115;?|&\#(0*)83;?|s)(&\#(0*)99;?|&\#(0*)67;?|c)(&\#(0*)114;?|&\#(0*)82;?|r)(&\#(0*)105;?|&\#(0*)73;?|i)(&\#112;?|&\#(0*)80;?|p)(&\#(0*)116;?|&\#(0*)84;?|t)(&\#(0*)58;?|\:))#i",
 553              "#(o)(nmouseover\s?=)#i",
 554              "#(o)(nmouseout\s?=)#i",
 555              "#(o)(nmousedown\s?=)#i",
 556              "#(o)(nmousemove\s?=)#i",
 557              "#(o)(nmouseup\s?=)#i",
 558              "#(o)(nclick\s?=)#i",
 559              "#(o)(ndblclick\s?=)#i",
 560              "#(o)(nload\s?=)#i",
 561              "#(o)(nsubmit\s?=)#i",
 562              "#(o)(nblur\s?=)#i",
 563              "#(o)(nchange\s?=)#i",
 564              "#(o)(nfocus\s?=)#i",
 565              "#(o)(nselect\s?=)#i",
 566              "#(o)(nunload\s?=)#i",
 567              "#(o)(nkeypress\s?=)#i"
 568          );
 569          
 570          $message = preg_replace($js_array, "$1<strong></strong>$2$4", $message);
 571  
 572          return $message;
 573      }
 574      
 575      /**
 576      * Handles fontsize.
 577      *
 578      * @param string The original size.
 579      * @param string The text within a size tag.
 580      * @return string The parsed text.
 581      */
 582  	function mycode_handle_size($size, $text)
 583      {
 584          $size = intval($size)+10;
 585  
 586          if($size > 50)
 587          {
 588              $size = 50;
 589          }
 590  
 591          $text = "<span style=\"font-size: {$size}pt;\">".str_replace("\'", "'", $text)."</span>";
 592  
 593          return $text;
 594      }
 595  
 596      /**
 597      * Parses quote MyCode.
 598      *
 599      * @param string The message to be parsed
 600      * @param boolean Are we formatting as text?
 601      * @return string The parsed message.
 602      */
 603  	function mycode_parse_quotes($message, $text_only=false)
 604      {
 605          global $lang, $templates, $theme, $mybb;
 606  
 607          // Assign pattern and replace values.
 608          $pattern = array(
 609              "#\[quote=([\"']|&quot;|)(.*?)(?:\\1)(.*?)(?:[\"']|&quot;)?\](.*?)\[/quote\](\r\n?|\n?)#esi",
 610              "#\[quote\](.*?)\[\/quote\](\r\n?|\n?)#si"
 611          );
 612  
 613          if($text_only == false)
 614          {
 615              $replace = array(
 616                  "\$this->mycode_parse_post_quotes('$4','$2$3')",
 617                  "<blockquote><cite>$lang->quote</cite>$1</blockquote>\n"
 618              );
 619          }
 620          else
 621          {
 622              $replace = array(
 623                  "\$this->mycode_parse_post_quotes('$4','$2$3', true)",
 624                  "\n{$lang->quote}\n--\n$1\n--\n"
 625              );
 626          }
 627  
 628          do
 629          {
 630              $previous_message = $message;
 631              $message = preg_replace($pattern, $replace, $message, -1, $count);
 632          } while($count);
 633  
 634          if(!$message)
 635          {
 636              $message = $previous_message;
 637          }
 638  
 639          if($text_only == false)
 640          {
 641              $find = array(
 642                  "#(\r\n*|\n*)<\/cite>(\r\n*|\n*)#",
 643                  "#(\r\n*|\n*)<\/blockquote>#"
 644              );
 645  
 646              $replace = array(
 647                  "</cite><br />",
 648                  "</blockquote>"
 649              );
 650              $message = preg_replace($find, $replace, $message);
 651          }
 652          return $message;
 653      }
 654      
 655      /**
 656      * Parses quotes with post id and/or dateline.
 657      *
 658      * @param string The message to be parsed
 659      * @param string The username to be parsed
 660      * @param boolean Are we formatting as text?
 661      * @return string The parsed message.
 662      */
 663  	function mycode_parse_post_quotes($message, $username, $text_only=false)
 664      {
 665          global $lang, $templates, $theme, $mybb;
 666  
 667          $linkback = $date = "";
 668  
 669          $message = trim($message);
 670          $message = preg_replace("#(^<br(\s?)(\/?)>|<br(\s?)(\/?)>$)#i", "", $message);
 671  
 672          if(!$message) return '';
 673  
 674          $message = str_replace('\"', '"', $message);
 675          $username = str_replace('\"', '"', $username)."'";
 676          $delete_quote = true;
 677  
 678          preg_match("#pid=(?:&quot;|\"|')?([0-9]+)[\"']?(?:&quot;|\"|')?#i", $username, $match);
 679          if(intval($match[1]))
 680          {
 681              $pid = intval($match[1]);
 682              $url = $mybb->settings['bburl']."/".get_post_link($pid)."#pid$pid";
 683              if(defined("IN_ARCHIVE"))
 684              {
 685                  $linkback = " <a href=\"{$url}\">[ -> ]</a>";
 686              }
 687              else
 688              {
 689                  eval("\$linkback = \" ".$templates->get("postbit_gotopost", 1, 0)."\";");
 690              }
 691              
 692              $username = preg_replace("#(?:&quot;|\"|')? pid=(?:&quot;|\"|')?[0-9]+[\"']?(?:&quot;|\"|')?#i", '', $username);
 693              $delete_quote = false;
 694          }
 695  
 696          unset($match);
 697          preg_match("#dateline=(?:&quot;|\"|')?([0-9]+)(?:&quot;|\"|')?#i", $username, $match);
 698          if(intval($match[1]))
 699          {
 700              if($match[1] < TIME_NOW)
 701              {
 702                  $postdate = my_date($mybb->settings['dateformat'], intval($match[1]));
 703                  $posttime = my_date($mybb->settings['timeformat'], intval($match[1]));
 704                  $date = " ({$postdate} {$posttime})";
 705              }
 706              $username = preg_replace("#(?:&quot;|\"|')? dateline=(?:&quot;|\"|')?[0-9]+(?:&quot;|\"|')?#i", '', $username);
 707              $delete_quote = false;
 708          }
 709  
 710          if($delete_quote)
 711          {
 712              $username = my_substr($username, 0, my_strlen($username)-1);
 713          }
 714  
 715          if($text_only)
 716          {
 717              return "\n".htmlspecialchars_uni($username)." $lang->wrote{$date}\n--\n{$message}\n--\n";
 718          }
 719          else
 720          {
 721              $span = "";
 722              if(!$delete_quote)
 723              {
 724                  $span = "<span>{$date}</span>";
 725              }
 726              
 727              return "<blockquote><cite>{$span}".htmlspecialchars_uni($username)." $lang->wrote{$linkback}</cite>{$message}</blockquote>\n";
 728          }
 729      }
 730  
 731      /**
 732      * Parses code MyCode.
 733      *
 734      * @param string The message to be parsed
 735      * @param boolean Are we formatting as text?
 736      * @return string The parsed message.
 737      */
 738  	function mycode_parse_code($code, $text_only=false)
 739      {
 740          global $lang;
 741  
 742          if($text_only == true)
 743          {
 744              return "\n{$lang->code}\n--\n{$code}\n--\n";
 745          }
 746  
 747          // Clean the string before parsing.
 748          $code = preg_replace('#^(\t*)(\n|\r|\0|\x0B| )*#', '\\1', $code);
 749          $code = rtrim($code);
 750          $original = preg_replace('#^\t*#', '', $code);
 751  
 752          if(empty($original))
 753          {
 754              return;
 755          }
 756  
 757          $code = str_replace('$', '&#36;', $code);
 758          $code = preg_replace('#\$([0-9])#', '\\\$\\1', $code);
 759          $code = str_replace('\\', '&#92;', $code);
 760          $code = str_replace("\t", '&nbsp;&nbsp;&nbsp;&nbsp;', $code);
 761          $code = str_replace("  ", '&nbsp;&nbsp;', $code);
 762  
 763          return "<div class=\"codeblock\">\n<div class=\"title\">".$lang->code."\n</div><div class=\"body\" dir=\"ltr\"><code>".$code."</code></div></div>\n";
 764      }
 765  
 766      /**
 767      * Parses PHP code MyCode.
 768      *
 769      * @param string The message to be parsed
 770      * @param boolean Whether or not it should return it as pre-wrapped in a div or not.
 771      * @param boolean Are we formatting as text?
 772      * @return string The parsed message.
 773      */
 774  	function mycode_parse_php($str, $bare_return = false, $text_only = false)
 775      {
 776          global $lang;
 777  
 778          if($text_only == true)
 779          {
 780              return "\n{$lang->php_code}\n--\n$str\n--\n";
 781          }
 782  
 783          // Clean the string before parsing except tab spaces.
 784          $str = preg_replace('#^(\t*)(\n|\r|\0|\x0B| )*#', '\\1', $str);
 785          $str = rtrim($str);
 786  
 787          $original = preg_replace('#^\t*#', '', $str);
 788  
 789          if(empty($original))
 790          {
 791              return;
 792          }
 793  
 794          $str = str_replace('&amp;', '&', $str);
 795          $str = str_replace('&lt;', '<', $str);
 796          $str = str_replace('&gt;', '>', $str);
 797  
 798          // See if open and close tags are provided.
 799          $added_open_tag = false;
 800          if(!preg_match("#^\s*<\?#si", $str))
 801          {
 802              $added_open_tag = true;
 803              $str = "<?php \n".$str;
 804          }
 805  
 806          $added_end_tag = false;
 807          if(!preg_match("#\?>\s*$#si", $str))
 808          {
 809              $added_end_tag = true;
 810              $str = $str." \n?>";
 811          }
 812  
 813          $code = @highlight_string($str, true);
 814  
 815          // Do the actual replacing.
 816          $code = preg_replace('#<code>\s*<span style="color: \#000000">\s*#i', "<code>", $code);
 817          $code = preg_replace("#</span>\s*</code>#", "</code>", $code);
 818          $code = preg_replace("#</span>(\r\n?|\n?)</code>#", "</span></code>", $code);
 819          $code = str_replace("\\", '&#092;', $code);
 820          $code = str_replace('$', '&#36;', $code);
 821          $code = preg_replace("#&amp;\#([0-9]+);#si", "&#$1;", $code);
 822  
 823          if($added_open_tag)
 824          {
 825              $code = preg_replace("#<code><span style=\"color: \#([A-Z0-9]{6})\">&lt;\?php( |&nbsp;)(<br />?)#", "<code><span style=\"color: #$1\">", $code);
 826          }
 827  
 828          if($added_end_tag)
 829          {
 830              $code = str_replace("?&gt;</span></code>", "</span></code>", $code);
 831              // Wait a minute. It fails highlighting? Stupid highlighter.
 832              $code = str_replace("?&gt;</code>", "</code>", $code);
 833          }
 834  
 835          $code = preg_replace("#<span style=\"color: \#([A-Z0-9]{6})\"></span>#", "", $code);
 836          $code = str_replace("<code>", "<div dir=\"ltr\"><code>", $code);
 837          $code = str_replace("</code>", "</code></div>", $code);
 838          $code = preg_replace("# *$#", "", $code);
 839  
 840          if($bare_return)
 841          {
 842              return $code;
 843          }
 844  
 845          // Send back the code all nice and pretty
 846          return "<div class=\"codeblock phpcodeblock\"><div class=\"title\">$lang->php_code\n</div><div class=\"body\">".$code."</div></div>\n";
 847      }
 848  
 849      /**
 850      * Parses URL MyCode.
 851      *
 852      * @param string The URL to link to.
 853      * @param string The name of the link.
 854      * @return string The built-up link.
 855      */
 856  	function mycode_parse_url($url, $name="")
 857      {
 858          if(!preg_match("#^[a-z0-9]+://#i", $url))
 859          {
 860              $url = "http://".$url;
 861          }
 862          $fullurl = $url;
 863  
 864          $url = str_replace('&amp;', '&', $url);
 865          $name = str_replace('&amp;', '&', $name);
 866          
 867          if(!$name)
 868          {
 869              $name = $url;
 870          }
 871          
 872          $name = str_replace("\'", "'", $name);
 873          $url = str_replace("\'", "'", $url);
 874          $fullurl = str_replace("\'", "'", $fullurl);
 875          
 876          if($name == $url && (!isset($this->options['shorten_urls']) || $this->options['shorten_urls'] != 0))
 877          {
 878              if(my_strlen($url) > 55)
 879              {
 880                  $name = my_substr($url, 0, 40)."...".my_substr($url, -10);
 881              }
 882          }
 883  
 884          $nofollow = '';
 885          if(isset($this->options['nofollow_on']))
 886          {
 887              $nofollow = " rel=\"nofollow\"";
 888          }
 889  
 890          // Fix some entities in URLs
 891          $entities = array('$' => '%24', '&#36;' => '%24', '^' => '%5E', '`' => '%60', '[' => '%5B', ']' => '%5D', '{' => '%7B', '}' => '%7D', '"' => '%22', '<' => '%3C', '>' => '%3E', ' ' => '%20');
 892          $fullurl = str_replace(array_keys($entities), array_values($entities), $fullurl);
 893  
 894          $name = preg_replace("#&amp;\#([0-9]+);#si", "&#$1;", $name); // Fix & but allow unicode
 895          $link = "<a href=\"$fullurl\" target=\"_blank\"{$nofollow}>$name</a>";
 896          return $link;
 897      }
 898  
 899      /**
 900       * Parses IMG MyCode.
 901       *
 902       * @param string The URL to the image
 903       * @param array Optional array of dimensions
 904       */
 905  	function mycode_parse_img($url, $dimensions=array(), $align='')
 906      {
 907          global $lang;
 908          $url = trim($url);
 909          $url = str_replace("\n", "", $url);
 910          $url = str_replace("\r", "", $url);
 911          if($align == "right")
 912          {
 913              $css_align = " style=\"float: right;\"";
 914          }
 915          else if($align == "left")
 916          {
 917              $css_align = " style=\"float: left;\"";
 918          }
 919          $alt = htmlspecialchars_uni(basename($url));
 920          if(my_strlen($alt) > 55)
 921          {
 922              $alt = my_substr($alt, 0, 40)."...".my_substr($alt, -10);
 923          }
 924          $alt = $lang->sprintf($lang->posted_image, $alt);
 925          if($dimensions[0] > 0 && $dimensions[1] > 0)
 926          {
 927              return "<img src=\"{$url}\" width=\"{$dimensions[0]}\" height=\"{$dimensions[1]}\" border=\"0\" alt=\"{$alt}\"{$css_align} />";
 928          }
 929          else
 930          {
 931              return "<img src=\"{$url}\" border=\"0\" alt=\"{$alt}\"{$css_align} />";            
 932          }
 933      }
 934  
 935      /**
 936      * Parses email MyCode.
 937      *
 938      * @param string The email address to link to.
 939      * @param string The name for the link.
 940      * @return string The built-up email link.
 941      */
 942  	function mycode_parse_email($email, $name="")
 943      {
 944          $name = str_replace("\\'", "'", $name);
 945          $email = str_replace("\\'", "'", $email);
 946          if(!$name)
 947          {
 948              $name = $email;
 949          }
 950          if(preg_match("/^([a-zA-Z0-9-_\+\.]+?)@[a-zA-Z0-9-]+\.[a-zA-Z0-9\.-]+$/si", $email))
 951          {
 952              return "<a href=\"mailto:$email\">".$name."</a>";
 953          }
 954          else
 955          {
 956              return $email;
 957          }
 958      }
 959      
 960  	function mycode_parse_video($video, $url)
 961      {
 962          global $templates;
 963          
 964          if(empty($video) || empty($url))
 965          {
 966              return "[video={$video}]{$url}[/video]";
 967          }
 968          
 969          $parsed_url = @parse_url($url);
 970          if($parsed_url == false)
 971          {
 972              return "[video={$video}]{$url}[/video]";;
 973          }
 974          
 975          $fragments = array();
 976          if($parsed_url['fragment'])
 977          {
 978              $fragments = explode("&", $parsed_url['fragment']);
 979          }
 980          
 981          $queries = explode("&", $parsed_url['query']);
 982          
 983          $input = array();
 984          foreach($queries as $query)
 985          {
 986              list($key, $value) = explode("=", $query);
 987              $key = str_replace("amp;", "", $key);
 988              $input[$key] = $value;
 989          }
 990          
 991          $path = explode('/', $parsed_url['path']);
 992          
 993          switch($video)
 994          {
 995              case "dailymotion":
 996                  list($id, ) = split("_", $path[2], 1); // http://www.dailymotion.com/video/fds123_title-goes-here
 997                  break;
 998              case "metacafe":
 999                  $id = $path[2]; // http://www.metacafe.com/watch/fds123/title_goes_here/
1000                  $title = htmlspecialchars_uni($path[3]);
1001                  break;
1002              case "myspacetv":
1003                  $id = $input['videoid']; // http://myspacetv.com/index.cfm?fuseaction=vids.individual&videoid=fds123
1004                  break;
1005              case "yahoo":
1006                  $id = $path[3]; // http://video.yahoo.com/watch/fds123/abc567
1007                  $vid = htmlspecialchars_uni($path[2]);
1008                  break;
1009              case "vimeo":
1010                  $id = $path[1]; // http://vimeo.com/fds123
1011                  break;
1012              case "youtube":
1013                  if($fragments[0])
1014                  {
1015                      $id = str_replace('!v=', '', $fragments[0]); // http://www.youtube.com/watch#!v=fds123
1016                  }
1017                  elseif($input['v'])
1018                  {
1019                      $id = $input['v']; // http://www.youtube.com/watch?v=fds123
1020                  }
1021                  else
1022                  {
1023                      $id = $path[1]; // http://www.youtu.be/fds123
1024                  }
1025                  break;
1026              default:
1027                  return "[video={$video}]{$url}[/video]";
1028          }
1029  
1030          if(empty($id) || ($video == "yahoo" && empty($vid)))
1031          {
1032              return "[video={$video}]{$url}[/video]";
1033          }
1034          
1035          $id = htmlspecialchars_uni($id);
1036          
1037          eval("\$video_code = \"".$templates->get("video_{$video}_embed")."\";");
1038          
1039          return $video_code;
1040      }
1041  
1042      /**
1043      * Parses URLs automatically.
1044      *
1045      * @param string The message to be parsed
1046      * @return string The parsed message.
1047      */
1048  	function mycode_auto_url($message)
1049      {    
1050          $message = " ".$message;
1051          $message = preg_replace("#([\>\s\(\)])(http|https|ftp|news){1}://([^\/\"\s\<\[\.]+\.([^\/\"\s\<\[\.]+\.)*[\w]+(:[0-9]+)?(/[^\"\s<\[]*)?)#i", "$1[url]$2://$3[/url]", $message);
1052          $message = preg_replace("#([\>\s\(\)])(www|ftp)\.(([^\/\"\s\<\[\.]+\.)*[\w]+(:[0-9]+)?(/[^\"\s<\[]*)?)#i", "$1[url]$2.$3[/url]", $message);
1053          $message = my_substr($message, 1);
1054          
1055          return $message;
1056      }
1057  
1058      /**
1059      * Parses list MyCode.
1060      *
1061      * @param string The message to be parsed
1062      * @param string The list type
1063      * @param boolean Are we formatting as text?
1064      * @return string The parsed message.
1065      */
1066  	function mycode_parse_list($message, $type="")
1067      {
1068          $message = str_replace('\"', '"', $message);
1069          $message = preg_replace("#\s*\[\*\]\s*#", "</li>\n<li>", $message);
1070          $message .= "</li>";
1071  
1072          if($type)
1073          {
1074              $list = "\n<ol type=\"$type\">$message</ol>\n";
1075          }
1076          else
1077          {
1078              $list = "<ul>$message</ul>\n";
1079          }
1080          $list = preg_replace("#<(ol type=\"$type\"|ul)>\s*</li>#", "<$1>", $list);
1081          return $list;
1082      }
1083  
1084      /**
1085       * Strips smilies from a string
1086        *
1087       * @param string The message for smilies to be stripped from
1088       * @return string The message with smilies stripped
1089       */
1090  	function strip_smilies($message)
1091      {
1092          if($this->smilies_cache == 0)
1093          {
1094              $this->cache_smilies();
1095          }
1096          if(is_array($this->smilies_cache))
1097          {
1098              $message = str_replace($this->smilies_cache, array_keys($this->smilies_cache), $message);
1099          }
1100          return $message;
1101      }
1102      
1103      /**
1104       * Highlights a string
1105        *
1106       * @param string The message to be highligted
1107       * @param string The highlight keywords
1108       * @return string The message with highlight bbcodes
1109       */
1110  	function highlight_message($message, $highlight)
1111      {
1112          if(empty($this->highlight_cache))
1113          {
1114              $this->highlight_cache = build_highlight_array($highlight);
1115          }
1116          
1117          if(is_array($this->highlight_cache) && !empty($this->highlight_cache))
1118          {
1119              $message = preg_replace(array_keys($this->highlight_cache), $this->highlight_cache, $message);
1120          }
1121          
1122          return $message;
1123      }
1124  
1125      /**
1126       * Parses message to plain text equivalents of MyCode.
1127       *
1128       * @param string The message to be parsed
1129       * @return string The parsed message.
1130       */
1131  	function text_parse_message($message, $options=array())
1132      {
1133          global $plugins;
1134          
1135          // Filter bad words if requested.
1136          if($options['filter_badwords'] != 0)
1137          {
1138              $message = $this->parse_badwords($message);
1139          }
1140  
1141          // Parse quotes first
1142          $message = $this->mycode_parse_quotes($message, true);
1143  
1144          $find = array(
1145              "#\[(b|u|i|s|url|email|color|img)\](.*?)\[/\\1\]#is",
1146              "#\[php\](.*?)\[/php\](\r\n?|\n?)#ise",
1147              "#\[code\](.*?)\[/code\](\r\n?|\n?)#ise",
1148              "#\[img=([0-9]{1,3})x([0-9]{1,3})\](\r\n?|\n?)(https?://([^<>\"']+?))\[/img\]#is",
1149              "#\[url=([a-z]+?://)([^\r\n\"<]+?)\](.+?)\[/url\]#si",
1150              "#\[url=([^\r\n\"<&\(\)]+?)\](.+?)\[/url\]#si",
1151          );
1152          
1153          $replace = array(
1154              "$2",
1155              "\$this->mycode_parse_php('$1', false, true)",
1156              "\$this->mycode_parse_code('$1', true)",
1157              "$4",
1158              "$3 ($1$2)",
1159              "$2 ($1)",
1160          );
1161          $message = preg_replace($find, $replace, $message);
1162          
1163          // Replace "me" code and slaps if we have a username
1164          if($options['me_username'])
1165          {
1166              global $lang;
1167              
1168              $message = preg_replace('#(>|^|\r|\n)/me ([^\r\n<]*)#i', "\\1* {$options['me_username']} \\2", $message);
1169              $message = preg_replace('#(>|^|\r|\n)/slap ([^\r\n<]*)#i', "\\1* {$options['me_username']} {$lang->slaps} \\2 {$lang->with_trout}", $message);
1170          }
1171  
1172          // Special code requiring special attention
1173          while(preg_match("#\[list\](.*?)\[/list\]#esi", $message))
1174          {
1175              $message = preg_replace("#\s?\[list\](.*?)\[/list\](\r\n?|\n?)#esi", "\$this->mycode_parse_list('$1')\n", $message);
1176          }
1177  
1178          // Replace lists.
1179          while(preg_match("#\[list=(a|A|i|I|1)\](.*?)\[/list\](\r\n?|\n?)#esi", $message))
1180          {
1181              $message = preg_replace("#\s?\[list=(a|A|i|I|1)\](.*?)\[/list\]#esi", "\$this->mycode_parse_list('$2', '$1')\n", $message);
1182          }
1183  
1184          // Run plugin hooks
1185          $message = $plugins->run_hooks("text_parse_message", $message);
1186          
1187          return $message;
1188      }
1189  }
1190  ?>


Generated: Sun Dec 11 14:16:27 2011 Cross-referenced by PHPXref 0.7.1