Beispiel #1
0
 /**
  * This is the next step in parsing a tag. It's possible for it to still be invalid at this
  * point but many of the basic invalid tag name conditions have already been handled.
  *
  * @param $parent  the current parent element
  * @param $tokenizer  the tokenizer we're using
  * @param $tagContent  the text between the [ and the ], assuming there is actually a ]
  *
  * @return the new parent element
  */
 protected function parseTag(ElementNode $parent, Tokenizer $tokenizer, $tagContent)
 {
     $next;
     if (!$tokenizer->hasNext() || ($next = $tokenizer->next()) != ']') {
         /* This is a malformed tag. Both the previous [ and the tagContent
          * is really just plain text. */
         $this->createTextNode($parent, '[');
         $this->createTextNode($parent, $tagContent);
         return $parent;
     }
     /* This is a well-formed tag consisting of [something] or [/something], but
      * we still need to ensure that 'something' is a valid tag name. Additionally,
      * if it's a closing tag, we need to ensure that there was a previous matching
      * opening tag.
      */
     /* There could be an attribute. */
     $tagPieces = explode('=', $tagContent);
     $tmpTagName = $tagPieces[0];
     $actualTagName;
     if ('/' == $tmpTagName[0]) {
         /* This is a closing tag name. */
         $actualTagName = substr($tmpTagName, 1);
     } else {
         $actualTagName = $tmpTagName;
     }
     if ('/' == $tmpTagName[0]) {
         /* This is attempting to close an open tag. We must verify that there exists an
          * open tag of the same type and that there is no option (options on closing
          * tags don't make any sense). */
         $elToClose = $parent->closestParentOfType($actualTagName);
         if (null == $elToClose || count($tagPieces) > 1) {
             /* Closing an unopened tag or has an option. Treat everything as plain text. */
             $this->createTextNode($parent, '[');
             $this->createTextNode($parent, $tagContent);
             $this->createTextNode($parent, ']');
             return $parent;
         } else {
             /* We're closing $elToClose. In order to do that, we just need to return
              * $elToClose's parent, since that will change our effective parent to be
              * elToClose's parent. */
             return $elToClose->getParent();
         }
     }
     /* Verify that this is a known bbcode tag name. */
     if ('' == $actualTagName || !$this->codeExists($actualTagName, count($tagPieces) > 1)) {
         /* This is an invalid tag name! Treat everything we've seen as plain text. */
         $this->createTextNode($parent, '[');
         $this->createTextNode($parent, $tagContent);
         $this->createTextNode($parent, ']');
         return $parent;
     }
     /* If we're here, this is a valid opening tag. Let's make a new node for it. */
     $el = new ElementNode();
     $el->setNodeId(++$this->nextNodeid);
     $code = $this->getCode($actualTagName, count($tagPieces) > 1);
     $el->setCodeDefinition($code);
     if (count($tagPieces) > 1) {
         /* We have an attribute we should save. */
         unset($tagPieces[0]);
         $el->setAttribute(implode('=', $tagPieces));
     }
     $parent->addChild($el);
     return $el;
 }
Beispiel #2
0
 /**
  * Constructs the parse tree from a string of bbcode markup.
  * 
  * @param string $str   the bbcode markup to parse
  */
 public function parse($str)
 {
     $this->reset();
     $parent = $this->treeRoot;
     $tokenManager = new TokenManager($str);
     $nodeid = 1;
     $inTag = false;
     while ($tokenManager->hasCurrent()) {
         // tokens are either "[", "]" or a string that contains neither a opening bracket nor a closing bracket
         if ($inTag) {
             // this token should be a tag name
             // explode by = in case there's an attribute
             $pieces = explode('=', $tokenManager->getCurrent(), 2);
             // check if it's a closing tag
             if (substr($pieces[0], 0, 1) == "/") {
                 $tagName = substr($pieces[0], 1);
                 $closing = true;
             } else {
                 $tagName = $pieces[0];
                 $closing = false;
             }
             if (($this->codeExists($tagName, isset($pieces[1])) || $closing && $this->codeExists($tagName, true)) && $tokenManager->hasNext() && $tokenManager->next() == "]") {
                 if ($closing) {
                     $closestParent = $parent->closestParentOfType($tagName);
                     if ($closestParent != null && $closestParent->hasParent()) {
                         // closing an element... move to this element's parent
                         $parent->getCodeDefinition()->decrementCounter();
                         $parent = $closestParent->getParent();
                         $tokenManager->advance();
                         $tokenManager->advance();
                         $inTag = false;
                         continue;
                     }
                 } else {
                     // new element
                     $el = new ElementNode();
                     $code = $this->getCode($tagName, isset($pieces[1]));
                     $code->incrementCounter();
                     $el->setNestDepth($code->getCounter());
                     $el->setCodeDefinition($code);
                     $el->setTagName($tagName);
                     $el->setNodeId($nodeid++);
                     if (isset($pieces[1])) {
                         $el->setAttribute($pieces[1]);
                     }
                     $parent->addChild($el);
                     $parent = $el;
                     $tokenManager->advance();
                     $tokenManager->advance();
                     $inTag = false;
                     continue;
                 }
             }
             // the opening bracket that sent us in here was really just plain text
             $node = new TextNode("[");
             $node->setNodeId($nodeid++);
             $parent->addChild($node);
             $inTag = false;
             // treat this token as regular text, and let the next if...else structure handle it as regular text
         }
         if ($tokenManager->getCurrent() == "[") {
             $inTag = true;
         } else {
             $node = new TextNode($tokenManager->getCurrent());
             $node->setNodeId($nodeid++);
             $parent->addChild($node);
         }
         $tokenManager->advance();
     }
 }