1<?php 2/** 3 * Smarty Internal Plugin Config 4 * 5 * @package Smarty 6 * @subpackage Config 7 * @author Uwe Tews 8 */ 9 10/** 11 * Smarty Internal Plugin Config 12 * 13 * Main class for config variables 14 * 15 * @package Smarty 16 * @subpackage Config 17 * 18 * @property Smarty_Config_Source $source 19 * @property Smarty_Config_Compiled $compiled 20 * @ignore 21 */ 22class Smarty_Internal_Config 23{ 24 /** 25 * Samrty instance 26 * 27 * @var Smarty object 28 */ 29 public $smarty = null; 30 /** 31 * Object of config var storage 32 * 33 * @var object 34 */ 35 public $data = null; 36 /** 37 * Config resource 38 * @var string 39 */ 40 public $config_resource = null; 41 /** 42 * Compiled config file 43 * 44 * @var string 45 */ 46 public $compiled_config = null; 47 /** 48 * filepath of compiled config file 49 * 50 * @var string 51 */ 52 public $compiled_filepath = null; 53 /** 54 * Filemtime of compiled config Filemtime 55 * 56 * @var int 57 */ 58 public $compiled_timestamp = null; 59 /** 60 * flag if compiled config file is invalid and must be (re)compiled 61 * @var bool 62 */ 63 public $mustCompile = null; 64 /** 65 * Config file compiler object 66 * 67 * @var Smarty_Internal_Config_File_Compiler object 68 */ 69 public $compiler_object = null; 70 71 /** 72 * Constructor of config file object 73 * 74 * @param string $config_resource config file resource name 75 * @param Smarty $smarty Smarty instance 76 * @param object $data object for config vars storage 77 */ 78 public function __construct($config_resource, $smarty, $data = null) 79 { 80 $this->data = $data; 81 $this->smarty = $smarty; 82 $this->config_resource = $config_resource; 83 } 84 85 /** 86 * Returns the compiled filepath 87 * 88 * @return string the compiled filepath 89 */ 90 public function getCompiledFilepath() 91 { 92 return $this->compiled_filepath === null ? 93 ($this->compiled_filepath = $this->buildCompiledFilepath()) : 94 $this->compiled_filepath; 95 } 96 97 /** 98 * Get file path. 99 * 100 * @return string 101 */ 102 public function buildCompiledFilepath() 103 { 104 $_compile_id = isset($this->smarty->compile_id) ? preg_replace('![^\w\|]+!', '_', $this->smarty->compile_id) : null; 105 $_flag = (int) $this->smarty->config_read_hidden + (int) $this->smarty->config_booleanize * 2 106 + (int) $this->smarty->config_overwrite * 4; 107 $_filepath = sha1($this->source->filepath . $_flag); 108 // if use_sub_dirs, break file into directories 109 if ($this->smarty->use_sub_dirs) { 110 $_filepath = substr($_filepath, 0, 2) . DS 111 . substr($_filepath, 2, 2) . DS 112 . substr($_filepath, 4, 2) . DS 113 . $_filepath; 114 } 115 $_compile_dir_sep = $this->smarty->use_sub_dirs ? DS : '^'; 116 if (isset($_compile_id)) { 117 $_filepath = $_compile_id . $_compile_dir_sep . $_filepath; 118 } 119 $_compile_dir = $this->smarty->getCompileDir(); 120 121 return $_compile_dir . $_filepath . '.' . basename($this->source->name) . '.config' . '.php'; 122 } 123 124 /** 125 * Returns the timpestamp of the compiled file 126 * 127 * @return integer the file timestamp 128 */ 129 public function getCompiledTimestamp() 130 { 131 return $this->compiled_timestamp === null 132 ? ($this->compiled_timestamp = (file_exists($this->getCompiledFilepath())) ? filemtime($this->getCompiledFilepath()) : false) 133 : $this->compiled_timestamp; 134 } 135 136 /** 137 * Returns if the current config file must be compiled 138 * 139 * It does compare the timestamps of config source and the compiled config and checks the force compile configuration 140 * 141 * @return boolean true if the file must be compiled 142 */ 143 public function mustCompile() 144 { 145 return $this->mustCompile === null ? 146 $this->mustCompile = ($this->smarty->force_compile || $this->getCompiledTimestamp () === false || $this->smarty->compile_check && $this->getCompiledTimestamp () < $this->source->timestamp): 147 $this->mustCompile; 148 } 149 150 /** 151 * Returns the compiled config file 152 * 153 * It checks if the config file must be compiled or just read the compiled version 154 * 155 * @return string the compiled config file 156 */ 157 public function getCompiledConfig() 158 { 159 if ($this->compiled_config === null) { 160 // see if template needs compiling. 161 if ($this->mustCompile()) { 162 $this->compileConfigSource(); 163 } else { 164 $this->compiled_config = file_get_contents($this->getCompiledFilepath()); 165 } 166 } 167 168 return $this->compiled_config; 169 } 170 171 /** 172 * Compiles the config files 173 * 174 * @throws Exception 175 */ 176 public function compileConfigSource() 177 { 178 // compile template 179 if (!is_object($this->compiler_object)) { 180 // load compiler 181 $this->compiler_object = new Smarty_Internal_Config_File_Compiler($this->smarty); 182 } 183 // compile locking 184 if ($this->smarty->compile_locking) { 185 if ($saved_timestamp = $this->getCompiledTimestamp()) { 186 touch($this->getCompiledFilepath()); 187 } 188 } 189 // call compiler 190 try { 191 $this->compiler_object->compileSource($this); 192 } catch (Exception $e) { 193 // restore old timestamp in case of error 194 if ($this->smarty->compile_locking && $saved_timestamp) { 195 touch($this->getCompiledFilepath(), $saved_timestamp); 196 } 197 throw $e; 198 } 199 // compiling succeded 200 // write compiled template 201 Smarty_Internal_Write_File::writeFile($this->getCompiledFilepath(), $this->getCompiledConfig(), $this->smarty); 202 } 203 204 /** 205 * load config variables 206 * 207 * @param mixed $sections array of section names, single section or null 208 * @param object $scope global,parent or local 209 */ 210 public function loadConfigVars($sections = null, $scope = 'local') 211 { 212 if ($this->data instanceof Smarty_Internal_Template) { 213 $this->data->properties['file_dependency'][sha1($this->source->filepath)] = array($this->source->filepath, $this->source->timestamp, 'file'); 214 } 215 if ($this->mustCompile()) { 216 $this->compileConfigSource(); 217 } 218 // pointer to scope 219 if ($scope == 'local') { 220 $scope_ptr = $this->data; 221 } elseif ($scope == 'parent') { 222 if (isset($this->data->parent)) { 223 $scope_ptr = $this->data->parent; 224 } else { 225 $scope_ptr = $this->data; 226 } 227 } elseif ($scope == 'root' || $scope == 'global') { 228 $scope_ptr = $this->data; 229 while (isset($scope_ptr->parent)) { 230 $scope_ptr = $scope_ptr->parent; 231 } 232 } 233 $_config_vars = array(); 234 include($this->getCompiledFilepath()); 235 // copy global config vars 236 foreach ($_config_vars['vars'] as $variable => $value) { 237 if ($this->smarty->config_overwrite || !isset($scope_ptr->config_vars[$variable])) { 238 $scope_ptr->config_vars[$variable] = $value; 239 } else { 240 $scope_ptr->config_vars[$variable] = array_merge((array) $scope_ptr->config_vars[$variable], (array) $value); 241 } 242 } 243 // scan sections 244 if (!empty($sections)) { 245 foreach ((array) $sections as $this_section) { 246 if (isset($_config_vars['sections'][$this_section])) { 247 foreach ($_config_vars['sections'][$this_section]['vars'] as $variable => $value) { 248 if ($this->smarty->config_overwrite || !isset($scope_ptr->config_vars[$variable])) { 249 $scope_ptr->config_vars[$variable] = $value; 250 } else { 251 $scope_ptr->config_vars[$variable] = array_merge((array) $scope_ptr->config_vars[$variable], (array) $value); 252 } 253 } 254 } 255 } 256 } 257 } 258 259 /** 260 * set Smarty property in template context 261 * 262 * @param string $property_name property name 263 * @param mixed $value value 264 * @throws SmartyException if $property_name is not valid 265 */ 266 public function __set($property_name, $value) 267 { 268 switch ($property_name) { 269 case 'source': 270 case 'compiled': 271 $this->$property_name = $value; 272 273 return; 274 } 275 276 throw new SmartyException("invalid config property '$property_name'."); 277 } 278 279 /** 280 * get Smarty property in template context 281 * 282 * @param string $property_name property name 283 * @throws SmartyException if $property_name is not valid 284 */ 285 public function __get($property_name) 286 { 287 switch ($property_name) { 288 case 'source': 289 if (empty($this->config_resource)) { 290 throw new SmartyException("Unable to parse resource name \"{$this->config_resource}\""); 291 } 292 $this->source = Smarty_Resource::config($this); 293 294 return $this->source; 295 296 case 'compiled': 297 $this->compiled = $this->source->getCompiled($this); 298 299 return $this->compiled; 300 } 301 302 throw new SmartyException("config attribute '$property_name' does not exist."); 303 } 304 305} 306