1<?php 2/** 3 * Smarty Internal Plugin Config File Compiler 4 * This is the config file compiler class. It calls the lexer and parser to 5 * perform the compiling. 6 * 7 * @package Smarty 8 * @subpackage Config 9 * @author Uwe Tews 10 */ 11 12/** 13 * Main config file compiler class 14 * 15 * @package Smarty 16 * @subpackage Config 17 */ 18class Smarty_Internal_Config_File_Compiler 19{ 20 /** 21 * Lexer class name 22 * 23 * @var string 24 */ 25 public $lexer_class; 26 27 /** 28 * Parser class name 29 * 30 * @var string 31 */ 32 public $parser_class; 33 34 /** 35 * Lexer object 36 * 37 * @var object 38 */ 39 public $lex; 40 41 /** 42 * Parser object 43 * 44 * @var object 45 */ 46 public $parser; 47 48 /** 49 * Smarty object 50 * 51 * @var Smarty object 52 */ 53 public $smarty; 54 55 /** 56 * Smarty object 57 * 58 * @var Smarty_Internal_Template object 59 */ 60 public $template; 61 62 /** 63 * Compiled config data sections and variables 64 * 65 * @var array 66 */ 67 public $config_data = array(); 68 69 /** 70 * compiled config data must always be written 71 * 72 * @var bool 73 */ 74 public $write_compiled_code = true; 75 76 /** 77 * Initialize compiler 78 * 79 * @param string $lexer_class class name 80 * @param string $parser_class class name 81 * @param Smarty $smarty global instance 82 */ 83 public function __construct($lexer_class, $parser_class, Smarty $smarty) 84 { 85 $this->smarty = $smarty; 86 // get required plugins 87 $this->lexer_class = $lexer_class; 88 $this->parser_class = $parser_class; 89 $this->smarty = $smarty; 90 $this->config_data[ 'sections' ] = array(); 91 $this->config_data[ 'vars' ] = array(); 92 } 93 94 /** 95 * Method to compile Smarty config source. 96 * 97 * @param Smarty_Internal_Template $template 98 * 99 * @return bool true if compiling succeeded, false if it failed 100 * @throws \SmartyException 101 */ 102 public function compileTemplate(Smarty_Internal_Template $template) 103 { 104 $this->template = $template; 105 $this->template->compiled->file_dependency[ $this->template->source->uid ] = 106 array( 107 $this->template->source->filepath, 108 $this->template->source->getTimeStamp(), 109 $this->template->source->type 110 ); 111 if ($this->smarty->debugging) { 112 if (!isset($this->smarty->_debug)) { 113 $this->smarty->_debug = new Smarty_Internal_Debug(); 114 } 115 $this->smarty->_debug->start_compile($this->template); 116 } 117 // init the lexer/parser to compile the config file 118 /* @var Smarty_Internal_ConfigFileLexer $this ->lex */ 119 $this->lex = new $this->lexer_class( 120 str_replace( 121 array( 122 "\r\n", 123 "\r" 124 ), 125 "\n", 126 $template->source->getContent() 127 ) . "\n", 128 $this 129 ); 130 /* @var Smarty_Internal_ConfigFileParser $this ->parser */ 131 $this->parser = new $this->parser_class($this->lex, $this); 132 if (function_exists('mb_internal_encoding') 133 && function_exists('ini_get') 134 && ((int)ini_get('mbstring.func_overload')) & 2 135 ) { 136 $mbEncoding = mb_internal_encoding(); 137 mb_internal_encoding('ASCII'); 138 } else { 139 $mbEncoding = null; 140 } 141 if ($this->smarty->_parserdebug) { 142 $this->parser->PrintTrace(); 143 } 144 // get tokens from lexer and parse them 145 while ($this->lex->yylex()) { 146 if ($this->smarty->_parserdebug) { 147 echo "<br>Parsing {$this->parser->yyTokenName[$this->lex->token]} Token {$this->lex->value} Line {$this->lex->line} \n"; 148 } 149 $this->parser->doParse($this->lex->token, $this->lex->value); 150 } 151 // finish parsing process 152 $this->parser->doParse(0, 0); 153 if ($mbEncoding) { 154 mb_internal_encoding($mbEncoding); 155 } 156 if ($this->smarty->debugging) { 157 $this->smarty->_debug->end_compile($this->template); 158 } 159 // template header code 160 $template_header = 161 "<?php /* Smarty version " . Smarty::SMARTY_VERSION . ", created on " . strftime("%Y-%m-%d %H:%M:%S") . 162 "\n"; 163 $template_header .= " compiled from '{$this->template->source->filepath}' */ ?>\n"; 164 $code = '<?php $_smarty_tpl->smarty->ext->configLoad->_loadConfigVars($_smarty_tpl, ' . 165 var_export($this->config_data, true) . '); ?>'; 166 return $template_header . $this->template->smarty->ext->_codeFrame->create($this->template, $code); 167 } 168 169 /** 170 * display compiler error messages without dying 171 * If parameter $args is empty it is a parser detected syntax error. 172 * In this case the parser is called to obtain information about expected tokens. 173 * If parameter $args contains a string this is used as error message 174 * 175 * @param string $args individual error message or null 176 * 177 * @throws SmartyCompilerException 178 */ 179 public function trigger_config_file_error($args = null) 180 { 181 // get config source line which has error 182 $line = $this->lex->line; 183 if (isset($args)) { 184 // $line--; 185 } 186 $match = preg_split("/\n/", $this->lex->data); 187 $error_text = 188 "Syntax error in config file '{$this->template->source->filepath}' on line {$line} '{$match[$line - 1]}' "; 189 if (isset($args)) { 190 // individual error message 191 $error_text .= $args; 192 } else { 193 // expected token from parser 194 foreach ($this->parser->yy_get_expected_tokens($this->parser->yymajor) as $token) { 195 $exp_token = $this->parser->yyTokenName[ $token ]; 196 if (isset($this->lex->smarty_token_names[ $exp_token ])) { 197 // token type from lexer 198 $expect[] = '"' . $this->lex->smarty_token_names[ $exp_token ] . '"'; 199 } else { 200 // otherwise internal token name 201 $expect[] = $this->parser->yyTokenName[ $token ]; 202 } 203 } 204 // output parser error message 205 $error_text .= ' - Unexpected "' . $this->lex->value . '", expected one of: ' . implode(' , ', $expect); 206 } 207 throw new SmartyCompilerException($error_text); 208 } 209} 210