Enforcing a limit of 50 smilies per parsed message
authorAlexander Ebert <ebert@woltlab.com>
Tue, 8 Nov 2016 10:03:56 +0000 (11:03 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Tue, 8 Nov 2016 10:03:56 +0000 (11:03 +0100)
Exceeding smilies will be ignored:
- `<img>` will be reverted into the textual representation
- text smilies will be left untouched

The limit is enforced for both types of smilies that could occur, for
example having 47 smilies using `<img>` will cause at maximum 3 text
smilies to be converted into actual images.

wcfsetup/install/files/lib/system/bbcode/SimpleMessageParser.class.php
wcfsetup/install/files/lib/system/html/input/node/HtmlInputNodeImg.class.php
wcfsetup/install/files/lib/system/html/input/node/HtmlInputNodeProcessor.class.php
wcfsetup/install/files/lib/system/html/input/node/HtmlInputNodeTextParser.class.php

index 7196737972a20fefb54e2d00a6c7d42e75bf5f69..5a253a390be526056152a974a1e353868032971d 100644 (file)
@@ -220,9 +220,16 @@ class SimpleMessageParser extends SingletonFactory {
         * @return      string          text
         */
        public function parseSmilies($text) {
+               $smileyCount = 0;
                foreach ($this->smilies as $code => $html) {
-                       //$text = preg_replace('~(?<!&\w{2}|&\w{3}|&\w{4}|&\w{5}|&\w{6}|&#\d{2}|&#\d{3}|&#\d{4}|&#\d{5})'.preg_quote(StringUtil::encodeHTML($code), '~').'(?![^<]*>)~', $html, $text);
-                       $text = preg_replace('~(?<=^|\s)'.preg_quote(StringUtil::encodeHTML($code), '~').'(?=$|\s|<br />|<br>)~', $html, $text);
+                       $text = preg_replace_callback('~(?<=^|\s)'.preg_quote(StringUtil::encodeHTML($code), '~').'(?=$|\s|<br />|<br>)~', function() use ($code, $html, &$smileyCount) {
+                               if ($smileyCount === 50) {
+                                       return $code;
+                               }
+                               
+                               $smileyCount++;
+                               return $html;
+                       }, $text);
                }
                
                return $text;
index 3c5a2ef16a503fce2e3dd958e5a57f6fc742df4b..2dedd889cb625e68715a82707d57fb40c7d2feed 100644 (file)
@@ -17,6 +17,12 @@ use wcf\util\JSON;
  * @since       3.0
  */
 class HtmlInputNodeImg extends AbstractHtmlInputNode {
+       /**
+        * number of found smilies
+        * @var integer
+        */
+       protected $smiliesFound = 0;
+       
        /**
         * @inheritDoc
         */
@@ -53,6 +59,8 @@ class HtmlInputNodeImg extends AbstractHtmlInputNode {
         * @inheritDoc
         */
        public function process(array $elements, AbstractHtmlNodeProcessor $htmlNodeProcessor) {
+               $this->smiliesFound = 0;
+               
                /** @var \DOMElement $element */
                foreach ($elements as $element) {
                        $class = $element->getAttribute('class');
@@ -68,6 +76,15 @@ class HtmlInputNodeImg extends AbstractHtmlInputNode {
                }
        }
        
+       /**
+        * Returns the number of smilies found within the message.
+        * 
+        * @return      integer
+        */
+       public function getSmileyCount() {
+               return $this->smiliesFound;
+       }
+       
        /**
         * Replaces image element with attachment metacode element. 
         * 
@@ -148,7 +165,7 @@ class HtmlInputNodeImg extends AbstractHtmlInputNode {
                
                /** @var Smiley $smiley */
                $smiley = SmileyCache::getInstance()->getSmileyByCode($code);
-               if ($smiley === null) {
+               if ($smiley === null || $this->smiliesFound === 50) {
                        $element->parentNode->insertBefore($element->ownerDocument->createTextNode($code), $element);
                        $element->parentNode->removeChild($element);
                }
@@ -161,6 +178,8 @@ class HtmlInputNodeImg extends AbstractHtmlInputNode {
                        
                        if ($smiley->smileyPath2x) $element->setAttribute('srcset', $smiley->getURL2x() . ' 2x');
                        else $element->removeAttribute('srcset');
+                       
+                       $this->smiliesFound++;
                }
        }
 }
index 82640971fba8420a62d122352e2d37682c15733e..55d4880fc0a30f3d0c05646789749c2635ed5775 100644 (file)
@@ -63,7 +63,9 @@ class HtmlInputNodeProcessor extends AbstractHtmlNodeProcessor {
                        $this->enforceQuoteDepth(MESSAGE_MAX_QUOTE_DEPTH);
                }
                
-               $this->invokeHtmlNode(new HtmlInputNodeImg());
+               $imgNodeHandler = new HtmlInputNodeImg();
+               $this->invokeHtmlNode($imgNodeHandler);
+               $smileyCount = $imgNodeHandler->getSmileyCount();
                
                // dynamic node handlers
                $this->invokeNodeHandlers('wcf\system\html\input\node\HtmlInputNode', ['img', 'woltlab-metacode']);
@@ -72,7 +74,7 @@ class HtmlInputNodeProcessor extends AbstractHtmlNodeProcessor {
                $this->trim();
                
                // detect mentions, urls, emails and smileys
-               $textParser = new HtmlInputNodeTextParser($this);
+               $textParser = new HtmlInputNodeTextParser($this, $smileyCount);
                $textParser->parse();
                
                // strip invalid class names
index c1922cda2f4981f934faaf6a03e6e65afc5578fa..7894724c60e8f1c11bee04c3857397ef606d3749 100644 (file)
@@ -37,6 +37,12 @@ class HtmlInputNodeTextParser {
         */
        protected $nodeStack = [];
        
+       /**
+        * number of found smilies
+        * @var integer
+        */
+       protected $smileyCount = 0;
+       
        /**
         * list of smilies by smiley code
         * @var Smiley[]
@@ -76,12 +82,15 @@ class HtmlInputNodeTextParser {
         * HtmlInputNodeTextParser constructor.
         * 
         * @param HtmlInputNodeProcessor $htmlInputNodeProcessor
+        * @param integer $smileyCount
         */
-       public function __construct(HtmlInputNodeProcessor $htmlInputNodeProcessor) {
+       public function __construct(HtmlInputNodeProcessor $htmlInputNodeProcessor, $smileyCount = 0) {
                $this->htmlInputNodeProcessor = $htmlInputNodeProcessor;
                $this->sourceBBCodes = HtmlBBCodeParser::getInstance()->getSourceBBCodes();
                
                if (MODULE_SMILEY) {
+                       $this->smileyCount = $smileyCount;
+                       
                        // get smilies
                        $smilies = SmileyCache::getInstance()->getSmilies();
                        $categories = SmileyCache::getInstance()->getCategories();
@@ -185,7 +194,9 @@ class HtmlInputNodeTextParser {
                                $value = $this->parseEmail($node, $value);
                        }
                        
-                       $value = $this->parseSmiley($node, $value);
+                       if ($this->smileyCount !== 50) {
+                               $value = $this->parseSmiley($node, $value);
+                       }
                        
                        if ($value !== $oldValue) {
                                $node->textContent = $value;
@@ -456,7 +467,11 @@ class HtmlInputNodeTextParser {
                
                return preg_replace_callback($smileyPattern, function($matches) use ($text) {
                        $smileyCode = $matches[0];
+                       if ($this->smileyCount === 50) {
+                               return $smileyCode;
+                       }
                        
+                       $this->smileyCount++;
                        $smiley = $this->smilies[$smileyCode];
                        $element = $text->ownerDocument->createElement('img');
                        $element->setAttribute('src', $smiley->getURL());