protected function processStartTag(Tag $tag) { $tagName = $tag->getName(); $tagConfig = $this->tagsConfig[$tagName]; if ($this->cntTotal[$tagName] >= $tagConfig['tagLimit']) { $this->logger->err('Tag limit exceeded', array('tag' => $tag, 'tagName' => $tagName, 'tagLimit' => $tagConfig['tagLimit'])); $tag->invalidate(); return; } if (!$this->filterTag($tag)) { $tag->invalidate(); return; } if ($this->fosterParent($tag) || $this->closeParent($tag) || $this->closeAncestor($tag)) { return; } if ($this->cntOpen[$tagName] >= $tagConfig['nestingLimit']) { $this->logger->err('Nesting limit exceeded', array('tag' => $tag, 'tagName' => $tagName, 'nestingLimit' => $tagConfig['nestingLimit'])); $tag->invalidate(); return; } if (!$this->tagIsAllowed($tagName)) { $msg = 'Tag is not allowed in this context'; $context = array('tag' => $tag, 'tagName' => $tagName); if ($tag->getLen() > 0) { $this->logger->warn($msg, $context); } else { $this->logger->debug($msg, $context); } $tag->invalidate(); return; } if ($this->requireAncestor($tag)) { $tag->invalidate(); return; } if ($tag->getFlags() & self::RULE_AUTO_CLOSE && !$tag->getEndTag() && !$this->isFollowedByClosingTag($tag)) { $newTag = new Tag(Tag::SELF_CLOSING_TAG, $tagName, $tag->getPos(), $tag->getLen()); $newTag->setAttributes($tag->getAttributes()); $newTag->setFlags($tag->getFlags()); $tag = $newTag; } if ($tag->getFlags() & self::RULE_TRIM_FIRST_LINE && !$tag->getEndTag() && \substr($this->text, $tag->getPos() + $tag->getLen(), 1) === "\n") { $this->addIgnoreTag($tag->getPos() + $tag->getLen(), 1); } $this->outputTag($tag); $this->pushContext($tag); $this->createChild($tag); }
/** * @testdox setAttributes() removes all other attributes */ public function testSetAttributesNuke() { $tag = new Tag(Tag::START_TAG, 'X', 0, 0); $tag->setAttribute('x', 'x'); $tag->setAttributes(['foo' => 'bar', 'baz' => 'quux']); $this->assertSame(['foo' => 'bar', 'baz' => 'quux'], $tag->getAttributes()); }
/** * Process given start tag (including self-closing tags) at current position * * @param Tag $tag Start tag (including self-closing) * @return void */ protected function processStartTag(Tag $tag) { $tagName = $tag->getName(); $tagConfig = $this->tagsConfig[$tagName]; // 1. Check that this tag has not reached its global limit tagLimit // 2. Execute this tag's filterChain, which will filter/validate its attributes // 3. Apply closeParent, closeAncestor and fosterParent rules // 4. Check for nestingLimit // 5. Apply requireAncestor rules // // This order ensures that the tag is valid and within the set limits before we attempt to // close parents or ancestors. We need to close ancestors before we can check for nesting // limits, whether this tag is allowed within current context (the context may change // as ancestors are closed) or whether the required ancestors are still there (they might // have been closed by a rule.) if ($this->cntTotal[$tagName] >= $tagConfig['tagLimit']) { $this->logger->err('Tag limit exceeded', ['tag' => $tag, 'tagName' => $tagName, 'tagLimit' => $tagConfig['tagLimit']]); $tag->invalidate(); return; } if (!$this->filterTag($tag)) { $tag->invalidate(); return; } if ($this->fosterParent($tag) || $this->closeParent($tag) || $this->closeAncestor($tag)) { // This tag parent/ancestor needs to be closed, we just return (the tag is still valid) return; } if ($this->cntOpen[$tagName] >= $tagConfig['nestingLimit']) { $this->logger->err('Nesting limit exceeded', ['tag' => $tag, 'tagName' => $tagName, 'nestingLimit' => $tagConfig['nestingLimit']]); $tag->invalidate(); return; } if (!$this->tagIsAllowed($tagName)) { $msg = 'Tag is not allowed in this context'; $context = ['tag' => $tag, 'tagName' => $tagName]; if ($tag->getLen() > 0) { $this->logger->warn($msg, $context); } else { $this->logger->debug($msg, $context); } $tag->invalidate(); return; } if ($this->requireAncestor($tag)) { $tag->invalidate(); return; } // If this tag has an autoClose rule and it's not paired with an end tag or followed by an // end tag, we replace it with a self-closing tag with the same properties if ($tag->getFlags() & self::RULE_AUTO_CLOSE && !$tag->getEndTag() && !$this->isFollowedByClosingTag($tag)) { $newTag = new Tag(Tag::SELF_CLOSING_TAG, $tagName, $tag->getPos(), $tag->getLen()); $newTag->setAttributes($tag->getAttributes()); $newTag->setFlags($tag->getFlags()); $tag = $newTag; } if ($tag->getFlags() & self::RULE_TRIM_FIRST_LINE && !$tag->getEndTag() && substr($this->text, $tag->getPos() + $tag->getLen(), 1) === "\n") { $this->addIgnoreTag($tag->getPos() + $tag->getLen(), 1); } // This tag is valid, output it and update the context $this->outputTag($tag); $this->pushContext($tag); }