Source for file jTplCompiler.class.php

Documentation is available at jTplCompiler.class.php

  1. <?php
  2. /**
  3. * @package     jelix
  4. * @subpackage  jtpl
  5. * @author      Laurent Jouanneau
  6. * @contributor Loic Mathaud (standalone version), Dominique Papin, DSDenes, Christophe Thiriot, Julien Issler, Brice Tence
  7. * @copyright   2005-2012 Laurent Jouanneau
  8. * @copyright   2006 Loic Mathaud, 2007 Dominique Papin, 2009 DSDenes, 2010 Christophe Thiriot
  9. * @copyright   2010 Julien Issler, 2010 Brice Tence
  10. * @link        http://www.jelix.org
  11. * @licence     GNU Lesser General Public Licence see LICENCE file or http://www.gnu.org/licenses/lgpl.html
  12. */
  13.  
  14. /**
  15.  * This is the compiler of templates: it converts a template into a php file.
  16.  * @package     jelix
  17.  * @subpackage  jtpl
  18.  */
  19. class jTplCompiler
  20.     implements jISimpleCompiler
  21.     {
  22.  
  23.     private $_literals;
  24.  
  25.     /**
  26.      * tokens of variable type
  27.      */
  28.     private  $_vartype = array (T_CHARACTER, T_CONSTANT_ENCAPSED_STRING, T_DNUMBER,
  29.             T_ENCAPSED_AND_WHITESPACE, T_LNUMBER, T_OBJECT_OPERATOR, T_STRING,
  30.             T_WHITESPACE, T_ARRAY);
  31.  
  32.     /**
  33.      * tokens of operators for assignements
  34.      */
  35.     private  $_assignOp = array (T_AND_EQUAL, T_DIV_EQUAL, T_MINUS_EQUAL,
  36.             T_MOD_EQUAL, T_MUL_EQUAL, T_OR_EQUAL, T_PLUS_EQUAL, T_PLUS_EQUAL,
  37.             T_SL_EQUAL, T_SR_EQUAL, T_XOR_EQUAL);
  38.  
  39.     /**
  40.      * tokens of operators for tests
  41.      */
  42.     private  $_op = array (T_BOOLEAN_AND, T_BOOLEAN_OR, T_EMPTY, T_INC, T_DEC,
  43.             T_ISSET, T_IS_EQUAL, T_IS_GREATER_OR_EQUAL, T_IS_IDENTICAL,
  44.             T_IS_NOT_EQUAL, T_IS_NOT_IDENTICAL, T_IS_SMALLER_OR_EQUAL,
  45.             T_LOGICAL_AND, T_LOGICAL_OR, T_LOGICAL_XOR, T_SR, T_SL,
  46.             T_DOUBLE_ARROW);
  47.  
  48.     /**
  49.      * tokens authorized into locale names
  50.      */
  51.     private $_inLocaleOk = array (T_STRING, T_ABSTRACT, T_AS, T_BREAK, T_CASE,
  52.             T_CATCH, T_CLASS, T_CLONE, T_CONST, T_CONTINUE, T_DECLARE, T_DEFAULT,
  53.             T_DNUMBER, T_DO, T_ECHO, T_ELSE, T_ELSEIF, T_EMPTY, T_ENDIF, T_ENDFOR,
  54.             T_EVAL, T_EXIT, T_EXTENDS, T_FINAL, T_FOR, T_FOREACH, T_FUNCTION,
  55.             T_GLOBAL, T_GOTO, T_IF, T_IMPLEMENTS, T_INCLUDE, T_INSTANCEOF, T_INTERFACE,
  56.             T_LIST, T_LNUMBER, T_LOGICAL_AND, T_LOGICAL_OR, T_LOGICAL_XOR,
  57.             T_NAMESPACE, T_NEW, T_PRINT, T_PRIVATE, T_PUBLIC, T_PROTECTED, T_REQUIRE,
  58.             T_RETURN, T_STATIC, T_SWITCH, T_THROW, T_TRY, T_USE, T_VAR, T_WHILE);
  59.  
  60.     /**
  61.      * tokens allowed in output for variables
  62.      */
  63.     protected $_allowedInVar;
  64.  
  65.     /**
  66.      * tokens allowed into expressions
  67.      */
  68.     protected $_allowedInExpr;
  69.  
  70.     /**
  71.      * tokens allowed into assignements
  72.      */
  73.     protected $_allowedAssign;
  74.  
  75.     /**
  76.      * tokens allowed in foreach statements
  77.      */
  78.     protected $_allowedInForeach;
  79.  
  80.     /**
  81.      * tokens not allowed in variable
  82.      */
  83.     protected $_excludedInVar = array (';','=');
  84.  
  85.     protected $_allowedConstants = array ('TRUE','FALSE','NULL', 'M_1_PI',
  86.             'M_2_PI', 'M_2_SQRTPI', 'M_E', 'M_LN10', 'M_LN2', 'M_LOG10E',
  87.             'M_LOG2E', 'M_PI','M_PI_2','M_PI_4','M_SQRT1_2','M_SQRT2');
  88.  
  89.     /**
  90.      * list of plugins paths
  91.      */
  92.     private $_pluginPath = array();
  93.  
  94.     protected $_metaBody = '';
  95.  
  96.     /**
  97.      * native modifiers
  98.      */
  99.     protected $_modifier = array ('upper'=>'strtoupper', 'lower'=>'strtolower',
  100.             'escxml'=>'htmlspecialchars', 'eschtml'=>'htmlspecialchars',
  101.             'strip_tags'=>'strip_tags', 'escurl'=>'rawurlencode',
  102.             'capitalize'=>'ucwords', 'stripslashes'=>'stripslashes',
  103.             'upperfirst'=>'ucfirst');
  104.  
  105.     /**
  106.      * stack of founded blocks
  107.      */
  108.     private $_blockStack = array ();
  109.  
  110.     /**
  111.      * name of the template file
  112.      */
  113.     private $_sourceFile;
  114.  
  115.     /**
  116.      * current parsed jtpl tag
  117.      */
  118.     private $_currentTag;
  119.  
  120.     /**
  121.      * type of the output
  122.      */
  123.     public $outputType = '';
  124.  
  125.     /**
  126.      * true if the template doesn't come from an untrusted source.
  127.      * if it comes from an untrusted source, like a template uploaded by a user,
  128.      * you should set to false.
  129.      */
  130.     public $trusted = true;
  131.  
  132.     /**
  133.      * list of user functions
  134.      */
  135.     protected $_userFunctions = array ();
  136.  
  137.     protected $removeASPtags = true;
  138.  
  139.     /**
  140.      * Initialize some properties
  141.      */
  142.     function __construct () {
  143.         $this->_allowedInVar = array_merge($this->_vartype, array(T_INC, T_DEC, T_DOUBLE_ARROW));
  144.         $this->_allowedInExpr = array_merge($this->_vartype, $this->_op);
  145.         $this->_allowedAssign = array_merge($this->_vartype, $this->_assignOp, $this->_op);
  146.         $this->_allowedInForeach = array_merge($this->_vartype, array(T_AS, T_DOUBLE_ARROW));
  147.  
  148.         $this->removeASPtags = (ini_get("asp_tags") == "1");
  149.  
  150.     }
  151.  
  152.     /**
  153.      * Launch the compilation of a template
  154.      *
  155.      * Store the result (a php content) into a cache file given by the selector.
  156.      * @param jSelectorTpl $selector the template selector
  157.      * @return boolean true if ok
  158.      */
  159.     public function compile ($selector) {
  160.         $this->_sourceFile = $selector->getPath();
  161.         $this->outputType = $selector->outputType;
  162.         $this->trusted = $selector->trusted;
  163.         $md5 = md5($selector->module.'_'.$selector->resource.'_'.$this->outputType.($this->trusted?'_t':''));
  164.  
  165.         jApp::pushCurrentModule($selector->module);
  166.  
  167.         if (!file_exists($this->_sourceFile)) {
  168.             $this->doError0('errors.tpl.not.found');
  169.         }
  170.         
  171.         $header = "if (jApp::config()->compilation['checkCacheFiletime'] &&\n";
  172.         $header .= "filemtime('".$this->_sourceFile.'\') > '.filemtime($this->_sourceFile)."){ return false;\n} else {\n";
  173.         $footer = "return true;}\n";
  174.  
  175.         $this->compileString(file_get_contents($this->_sourceFile), $selector->getCompiledFilePath(),
  176.             $selector->userModifiers, $selector->userFunctions, $md5, $header, $footer);
  177.  
  178.         jApp::popCurrentModule();
  179.         return true;
  180.     }
  181.  
  182.     public function compileString($templatecontent, $cachefile, $userModifiers, $userFunctions, $md5, $header='', $footer='') {
  183.         $this->_modifier = array_merge($this->_modifier, $userModifiers);
  184.         $this->_userFunctions = $userFunctions;
  185.  
  186.         $result = $this->compileContent($templatecontent);
  187.  
  188.         $header = "<?php \n".$header;
  189.         foreach ($this->_pluginPath as $path=>$ok) {
  190.             $header.=' require_once(\''.$path."');\n";
  191.         }
  192.         $header.='function template_meta_'.$md5.'($t){';
  193.         $header .="\n".$this->_metaBody."\n}\n";
  194.  
  195.         $header.='function template_'.$md5.'($t){'."\n?>";
  196.         $result = $header.$result."<?php \n}\n".$footer;
  197.  
  198.         jFile::write($cachefile, $result);
  199.  
  200.         return true;
  201.     }
  202.  
  203.     protected function compileContent ($tplcontent) {
  204.         $this->_metaBody = '';
  205.         $this->_blockStack = array();
  206.  
  207.         // we remove all php tags
  208.         $tplcontent = preg_replace("!<\?((?:php|=|\s).*)\?>!s", '', $tplcontent);
  209.         // we remove all template comments
  210.         $tplcontent = preg_replace("!{\*(.*?)\*}!s", '', $tplcontent);
  211.  
  212.         $tplcontent = preg_replace_callback("!(<\?.*\?>)!sm", function ($matches) {
  213.             return '<?php echo \''.str_replace("'","\\'",$matches[1]).'\'?>';
  214.         }, $tplcontent);
  215.  
  216.         if ($this->removeASPtags) {
  217.           // we remove all asp tags
  218.           $tplcontent = preg_replace("!<%.*%>!s", '', $tplcontent);
  219.         }
  220.  
  221.         preg_match_all("!{literal}(.*?){/literal}!s", $tplcontent, $_match);
  222.  
  223.         $this->_literals = $_match[1];
  224.  
  225.         $tplcontent = preg_replace("!{literal}(.*?){/literal}!s", '{literal}', $tplcontent);
  226.  
  227.         $tplcontent = preg_replace_callback("/{((.).*?)}(\n)/sm", function ($matches){
  228.                 list($full, , $firstcar, $lastcar) = $matches;
  229.                 if ($firstcar == '=' || $firstcar == '$' || $firstcar == '@') {
  230.                     return "$full\n";
  231.                 }
  232.                 else return $full;
  233.             }, $tplcontent);
  234.         $tplcontent = preg_replace_callback("/{((.).*?)}/sm", array($this,'_callback'), $tplcontent);
  235.  
  236.         /*$tplcontent = preg_replace('/\?>\n?<\?php/', '', $tplcontent);*/
  237.         $tplcontent = preg_replace('/<\?php\\s+\?>/', '', $tplcontent);
  238.  
  239.         if (count($this->_blockStack))
  240.             $this->doError1('errors.tpl.tag.block.end.missing', end($this->_blockStack));
  241.  
  242.         return $tplcontent;
  243.     }
  244.  
  245.     /**
  246.      * function called during the parsing of the template by a preg_replace_callback function
  247.      * It is called on each template tag {xxxx }
  248.      * @param array $matches a matched item
  249.      * @return string the corresponding php code of the tag (with php tag).
  250.      */
  251.     public function _callback ($matches) {
  252.         list(,$tag, $firstcar) = $matches;
  253.  
  254.         // check the first character
  255.         if (!preg_match('/^\$|@|=|[a-zA-Z\/]$/',$firstcar)) {
  256.             throw new jException('jelix~errors.tpl.tag.syntax.invalid',array($tag,$this->_sourceFile));
  257.         }
  258.  
  259.         $this->_currentTag = $tag;
  260.         if ($firstcar == '=') {
  261.             return  '<?php echo '.$this->_parseVariable(substr($tag,1)).'; ?>';
  262.         } else if ($firstcar == '$' || $firstcar == '@') {
  263.             return  '<?php echo '.$this->_parseVariable($tag).'; ?>';
  264.         } else {
  265.             if (!preg_match('/^(\/?[a-zA-Z0-9_]+)(?:(?:\s+(.*))|(?:\((.*)\)))?$/ms',$tag,$m)) {
  266.                 throw new jException('jelix~errors.tpl.tag.function.invalid',array($tag,$this->_sourceFile));
  267.             }
  268.             if (count($m) == 4) {
  269.                 $m[2] = $m[3];
  270.             }
  271.             if (!isset($m[2])) $m[2]='';
  272.             if ($m[1] == 'ldelim') return '{';
  273.             if ($m[1] == 'rdelim') return '}';
  274.             return '<?php '.$this->_parseFunction($m[1],$m[2]).'?>';
  275.         }
  276.     }
  277.  
  278.     /**
  279.     * analyse an "echo" tag : {$..} or {@..} 
  280.     * @param string $expr the content of the tag
  281.     * @return string the corresponding php instruction
  282.     */
  283.     protected function _parseVariable ($expr) {
  284.         $tok = explode('|',$expr);
  285.         $res = $this->_parseFinal(array_shift($tok),$this->_allowedInVar, $this->_excludedInVar);
  286.  
  287.         foreach ($tok as $modifier) {
  288.             if (!preg_match('/^(\w+)(?:\:(.*))?$/',$modifier,$m)) {
  289.                 $this->doError2('errors.tpl.tag.modifier.invalid',$this->_currentTag, $modifier);
  290.             }
  291.  
  292.             if (isset($m[2])) {
  293.                 $targs = $this->_parseFinal($m[2],$this->_allowedInVar, $this->_excludedInVar, true, ',',':');
  294.                 array_unshift($targs, $res);
  295.             } else {
  296.                 $targs = array($res);
  297.             }
  298.  
  299.             if ($path = $this->_getPlugin('cmodifier',$m[1])) {
  300.                 require_once($path[0]);
  301.                 $fct = $path[1];
  302.                 $res = $fct($this,$targs);
  303.  
  304.             } else if ($path = $this->_getPlugin('modifier',$m[1])) {
  305.                 $res = $path[1].'('.implode(',',$targs).')';
  306.                 $this->_pluginPath[$path[0]] = true;
  307.  
  308.             } else {
  309.                 if (isset($this->_modifier[$m[1]])) {
  310.                     $res = $this->_modifier[$m[1]].'('.$res.')';
  311.                 } else {
  312.                     $this->doError2('errors.tpl.tag.modifier.unknown',$this->_currentTag, $m[1]);
  313.                 }
  314.             }
  315.         }
  316.         return $res;
  317.     }
  318.  
  319.     /**
  320.      * analyse the tag which have a name
  321.      * @param string $name the name of the tag
  322.      * @param string $args the content that follow the name in the tag
  323.      * @return string the corresponding php instructions
  324.      */
  325.     protected function _parseFunction ($name, $args) {
  326.         $res='';
  327.         switch ($name) {
  328.             case 'if':
  329.                 $res = 'if('.$this->_parseFinal($args,$this->_allowedInExpr).'):';
  330.                 array_push($this->_blockStack,'if');
  331.                 break;
  332.  
  333.             case 'else':
  334.                 if (substr(end($this->_blockStack),0,2) !='if')
  335.                     $this->doError1('errors.tpl.tag.block.end.missing', end($this->_blockStack));
  336.                 else
  337.                     $res = 'else:';
  338.                 break;
  339.  
  340.             case 'elseif':
  341.                 if (end($this->_blockStack) !='if')
  342.                     $this->doError1('errors.tpl.tag.block.end.missing', end($this->_blockStack));
  343.                 else
  344.                     $res = 'elseif('.$this->_parseFinal($args,$this->_allowedInExpr).'):';
  345.                 break;
  346.  
  347.             case 'foreach':
  348.                 if ($this->trusted)
  349.                     $notallowed = array(';','!');
  350.                 else
  351.                     $notallowed = array(';','!','(');
  352.  
  353.                 if (preg_match("/^\s*\((.*)\)\s*$/",$args, $m))
  354.                    $args = $m[1];
  355.  
  356.                 $res = 'foreach('.$this->_parseFinal($args,$this->_allowedInForeach, $notallowed).'):';
  357.                 array_push($this->_blockStack,'foreach');
  358.                 break;
  359.  
  360.             case 'while':
  361.                 $res = 'while('.$this->_parseFinal($args,$this->_allowedInExpr).'):';
  362.                 array_push($this->_blockStack,'while');
  363.                 break;
  364.  
  365.             case 'for':
  366.                 if ($this->trusted)
  367.                     $notallowed = array();
  368.                 else
  369.                     $notallowed = array('(');
  370.                 if (preg_match("/^\s*\((.*)\)\s*$/",$args, $m))
  371.                    $args = $m[1];
  372.                 $res = 'for('. $this->_parseFinal($args, $this->_allowedInExpr, $notallowed) .'):';
  373.                 array_push($this->_blockStack,'for');
  374.                 break;
  375.  
  376.             case '/foreach':
  377.             case '/for':
  378.             case '/if':
  379.             case '/while':
  380.                 $short = substr($name,1);
  381.                 if (end($this->_blockStack) !=$short) {
  382.                     $this->doError1('errors.tpl.tag.block.end.missing', end($this->_blockStack));
  383.                 } else {
  384.                     array_pop($this->_blockStack);
  385.                     $res='end'.$short.';';
  386.                 }
  387.                 break;
  388.  
  389.             case 'assign':
  390.             case 'eval':
  391.                 $res = $this->_parseFinal($args,$this->_allowedAssign).';';
  392.                 break;
  393.  
  394.             case 'literal':
  395.                 if (count($this->_literals))
  396.                     $res = '?>'.array_shift($this->_literals).'<?php ';
  397.                 else
  398.                     $this->doError1('errors.tpl.tag.block.end.missing','literal');
  399.                 break;
  400.  
  401.             case '/literal':
  402.                 $this->doError1('errors.tpl.tag.block.begin.missing','literal');
  403.                 break;
  404.  
  405.             case 'meta':
  406.                 $this->_parseMeta($args);
  407.                 break;
  408.  
  409.             case 'meta_if':
  410.                 $metaIfArgs = $this->_parseFinal($args,$this->_allowedInExpr);
  411.                 $this->_metaBody .= 'if('.$metaIfArgs.'):'."\n";
  412.                 array_push($this->_blockStack,'meta_if');
  413.                 break;
  414.  
  415.             case 'meta_else':
  416.                 if (substr(end($this->_blockStack),0,7) !='meta_if') {
  417.                     $this->doError1('errors.tpl.tag.block.end.missing', end($this->_blockStack));
  418.                 } else {
  419.                     $this->_metaBody .= "else:\n";
  420.                 }
  421.                 break;
  422.  
  423.             case 'meta_elseif':
  424.                 if (end($this->_blockStack) !='meta_if') {
  425.                     $this->doError1('errors.tpl.tag.block.end.missing', end($this->_blockStack));
  426.                 } else {
  427.                     $elseIfArgs = $this->_parseFinal($args,$this->_allowedInExpr);
  428.                     $this->_metaBody .= 'elseif('.$elseIfArgs."):\n";
  429.                 }
  430.                 break;
  431.  
  432.             case '/meta_if':
  433.                 $short = substr($name,1);
  434.                 if (end($this->_blockStack) != $short) {
  435.                     $this->doError1('errors.tpl.tag.block.end.missing', end($this->_blockStack));
  436.                 } else {
  437.                     array_pop($this->_blockStack);
  438.                     $this->_metaBody .= "endif;\n";
  439.                 }
  440.                 break;
  441.  
  442.             default:
  443.                 if (preg_match('!^/(\w+)$!',$name,$m)) {
  444.                     if (end($this->_blockStack) !=$m[1]) {
  445.                         $this->doError1('errors.tpl.tag.block.end.missing',end($this->_blockStack));
  446.                     } else {
  447.                         array_pop($this->_blockStack);
  448.                         if (function_exists($fct = 'jtpl_block_'.$this->outputType.'_'.$m[1])) {
  449.                             $res = $fct($this,false,null);
  450.                         } else if(function_exists($fct = 'jtpl_block_common_'.$m[1])) {
  451.                             $res = $fct($this,false,null);
  452.                         } else
  453.                             $this->doError1('errors.tpl.tag.block.begin.missing',$m[1]);
  454.                     }
  455.  
  456.                 } else if(preg_match('/^meta_(\w+)$/',$name,$m)) {
  457.                      if ($path = $this->_getPlugin('meta',$m[1])) {
  458.                         $this->_parseMeta($args,$path[1]);
  459.                         $this->_pluginPath[$path[0]] = true;
  460.                     } else {
  461.                         $this->doError1('errors.tpl.tag.meta.unknown',$m[1]);
  462.                     }
  463.                     $res='';
  464.  
  465.                 } else if ($path = $this->_getPlugin('block',$name)) {
  466.                     require_once($path[0]);
  467.                     $argfct = $this->_parseFinal($args,$this->_allowedAssign, array(';'),true);
  468.                     $fct = $path[1];
  469.                     $res = $fct($this,true,$argfct);
  470.                     array_push($this->_blockStack,$name);
  471.  
  472.                 } else if ($path = $this->_getPlugin('cfunction',$name)) {
  473.                     require_once($path[0]);
  474.                     $argfct = $this->_parseFinal($args,$this->_allowedAssign, array(';'),true);
  475.                     $fct = $path[1];
  476.                     $res = $fct($this,$argfct);
  477.  
  478.                 } else if ($path = $this->_getPlugin('function',$name)) {
  479.                     $argfct = $this->_parseFinal($args,$this->_allowedAssign);
  480.                     $res = $path[1].'( $t'.(trim($argfct)!=''?','.$argfct:'').');';
  481.                     $this->_pluginPath[$path[0]] = true;
  482.  
  483.                 } else if (isset($this->_userFunctions[$name])) {
  484.                     $argfct = $this->_parseFinal($args,$this->_allowedAssign);
  485.                     $res = $this->_userFunctions[$name].'( $t'.(trim($argfct)!=''?','.$argfct:'').');';
  486.  
  487.                 } else {
  488.                     $this->doError1('errors.tpl.tag.function.unknown',$name);
  489.                 }
  490.         }
  491.         return $res;
  492.     }
  493.  
  494.     /**
  495.      * for plugins, it says if the plugin is inside the given block
  496.      * @param string $blockName the block to search
  497.      * @param boolean $onlyUpper check only the upper block
  498.      * @return boolean  true if it is inside the block
  499.      */
  500.     public function isInsideBlock ($blockName, $onlyUpper = false) {
  501.         if ($onlyUpper)
  502.             return (end($this->_blockStack) == $blockName);
  503.         for ($i=count($this->_blockStack) -1; $i>=0; $i--) {
  504.             if ($this->_blockStack[$i] == $blockName)
  505.                 return true;
  506.         }
  507.         return false;
  508.     }
  509.  
  510.     /**
  511.      * sub-function which analyse an expression
  512.      * @param string $string the expression
  513.      * @param array $allowed list of allowed php token
  514.      * @param array $exceptchar list of forbidden characters
  515.      * @param boolean $splitArgIntoArray true: split the results on coma
  516.      * @return array|string
  517.      */
  518.     protected function _parseFinal ($string, $allowed = array(), $exceptchar = array(';'),
  519.                                     $splitArgIntoArray = false, $sep1 = ',', $sep2 = ',') {
  520.         $tokens = token_get_all('<?php '.$string.'?>');
  521.  
  522.         $results = array();
  523.         $result ='';
  524.         $first = true;
  525.         $inLocale = false;
  526.         $locale = '';
  527.         $bracketcount = $sqbracketcount = 0;
  528.         $firstok = array_shift($tokens);
  529.  
  530.         // there is a bug, sometimes the first token isn't T_OPEN_TAG...
  531.         if ($firstok == '<' && $tokens[0] == '?' && is_array($tokens[1])
  532.             && $tokens[1][0] == T_STRING && $tokens[1][1] == 'php') {
  533.             array_shift($tokens);
  534.             array_shift($tokens);
  535.         }
  536.  
  537.         $previousTok = null;
  538.  
  539.         foreach ($tokens as $tok) {
  540.             if (is_array($tok)) {
  541.                 list($type,$str) = $tok;
  542.                 $first = false;
  543.                 if ($type == T_CLOSE_TAG) {
  544.                     $previousTok = $tok;
  545.                     continue;
  546.                 }
  547.                 if ($inLocale && in_array($type,$this->_inLocaleOk)) {
  548.                     $locale .= $str;
  549.                 } elseif ($type == T_VARIABLE && $inLocale) {
  550.                     $locale .= '\'.$t->_vars[\''.substr($str, 1).'\'].\'';
  551.                 } elseif ($type == T_VARIABLE){
  552.                     if (is_array($previousTok) && $previousTok[0] == T_OBJECT_OPERATOR)
  553.                         $result .= '{$t->_vars[\''.substr($str, 1).'\']}';
  554.                     else
  555.                         $result .= '$t->_vars[\''.substr($str, 1).'\']';
  556.                 } elseif ($type == T_WHITESPACE || in_array($type, $allowed)) {
  557.                     if (!$this->trusted && $type == T_STRING && defined($str)
  558.                         && !in_array(strtoupper($str), $this->_allowedConstants)) {
  559.                         $this->doError2('errors.tpl.tag.constant.notallowed', $this->_currentTag, $str);
  560.                     }
  561.                     if ($type == T_WHITESPACE)
  562.                         $str = preg_replace("/(\s+)/ms"," ",$str);
  563.                     $result .= $str;
  564.                 } else {
  565.                     $this->doError2('errors.tpl.tag.phpsyntax.invalid', $this->_currentTag, $str);
  566.                 }
  567.             } else {
  568.                 if ($tok == '@') {
  569.                     if ($inLocale) {
  570.                         $inLocale = false;
  571.                         if ($locale == '') {
  572.                             $this->doError1('errors.tpl.tag.locale.invalid', $this->_currentTag);
  573.                         } else {
  574.                             $result .= 'jLocale::get(\''.$locale.'\')';
  575.                             $locale = '';
  576.                         }
  577.                     } else {
  578.                         $inLocale = true;
  579.                     }
  580.                 } elseif ($inLocale && ($tok == '.' || $tok == '~')) {
  581.                     $locale .= $tok;
  582.                 } elseif ($inLocale || in_array($tok, $exceptchar)
  583.                           || ($first && $tok != '!' && $tok != '(')) {
  584.                     $this->doError2('errors.tpl.tag.character.invalid', $this->_currentTag, $tok);
  585.                 } elseif ($tok == '(') {
  586.                     $bracketcount++;
  587.                     $result .= $tok;
  588.                 } elseif ($tok == ')') {
  589.                     $bracketcount--;
  590.                     $result .= $tok;
  591.                 } elseif ($tok == '[') {
  592.                     $sqbracketcount++;
  593.                     $result .= $tok;
  594.                 } elseif ($tok == ']') {
  595.                     $sqbracketcount--;
  596.                     $result .= $tok;
  597.                 } elseif ($splitArgIntoArray && ($tok == $sep1 || $tok == $sep2)
  598.                           && $bracketcount == 0 && $sqbracketcount == 0) {
  599.                    $results[] = $result;
  600.                    $result = '';
  601.                 } else {
  602.                     $result .= $tok;
  603.                 }
  604.                 $first = false;
  605.             }
  606.             $previousTok = $tok;
  607.         }
  608.  
  609.         if ($inLocale) {
  610.             $this->doError1('errors.tpl.tag.locale.end.missing', $this->_currentTag);
  611.         }
  612.  
  613.         if ($bracketcount != 0 || $sqbracketcount != 0) {
  614.             $this->doError1('errors.tpl.tag.bracket.error', $this->_currentTag);
  615.         }
  616.  
  617.         $last = end($tokens);
  618.         if (!is_array($last) || $last[0] != T_CLOSE_TAG) {
  619.             $this->doError1('errors.tpl.tag.syntax.invalid', $this->_currentTag);
  620.         }
  621.  
  622.         if ($splitArgIntoArray) {
  623.             if ($result != '') $results[]=$result;
  624.             return $results;
  625.         } else {
  626.             return $result;
  627.         }
  628.     }
  629.  
  630.     protected function _parseMeta ($args, $fct = '') {
  631.         if (preg_match('/^(\w+)(\s+(.*))?$/', $args, $m)) {
  632.             if(isset($m[3]))
  633.                 $argfct = $this->_parseFinal($m[3], $this->_allowedInExpr);
  634.             else
  635.                 $argfct = 'null';
  636.             if ($fct != '') {
  637.                 $this->_metaBody.= $fct.'( $t,'."'".$m[1]."',".$argfct.");\n";
  638.             } else {
  639.                 $this->_metaBody.= "\$t->_meta['".$m[1]."']=".$argfct.";\n";
  640.             }
  641.         } else {
  642.             $this->doError1('errors.tpl.tag.meta.invalid', $this->_currentTag);
  643.         }
  644.     }
  645.  
  646.     public function addMetaContent ($content) {
  647.         $this->_metaBody .= $content."\n";
  648.     }
  649.  
  650.     /**
  651.      * Try to find a plugin
  652.      * @param string $type type of plugin (function, modifier...)
  653.      * @param string $name the plugin name
  654.      * @return array|booleanan array containing the path of the plugin
  655.      *                       and the name of the plugin function, or false if not found
  656.      */
  657.     protected function _getPlugin ($type, $name) {
  658.         $foundPath = '';
  659.  
  660.         $config = jApp::config();
  661.         if (isset($config->{'_tplpluginsPathList_'.$this->outputType})) {
  662.             foreach ($config->{'_tplpluginsPathList_'.$this->outputType} as $path) {
  663.                 $foundPath = $path.$type.'.'.$name.'.php';
  664.  
  665.                 if (file_exists($foundPath)) {
  666.                     return array($foundPath, 'jtpl_'.$type.'_'.$this->outputType.'_'.$name);
  667.                 }
  668.             }
  669.         }
  670.         if (isset($config->_tplpluginsPathList_common)) {
  671.             foreach ($config->_tplpluginsPathList_common as $path) {
  672.                 $foundPath = $path.$type.'.'.$name.'.php';
  673.                 if (file_exists($foundPath)) {
  674.                     return array($foundPath, 'jtpl_'.$type.'_common_'.$name);
  675.                 }
  676.             }
  677.         }
  678.         return false;
  679.     }
  680.  
  681.     public function doError0 ($err) {
  682.         throw new jException('jelix~'.$err,array($this->_sourceFile));
  683.     }
  684.  
  685.     public function doError1 ($err, $arg) {
  686.         throw new jException('jelix~'.$err,array($arg, $this->_sourceFile));
  687.     }
  688.  
  689.     public function doError2 ($err, $arg1, $arg2) {
  690.         throw new jException('jelix~'.$err, array($arg1, $arg2, $this->_sourceFile));
  691.     }
  692. }

Documentation generated on Wed, 04 Jan 2017 22:57:10 +0100 by phpDocumentor 1.4.3