From 632bce65cbcb3656d2be50d40527b01c1b424fab Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Mon, 18 Jul 2016 15:25:28 +0200 Subject: [PATCH] Ignore unclosed bbcodes --- .../system/bbcode/HtmlBBCodeParser.class.php | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/wcfsetup/install/files/lib/system/bbcode/HtmlBBCodeParser.class.php b/wcfsetup/install/files/lib/system/bbcode/HtmlBBCodeParser.class.php index d3acbf260e..de926a6e54 100644 --- a/wcfsetup/install/files/lib/system/bbcode/HtmlBBCodeParser.class.php +++ b/wcfsetup/install/files/lib/system/bbcode/HtmlBBCodeParser.class.php @@ -41,7 +41,11 @@ class HtmlBBCodeParser extends BBCodeParser { // difference to the original implementation: sourcecode bbcodes are handled too $this->buildTagArray(false); + // difference to the original implementation: we don't care for unclosed tags, + // they'll be marked as invalid and removed at the end, leaving lonely opening + // tags that will eventually be removed within the marker processor $this->buildXMLStructure(); + $this->buildParsedString(); return $this->parsedText; @@ -139,6 +143,94 @@ class HtmlBBCodeParser extends BBCodeParser { if (isset($this->textArray[$i + 1])) $this->parsedText .= $this->textArray[$i + 1]; } + /** + * @inheritDoc + */ + public function buildXMLStructure() { + // stack for open tags + $openTagStack = $openTagDataStack = []; + $newTagArray = []; + $newTextArray = []; + + $i = -1; + foreach ($this->tagArray as $i => $tag) { + if ($tag['closing']) { + // closing tag + if (in_array($tag['name'], $openTagStack) && $this->isAllowed($openTagStack, $tag['name'], true)) { + // close unclosed tags + while (($previousTag = end($openTagStack)) != $tag['name']) { + $nextIndex = count($newTagArray); + + // mark as invalid and do not flag as opened tag + $newTag = $this->buildTag('[/'.end($openTagStack).']'); + $newTag['invalid'] = true; + + $newTagArray[$nextIndex] = $newTag; + if (!isset($newTextArray[$nextIndex])) $newTextArray[$nextIndex] = ''; + $newTextArray[$nextIndex] .= $this->textArray[$i]; + $this->textArray[$i] = ''; + array_pop($openTagStack); + array_pop($openTagDataStack); + } + + $nextIndex = count($newTagArray); + $newTagArray[$nextIndex] = $tag; + array_pop($openTagStack); + array_pop($openTagDataStack); + if (!isset($newTextArray[$nextIndex])) $newTextArray[$nextIndex] = ''; + $newTextArray[$nextIndex] .= $this->textArray[$i]; + } + else { + // no such tag open + // handle as plain text + $this->textArray[$i] .= $tag['source']; + $last = count($newTagArray); + if (!isset($newTextArray[$last])) $newTextArray[$last] = ''; + $newTextArray[$last] .= $this->textArray[$i]; + } + } + else { + // opening tag + if ($this->isAllowed($openTagStack, $tag['name']) && $this->isValidTag($tag)) { + $openTagStack[] = $tag['name']; + $openTagDataStack[] = $tag; + $nextIndex = count($newTagArray); + $newTagArray[$nextIndex] = $tag; + if (!isset($newTextArray[$nextIndex])) $newTextArray[$nextIndex] = ''; + $newTextArray[$nextIndex] .= $this->textArray[$i]; + } + else { + // tag not allowed + $this->textArray[$i] .= $tag['source']; + $last = count($newTagArray); + if (!isset($newTextArray[$last])) $newTextArray[$last] = ''; + $newTextArray[$last] .= $this->textArray[$i]; + } + } + } + + $last = count($newTagArray); + if (!isset($newTextArray[$last])) $newTextArray[$last] = ''; + $newTextArray[$last] .= $this->textArray[$i + 1]; + + // close unclosed open tags + while (end($openTagStack)) { + $nextIndex = count($newTagArray); + + // mark as invalid + $newTag = $this->buildTag('[/'.end($openTagStack).']'); + $newTag['invalid'] = true; + + $newTagArray[$nextIndex] = $newTag; + if (!isset($newTextArray[$nextIndex])) $newTextArray[$nextIndex] = ''; + array_pop($openTagStack); + array_pop($openTagDataStack); + } + + $this->tagArray = $newTagArray; + $this->textArray = $newTextArray; + } + /** * Builds the bbcode output. * @@ -284,6 +376,11 @@ class HtmlBBCodeParser extends BBCodeParser { throw new SystemException("Tag mismatch, expected '".$name."', got '".$data['name']."'."); } + if (!empty($data['invalid'])) { + // drop invalid closing tags + return ''; + } + return ''; } -- 2.20.1