* @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] = '
';
}
}
}
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;
}
}