* @package com.woltlab.wcf * @subpackage system.bbcode * @category Community Framework */ class SimpleMessageParser extends SingletonFactory { /** * forbidden characters * @var string */ protected static $illegalChars = '[^\x0-\x2C\x2E\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+'; /** * list of smilies * @var Smiley[] */ protected $smilies = []; /** * cached URLs * @var string[] */ protected $cachedURLs = []; /** * cached e-mails * @var string[] */ protected $cachedEmails = []; /** * currently parsed message * @var string */ public $message = ''; /** * @inheritDoc */ protected function init() { parent::init(); if (MODULE_SMILEY == 1) { // get smilies $smilies = SmileyCache::getInstance()->getSmilies(); $categories = SmileyCache::getInstance()->getCategories(); foreach ($smilies as $categoryID => $categorySmilies) { if ($categories[$categoryID ?: null]->isDisabled) continue; /** @var Smiley $smiley */ foreach ($categorySmilies as $smiley) { foreach ($smiley->smileyCodes as $smileyCode) { $this->smilies[$smileyCode] = ''.StringUtil::encodeHTML($smiley->smileyCode).''; } } } krsort($this->smilies); } } /** * Parses the given message and returns the parsed message. * * @param string $message * @param boolean $parseURLs * @param boolean $parseSmilies * @return string */ public function parse($message, $parseURLs = true, $parseSmilies = true) { $this->message = $message; $this->cachedURLs = $this->cachedEmails = []; // call event EventHandler::getInstance()->fireAction($this, 'beforeParsing'); // parse urls if ($parseURLs) { $this->message = $this->parseURLs($this->message); } // encode html $this->message = StringUtil::encodeHTML($this->message); // converts newlines to
's $this->message = nl2br($this->message); // parse urls if ($parseURLs) { $this->message = $this->insertCachedURLs($this->message); } // parse smilies if ($parseSmilies) { $this->message = $this->parseSmilies($this->message); } // replace bad html tags (script etc.) $badSearch = ['/(javascript):/i', '/(about):/i', '/(vbscript):/i']; $badReplace = ['$1:', '$1:', '$1:']; $this->message = preg_replace($badSearch, $badReplace, $this->message); // call event EventHandler::getInstance()->fireAction($this, 'afterParsing'); return $this->message; } /** * Parses urls. * * @param string $text * @return string text */ public function parseURLs($text) { // define pattern $urlPattern = '~(?()\[\]{}\s]* (?: [!.,?;(){}]+ [^!.,?;"\'<>()\[\]{}\s]+ )* )? ~ix'; $emailPattern = '~(?cachedURLs[$hash] = $matches[0]; return $hash; } /** * Returns the hash for an matched e-mail in the message. * * @param array $matches * @return string */ protected function cacheEmailsCallback($matches) { $hash = '@@'.StringUtil::getHash(uniqid(microtime()).$matches[0]).'@@'; $this->cachedEmails[$hash] = $matches[0]; return $hash; } /** * Reinserts cached URLs and e-mails. * * @param string $text * @return string */ protected function insertCachedURLs($text) { foreach ($this->cachedURLs as $hash => $url) { // add protocol if necessary if (!preg_match("/[a-z]:\/\//si", $url)) { $url = 'http://'.$url; } $text = str_replace($hash, StringUtil::getAnchorTag($url), $text); } foreach ($this->cachedEmails as $hash => $email) { $email = StringUtil::encodeHTML($email); $text = str_replace($hash, ''.$email.'', $text); } return $text; } /** * Parses smiley codes. * * @param string $text * @return string text */ public function parseSmilies($text) { foreach ($this->smilies as $code => $html) { //$text = preg_replace('~(?)~', $html, $text); $text = preg_replace('~(?<=^|\s)'.preg_quote(StringUtil::encodeHTML($code), '~').'(?=$|\s|
)~', $html, $text); } return $text; } }