Example #1
0
 public function parseString(PHPTAL_Dom_DocumentBuilder $builder, $src, $filename = '<string>')
 {
     try {
         $builder->setEncoding($this->input_encoding);
         $this->_file = $filename;
         $this->_line = 1;
         $state = self::ST_ROOT;
         $mark = 0;
         $len = strlen($src);
         $quoteStyle = '"';
         $tagname = "";
         $attribute = "";
         $attributes = array();
         $customDoctype = false;
         $builder->setSource($this->_file, $this->_line);
         $builder->onDocumentStart();
         $i = 0;
         // remove BOM (UTF-8 byte order mark)...
         if (substr($src, 0, 3) === self::BOM_STR) {
             $i = 3;
         }
         for (; $i < $len; $i++) {
             $c = $src[$i];
             // Change to substr($src, $i, 1); if you want to use mb_string.func_overload
             if ($c === "\n") {
                 $builder->setSource($this->_file, ++$this->_line);
             }
             switch ($state) {
                 case self::ST_ROOT:
                     if ($c === '<') {
                         $mark = $i;
                         // mark tag start
                         $state = self::ST_LT;
                     } elseif (!self::isWhiteChar($c)) {
                         $this->raiseError("Characters found before beginning of the document! (wrap document in < tal:block > to avoid this error)");
                     }
                     break;
                 case self::ST_TEXT:
                     if ($c === '<') {
                         if ($mark != $i) {
                             $builder->onElementData($this->sanitizeEscapedText($this->checkEncoding(substr($src, $mark, $i - $mark))));
                         }
                         $mark = $i;
                         $state = self::ST_LT;
                     }
                     break;
                 case self::ST_LT:
                     if ($c === '/') {
                         $mark = $i + 1;
                         $state = self::ST_TAG_CLOSE;
                     } elseif ($c === '?' and strtolower(substr($src, $i, 5)) === '?xml ') {
                         $state = self::ST_XMLDEC;
                     } elseif ($c === '?') {
                         $state = self::ST_PREPROC;
                     } elseif ($c === '!' and substr($src, $i, 3) === '!--') {
                         $state = self::ST_COMMENT;
                     } elseif ($c === '!' and substr($src, $i, 8) === '![CDATA[') {
                         $state = self::ST_CDATA;
                         $mark = $i + 8;
                         // past opening tag
                     } elseif ($c === '!' and strtoupper(substr($src, $i, 8)) === '!DOCTYPE') {
                         $state = self::ST_DOCTYPE;
                     } elseif (self::isWhiteChar($c)) {
                         $state = self::ST_TEXT;
                     } else {
                         $mark = $i;
                         // mark node name start
                         $attributes = array();
                         $attribute = "";
                         $state = self::ST_TAG_NAME;
                     }
                     break;
                 case self::ST_TAG_NAME:
                     if (self::isWhiteChar($c) || $c === '/' || $c === '>') {
                         $tagname = substr($src, $mark, $i - $mark);
                         if (!$this->isValidQName($tagname)) {
                             $this->raiseError("Invalid tag name '{$tagname}'");
                         }
                         if ($c === '/') {
                             $state = self::ST_TAG_SINGLE;
                         } elseif ($c === '>') {
                             $mark = $i + 1;
                             // mark text start
                             $state = self::ST_TEXT;
                             $builder->onElementStart($tagname, $attributes);
                         } else {
                             $state = self::ST_TAG_ATTRIBUTES;
                         }
                     }
                     break;
                 case self::ST_TAG_CLOSE:
                     if ($c === '>') {
                         $tagname = rtrim(substr($src, $mark, $i - $mark));
                         $builder->onElementClose($tagname);
                         $mark = $i + 1;
                         // mark text start
                         $state = self::ST_TEXT;
                     }
                     break;
                 case self::ST_TAG_SINGLE:
                     if ($c !== '>') {
                         $this->raiseError("Expected '/>', but found '/{$c}' inside tag < {$tagname} >");
                     }
                     $mark = $i + 1;
                     // mark text start
                     $state = self::ST_TEXT;
                     $builder->onElementStart($tagname, $attributes);
                     $builder->onElementClose($tagname);
                     break;
                 case self::ST_TAG_BETWEEN_ATTRIBUTE:
                 case self::ST_TAG_ATTRIBUTES:
                     if ($c === '>') {
                         $mark = $i + 1;
                         // mark text start
                         $state = self::ST_TEXT;
                         $builder->onElementStart($tagname, $attributes);
                     } elseif ($c === '/') {
                         $state = self::ST_TAG_SINGLE;
                     } elseif (self::isWhiteChar($c)) {
                         $state = self::ST_TAG_ATTRIBUTES;
                     } elseif ($state === self::ST_TAG_ATTRIBUTES && $this->isValidQName($c)) {
                         $mark = $i;
                         // mark attribute key start
                         $state = self::ST_ATTR_KEY;
                     } else {
                         $this->raiseError("Unexpected character '{$c}' between attributes of < {$tagname} >");
                     }
                     break;
                 case self::ST_COMMENT:
                     if ($c === '>' && $i > $mark + 4 && substr($src, $i - 2, 2) === '--') {
                         if (preg_match('/^-|--|-$/', substr($src, $mark + 4, $i - $mark + 1 - 7))) {
                             $this->raiseError("Ill-formed comment. XML comments are not allowed to contain '--' or start/end with '-': " . substr($src, $mark + 4, $i - $mark + 1 - 7));
                         }
                         $builder->onComment($this->checkEncoding(substr($src, $mark + 4, $i - $mark + 1 - 7)));
                         $mark = $i + 1;
                         // mark text start
                         $state = self::ST_TEXT;
                     }
                     break;
                 case self::ST_CDATA:
                     if ($c === '>' and substr($src, $i - 2, 2) === ']]') {
                         $builder->onCDATASection($this->checkEncoding(substr($src, $mark, $i - $mark - 2)));
                         $mark = $i + 1;
                         // mark text start
                         $state = self::ST_TEXT;
                     }
                     break;
                 case self::ST_XMLDEC:
                     if ($c === '?' && substr($src, $i, 2) === '?>') {
                         $builder->onXmlDecl($this->checkEncoding(substr($src, $mark, $i - $mark + 2)));
                         $i++;
                         // skip '>'
                         $mark = $i + 1;
                         // mark text start
                         $state = self::ST_TEXT;
                     }
                     break;
                 case self::ST_DOCTYPE:
                     if ($c === '[') {
                         $customDoctype = true;
                     } elseif ($customDoctype && $c === '>' && substr($src, $i - 1, 2) === ']>') {
                         $customDoctype = false;
                         $builder->onDocType($this->checkEncoding(substr($src, $mark, $i - $mark + 1)));
                         $mark = $i + 1;
                         // mark text start
                         $state = self::ST_TEXT;
                     } elseif (!$customDoctype && $c === '>') {
                         $customDoctype = false;
                         $builder->onDocType($this->checkEncoding(substr($src, $mark, $i - $mark + 1)));
                         $mark = $i + 1;
                         // mark text start
                         $state = self::ST_TEXT;
                     }
                     break;
                 case self::ST_PREPROC:
                     if ($c === '>' and substr($src, $i - 1, 1) === '?') {
                         $builder->onProcessingInstruction($this->checkEncoding(substr($src, $mark, $i - $mark + 1)));
                         $mark = $i + 1;
                         // mark text start
                         $state = self::ST_TEXT;
                     }
                     break;
                 case self::ST_ATTR_KEY:
                     if ($c === '=' || self::isWhiteChar($c)) {
                         $attribute = substr($src, $mark, $i - $mark);
                         if (!$this->isValidQName($attribute)) {
                             $this->raiseError("Invalid attribute name '{$attribute}' in < {$tagname} >");
                         }
                         if (isset($attributes[$attribute])) {
                             $this->raiseError("Attribute {$attribute} in < {$tagname} > is defined more than once");
                         }
                         if ($c === '=') {
                             $state = self::ST_ATTR_VALUE;
                         } else {
                             /* white char */
                             $state = self::ST_ATTR_EQ;
                         }
                     } elseif ($c === '/' || $c === '>') {
                         $attribute = substr($src, $mark, $i - $mark);
                         if (!$this->isValidQName($attribute)) {
                             $this->raiseError("Invalid attribute name '{$attribute}'");
                         }
                         $this->raiseError("Attribute {$attribute} does not have value (found end of tag instead of '=')");
                     }
                     break;
                 case self::ST_ATTR_EQ:
                     if ($c === '=') {
                         $state = self::ST_ATTR_VALUE;
                     } elseif (!self::isWhiteChar($c)) {
                         $this->raiseError("Attribute {$attribute} in < {$tagname} > does not have value (found character '{$c}' instead of '=')");
                     }
                     break;
                 case self::ST_ATTR_VALUE:
                     if (self::isWhiteChar($c)) {
                     } elseif ($c === '"' or $c === '\'') {
                         $quoteStyle = $c;
                         $state = self::ST_ATTR_QUOTE;
                         $mark = $i + 1;
                         // mark attribute real value start
                     } else {
                         $this->raiseError("Value of attribute {$attribute} in < {$tagname} > is not in quotes (found character '{$c}' instead of quote)");
                     }
                     break;
                 case self::ST_ATTR_QUOTE:
                     if ($c === $quoteStyle) {
                         $attributes[$attribute] = $this->sanitizeEscapedText($this->checkEncoding(substr($src, $mark, $i - $mark)));
                         // PHPTAL's code generator assumes input is escaped for double-quoted strings. Single-quoted attributes need to be converted.
                         // FIXME: it should be escaped at later stage.
                         $attributes[$attribute] = str_replace('"', "&quot;", $attributes[$attribute]);
                         $state = self::ST_TAG_BETWEEN_ATTRIBUTE;
                     }
                     break;
             }
         }
         if ($state === self::ST_TEXT) {
             if ($i > $mark) {
                 $text = substr($src, $mark, $i - $mark);
                 if (!ctype_space($text)) {
                     $this->raiseError("Characters found after end of the root element (wrap document in < tal:block > to avoid this error)");
                 }
             }
         } else {
             if ($state === self::ST_ROOT) {
                 $msg = "Document does not have any tags";
             } else {
                 $msg = "Finished document in unexpected state: " . self::$state_names[$state] . " is not finished";
             }
             $this->raiseError($msg);
         }
         $builder->onDocumentEnd();
     } catch (PHPTAL_TemplateException $e) {
         $e->hintSrcPosition($this->_file, $this->_line);
         throw $e;
     }
     return $builder;
 }
Example #2
0
 public function __construct()
 {
     $this->result = '';
     parent::__construct();
 }
Example #3
0
 /**
  * parse currently set template
  * @return string (compiled PHP code)
  */
 protected function parse()
 {
     self::setIncludePath();
     require_once 'PHPTAL/Dom/DocumentBuilder.php';
     require_once 'PHPTAL/Php/CodeGenerator.php';
     self::restoreIncludePath();
     // instantiate the PHPTAL source parser
     $parser = new PHPTAL_Dom_SaxXmlParser($this->_encoding);
     $builder = new PHPTAL_Dom_DocumentBuilder();
     $builder->stripComments($this->_stripComments);
     $data = $this->_source->getData();
     $realpath = $this->_source->getRealPath();
     if ($this->_prefilter) {
         $data = $this->_prefilter->filter($data);
     }
     $tree = $parser->parseString($builder, $data, $realpath)->getResult();
     $generator = new PHPTAL_Php_CodeGenerator($this->getFunctionName(), $this->_source->getRealPath(), $this->_encoding, $this->_outputMode, $this->getCodePath());
     $result = $generator->generateCode($tree);
     return $result;
 }