PageRenderTime 55ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/interfase/template.php

https://github.com/nopticon/hyd
PHP | 1479 lines | 1053 code | 160 blank | 266 comment | 189 complexity | a2db2cedd7212c254333ba8a4f8e3429 MD5 | raw file
Possible License(s): MIT
  1. <?php
  2. /*
  3. <Orion, a web development framework for RK.>
  4. Copyright (C) <2011> <Orion>
  5. This program is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. // Cache filenames prefix
  17. define('XS_TPL_PREFIX', 'tpl_');
  18. define('XS_TPL_PREFIX2', 'tpl2_');
  19. // Templates directory
  20. define('XS_TPL_START', 'template/');
  21. define('XS_TPL_ANY', '/template/');
  22. // Internal xs mod definitions. do not edit.
  23. define('XS_TAG_NONE', 0);
  24. define('XS_TAG_PHP', 1);
  25. define('XS_TAG_BEGIN', 2);
  26. define('XS_TAG_END', 3);
  27. define('XS_TAG_INCLUDE', 4);
  28. define('XS_TAG_IF', 5);
  29. define('XS_TAG_ELSE', 6);
  30. define('XS_TAG_ELSEIF', 7);
  31. define('XS_TAG_ENDIF', 8);
  32. define('XS_TAG_DEFINE', 9);
  33. define('XS_TAG_UNDEFINE', 10);
  34. define('XS_TAG_BEGINELSE', 11);
  35. class Template {
  36. // variable that holds all the data we'll be substituting into
  37. // the compiled templates.
  38. // ...
  39. // This will end up being a multi-dimensional array like this:
  40. // $this->_tpldata[block.][iteration#][child.][iteration#][child2.][iteration#][variablename] == value
  41. // if it's a root-level variable, it'll be like this:
  42. // $this->vars[varname] == value or $this->_tpldata['.'][0][varname] == value
  43. // array "vars" is added for easier access to data
  44. public $_tpldata = array('.' => array(0 => array()));
  45. public $vars;
  46. // Hash of filenames for each template handle.
  47. public $files = array();
  48. public $files_cache = array(); // array of cache files that exists
  49. public $files_cache2 = array(); // array of cache files (exists or not exists)
  50. // Root template directory.
  51. public $root = '';
  52. // Cache directory (compatible with default cache mod)
  53. public $cachedir = '';
  54. // Search/replace for unknown files
  55. public $cache_search = array();
  56. public $cache_replace = array();
  57. // Template root directory (generated by set_rootdir)
  58. public $tpldir = '';
  59. public $tpldir_len = 0;
  60. // Default template directory.
  61. // If file for default template isn't found file from this template is used.
  62. public $tpldef = '';
  63. // this will hash handle names to the compiled code for that handle.
  64. public $compiled_code = array();
  65. // This will hold the uncompiled code for that handle.
  66. public $uncompiled_code = array();
  67. // Cache settings
  68. public $use_cache = 1;
  69. public $cache_writable = 1;
  70. // Auto-compile setting
  71. public $auto_compile = 1;
  72. public $auto_recompile = 1;
  73. public $warn_includes = 1;
  74. // Current template name
  75. public $tpl = '';
  76. // List of replacements. tpl files in this list will be replaced with other tpl files
  77. // according to configuration in xs.cfg
  78. public $replace = array();
  79. // counter for include
  80. public $include_count = 0;
  81. // True if check switches
  82. public $xs_check_switches = 1;
  83. // eXtreme Styles variables
  84. public $xs_started = 0;
  85. // These handles will be parsed if pparse() is executed.
  86. // Can be used to automatically include header/footer if there is any content.
  87. public $preparse = '';
  88. public $postparse = '';
  89. // subtemplates mod detection
  90. public $subtemplates = false;
  91. public $replace_vars = true;
  92. // style configuration
  93. public $style_config = array();
  94. // list of switches that are known typos in some mods.
  95. // when error checking is enabled these errors will be auto-fixed.
  96. // format:
  97. // array(start_tag, end_tag)
  98. public $bugs = array(
  99. // ezportal typo:
  100. array('fetchpost_row', 'fetch_post_row'),
  101. // mycalendar 2.2.7 typos:
  102. array('date_cell', 'date_cells'),
  103. array('date_row', 'date_rows'),
  104. // history mod typo:
  105. array('site_today', 'site_week'),
  106. );
  107. /**
  108. * Constructor.
  109. */
  110. public function __contructor() {
  111. return;
  112. }
  113. /**
  114. * Sets the root dir.
  115. */
  116. public function set_template($root = '.') {
  117. global $config;
  118. $this->vars = &$this->_tpldata['.'][0];
  119. $this->use_cache = $config->xs_use_cache;
  120. $this->cache_search = array('.', '\\', '/', '_tpl');
  121. $this->cache_replace = array('_', '.', '.', '.php');
  122. $old_root = $this->root;
  123. $root = str_replace('\\', '/', $root);
  124. // $this->cachedir = ROOT . 'cache/';
  125. $this->cachedir = $config->cache_path;
  126. $this->tpldir = ROOT . 'template/';
  127. $this->tpldir_len = strlen($this->tpldir);
  128. $this->root = $root;
  129. $this->tpl = $this->template_name($root);
  130. // Check configuration
  131. $this->get_config();
  132. if ($old_root !== $this->root) {
  133. $this->files = array();
  134. $this->files_cache = array();
  135. $this->files_cache2 = array();
  136. $this->compiled_code = array();
  137. $this->uncompiled_code = array();
  138. }
  139. return;
  140. }
  141. /**
  142. * Destroys this template object. Should be called when you're done with it, in order
  143. * to clear out the template data so you can load/parse a new template set.
  144. */
  145. public function destroy() {
  146. $this->_tpldata = array('.' => array(0 => array()));
  147. $this->vars = &$this->_tpldata['.'][0];
  148. $this->xs_started = 0;
  149. }
  150. /**
  151. * Extracts template name from path
  152. */
  153. public function template_name($dir) {
  154. $tpl = XS_TPL_ANY; // can start at any position
  155. $tpl_null = XS_TPL_START; // can start only at zero position
  156. // searching for 'templates/' and removing everything before it
  157. $pos = strpos($dir, $tpl);
  158. if ($pos === false) {
  159. if(substr($dir, 0, strlen($tpl_null)) !== $tpl_null) {
  160. return '';
  161. }
  162. $str = substr($dir, strlen($tpl_null), strlen($dir));
  163. } else {
  164. $str = substr($dir, $pos + strlen($tpl), strlen($dir));
  165. }
  166. // searching for one more 'templates/'
  167. $dir = $this->template_name($str);
  168. if (!$dir) {
  169. $dir = $str;
  170. }
  171. if(strpos($str, $tpl) !== false) {
  172. $dir = $this->template_name($str);
  173. }
  174. // Check for another subdirectory
  175. $pos = strpos($dir, '/');
  176. if ($pos) {
  177. $dir = substr($dir, 0, $pos);
  178. }
  179. return $dir;
  180. }
  181. /**
  182. * Generates a full path+filename for the given filename, which can either
  183. * be an absolute name, or a name relative to the rootdir for this Template
  184. * object.
  185. */
  186. public function make_filename($filename, $xs_include = false) {
  187. // Check replacements list
  188. if (!$xs_include && isset($this->replace[$filename])) {
  189. $filename = $this->replace[$filename];
  190. }
  191. // Check if it's an absolute or relative path.
  192. if ((substr($filename, 0, 1) !== '/') && (substr($filename, 1, 1) !== ':')) {
  193. return $this->root . '/' . $filename;
  194. } else {
  195. return str_replace('\\', '/', $filename);
  196. }
  197. }
  198. /**
  199. * Converts template filename to cache filename.
  200. * Returns empty string if non-cachable (for tpl files outside of root dir).
  201. * $file should be absolute filename
  202. */
  203. public function make_filename_cache($file) {
  204. $str = str_replace($this->cache_search, $this->cache_replace, $file);
  205. if(substr($file, 0, $this->tpldir_len) !== $this->tpldir || empty($this->tpl)) {
  206. return $this->cachedir . XS_TPL_PREFIX2 . $str;
  207. }
  208. // removing not needed part
  209. $file = substr($file, $this->tpldir_len, strlen($file));
  210. // creating filename
  211. return $this->cachedir . XS_TPL_PREFIX . str_replace($this->cache_search, $this->cache_replace, $file);
  212. }
  213. /**
  214. * Sets the template filenames for handles. $filename_array
  215. * should be a hash of handle => filename pairs.
  216. */
  217. public function set_filenames($filename_array) {
  218. if (!is_array($filename_array)) {
  219. return false;
  220. }
  221. foreach($filename_array as $handle => $filename) {
  222. $this->set_filename($handle, $filename);
  223. }
  224. return true;
  225. }
  226. /**
  227. * Assigns template filename for handle.
  228. */
  229. public function set_filename($handle, $filename, $xs_include = false, $quiet = false) {
  230. global $config;
  231. $can_cache = $this->use_cache;
  232. if(strpos($filename, '..') !== false) {
  233. $can_cache = false;
  234. }
  235. $this->files[$handle] = $this->make_filename($filename, $xs_include);
  236. $this->files_cache[$handle] = '';
  237. $this->files_cache2[$handle] = '';
  238. // check if we are in admin control panel and override extreme styles mod controls if needed
  239. if(defined('XS_ADMIN_OVERRIDE') && XS_ADMIN_OVERRIDE === true && @function_exists('xs_admin_override')) {
  240. xs_admin_override();
  241. }
  242. // checking if we have valid filename
  243. if (!$this->files[$handle]) {
  244. if($xs_include || $quiet) {
  245. return false;
  246. } else {
  247. _pre("Template->make_filename(): Error - invalid template $filename", true);
  248. }
  249. }
  250. // creating cache filename
  251. if ($can_cache) {
  252. $this->files_cache2[$handle] = $this->make_filename_cache($this->files[$handle]);
  253. if(@file_exists($this->files_cache2[$handle])) {
  254. $this->files_cache[$handle] = $this->files_cache2[$handle];
  255. }
  256. }
  257. // checking if tpl and/or php file exists
  258. if (empty($this->files_cache[$handle]) && !@file_exists($this->files[$handle])) {
  259. // trying to load alternative filename (usually subSilver)
  260. if (!empty($this->tpldef) && !empty($this->tpl) && ($this->tpldef !== $this->tpl)) {
  261. $this->files[$handle] = '';
  262. // save old configuration
  263. $root = $this->root;
  264. $tpl_name = $this->tpl;
  265. // set temporary configuration
  266. $this->root = $this->tpldir . $this->tpldef;
  267. $this->tpl = $this->tpldef;
  268. // recursively run set_filename
  269. $res = $this->set_filename($handle, $filename, $xs_include, $quiet);
  270. // restore old configuration
  271. $this->root = $root;
  272. $this->tpl = $tpl_name;
  273. return $res;
  274. }
  275. if ($quiet) {
  276. return false;
  277. }
  278. if ($xs_include) {
  279. if ($this->warn_includes) {
  280. _pre('Template->make_filename(): Error - included template file not found: ' . $filename, true);
  281. }
  282. return false;
  283. } else {
  284. _pre('Template->make_filename(): Error - template file not found: ' . $this->files[$handle], true);
  285. }
  286. }
  287. // checking if we should recompile cache
  288. if (!empty($this->files_cache[$handle]) && $this->auto_recompile) {
  289. $cache_time = @filemtime($this->files_cache[$handle]);
  290. if(@filemtime($this->files[$handle]) > $cache_time || $config->xs_template_time > $cache_time) {
  291. // file was changed. don't use cache file (will be recompled if configuration allowes it)
  292. $this->files_cache[$handle] = '';
  293. }
  294. }
  295. return true;
  296. }
  297. /**
  298. * includes file or executes code
  299. */
  300. public function execute($filename, $code, $handle = false) {
  301. global $theme, $config;
  302. $template = $theme['template_name'];
  303. global $$template;
  304. $theme_info = &$$template;
  305. if ($filename) {
  306. require_once($filename);
  307. } else {
  308. eval($code);
  309. }
  310. return true;
  311. }
  312. /**
  313. * Load the file for the handle, compile the file,
  314. * and run the compiled code. This will print out
  315. * the results of executing the template.
  316. */
  317. public function pparse($handle) {
  318. global $config;
  319. // Parsing header if there is one
  320. if ($this->preparse || $this->postparse) {
  321. $preparse = $this->preparse;
  322. $postparse = $this->postparse;
  323. $this->preparse = '';
  324. $this->postparse = '';
  325. if ($preparse) {
  326. $this->pparse($preparse);
  327. }
  328. if ($postparse) {
  329. $str = $handle;
  330. $handle = $postparse;
  331. $this->pparse($str);
  332. }
  333. }
  334. // checking if handle exists
  335. if (empty($this->files[$handle]) && empty($this->files_cache[$handle])) {
  336. _pre("Template->loadfile(): No files found for handle $handle", true);
  337. }
  338. $this->xs_startup();
  339. $force_recompile = empty($this->uncompiled_code[$handle]) ? false : true;
  340. // Checking if php file exists.
  341. if (!empty($this->files_cache[$handle]) && !$force_recompile) {
  342. $this->execute($this->files_cache[$handle], '');
  343. return true;
  344. }
  345. if (!$this->loadfile($handle)) {
  346. _pre("Template->pparse(): Couldn't load template file for handle $handle", true);
  347. }
  348. // Actually compile the template now.
  349. if (empty($this->compiled_code[$handle])) {
  350. // Actually compile the code now.
  351. if (!empty($this->files_cache2[$handle]) && empty($this->files_cache[$handle]) && !$force_recompile) {
  352. $this->compiled_code[$handle] = $this->compile2($this->uncompiled_code[$handle], $handle, $this->files_cache2[$handle]);
  353. } else {
  354. $this->compiled_code[$handle] = $this->compile2($this->uncompiled_code[$handle], '', '');
  355. }
  356. }
  357. // Run the compiled code.
  358. if (empty($this->files_cache[$handle]) || $force_recompile) {
  359. $this->execute('', $this->compiled_code[$handle]);
  360. } else {
  361. $this->execute($this->files_cache[$handle], '');
  362. }
  363. return true;
  364. }
  365. /**
  366. * Precompile file
  367. */
  368. public function precompile($template, $filename) {
  369. global $precompile_num, $config;
  370. if (empty($precompile_num)) {
  371. $precompile_num = 0;
  372. }
  373. $precompile_num ++;
  374. $handle = 'precompile_' . $precompile_num;
  375. // save old configuration
  376. $root = $this->root;
  377. $tpl_name = $this->tpl;
  378. $old_config = $this->use_cache;
  379. $old_autosave = $this->auto_compile;
  380. // set temporary configuration
  381. $this->root = $this->tpldir . $template;
  382. $this->tpl = $template;
  383. $this->use_cache = 1;
  384. $this->auto_compile = 1;
  385. // set filename
  386. $res = $this->set_filename($handle, $filename, true, true);
  387. if (!$res || !$this->files_cache2[$handle]) {
  388. $this->root = $root;
  389. $this->tpl = $tpl_name;
  390. $this->use_cache = $old_config;
  391. $this->auto_compile = $old_autosave;
  392. return false;
  393. }
  394. $this->files_cache[$handle] = '';
  395. // load template
  396. $res = $this->loadfile($handle);
  397. if(!$res || empty($this->uncompiled_code[$handle])) {
  398. $this->root = $root;
  399. $this->tpl = $tpl_name;
  400. $this->use_cache = $old_config;
  401. $this->auto_compile = $old_autosave;
  402. return false;
  403. }
  404. // Compile the code
  405. $this->compile2($this->uncompiled_code[$handle], $handle, $this->files_cache2[$handle]);
  406. // Restore confirugation
  407. $this->root = $root;
  408. $this->tpl = $tpl_name;
  409. $this->use_cache = $old_config;
  410. $this->auto_compile = $old_autosave;
  411. return true;
  412. }
  413. /**
  414. * Inserts the uncompiled code for $handle as the
  415. * value of $varname in the root-level. This can be used
  416. * to effectively include a template in the middle of another
  417. * template.
  418. * Note that all desired assignments to the variables in $handle should be done
  419. * BEFORE calling this function.
  420. */
  421. public function assign_var_from_handle($varname, $handle) {
  422. ob_start();
  423. $res = $this->pparse($handle);
  424. $this->vars[$varname] = ob_get_contents();
  425. ob_end_clean();
  426. return $res;
  427. }
  428. /**
  429. * Block-level variable assignment. Adds a new block iteration with the given
  430. * variable assignments. Note that this should only be called once per block
  431. * iteration.
  432. */
  433. public function assign_block_vars($blockname, $vararray) {
  434. if (strpos($blockname, '.')) {
  435. // Nested block.
  436. $blocks = explode('.', $blockname);
  437. $blockcount = count($blocks) - 1;
  438. $str = &$this->_tpldata;
  439. for ($i = 0; $i < $blockcount; $i++)
  440. {
  441. $str = &$str[$blocks[$i].'.'];
  442. $str = &$str[count($str)-1];
  443. }
  444. // Now we add the block that we're actually assigning to.
  445. // We're adding a new iteration to this block with the given
  446. // variable assignments.
  447. $str[$blocks[$blockcount].'.'][] = $vararray;
  448. } else {
  449. // Top-level block.
  450. // Add a new iteration to this block with the variable assignments
  451. // we were given.
  452. $this->_tpldata[$blockname.'.'][] = $vararray;
  453. }
  454. return true;
  455. }
  456. /**
  457. * Root-level variable assignment. Adds to current assignments, overriding
  458. * any existing variable assignment with the same name.
  459. */
  460. public function assign_vars($vararray) {
  461. foreach ($vararray as $key => $val) {
  462. $this->vars[$key] = $val;
  463. }
  464. return true;
  465. }
  466. /**
  467. * If not already done, load the file for the given handle and populate
  468. * the uncompiled_code[] hash with its code. Do not compile.
  469. */
  470. public function loadfile($handle) {
  471. global $config;
  472. if (!empty($this->files_cache[$handle]) || !empty($this->uncompiled_code[$handle])) {
  473. return true;
  474. }
  475. // If we don't have a file assigned to this handle, die.
  476. if (empty($this->files[$handle])) {
  477. _pre("Template->loadfile(): No file specified for handle $handle", true);
  478. }
  479. $str = implode('', @file($this->files[$handle]));
  480. if (empty($str)) {
  481. _pre("Template->loadfile(): File " . $this->files[$handle] . " for handle $handle is empty", true);
  482. }
  483. $this->uncompiled_code[$handle] = $str;
  484. return true;
  485. }
  486. /**
  487. * Generates a reference to the given variable inside the given (possibly nested)
  488. * block namespace. This is a string of the form:
  489. * ' . $this->_tpldata['parent.'][$_parent_i]['$child1.'][$_child1_i]['$child2.'][$_child2_i]...['varname'] . '
  490. * It's ready to be inserted into an "echo" line in one of the templates.
  491. * NOTE: expects a trailing "." on the namespace.
  492. */
  493. public function generate_block_varref($namespace, $varname) {
  494. // Strip the trailing period.
  495. $namespace = substr($namespace, 0, strlen($namespace) - 1);
  496. // Get a reference to the data block for this namespace.
  497. $varref = $this->generate_block_data_ref($namespace, true);
  498. // Prepend the necessary code to stick this in an echo line.
  499. // Append the variable reference.
  500. $varref .= '[\'' . $varname . '\']';
  501. $varref = '<'.'?php echo isset(' . $varref . ') ? ' . $varref . ' : \'\'; ?'.'>';
  502. return $varref;
  503. }
  504. /**
  505. * Generates a reference to the array of data values for the given
  506. * (possibly nested) block namespace. This is a string of the form:
  507. * $this->_tpldata['parent.'][$_parent_i]['$child1.'][$_child1_i]['$child2.'][$_child2_i]...['$childN.']
  508. *
  509. * If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above.
  510. * NOTE: does not expect a trailing "." on the blockname.
  511. */
  512. public function generate_block_data_ref($blockname, $include_last_iterator, $defop = false) {
  513. // Get an array of the blocks involved.
  514. $blocks = explode('.', $blockname);
  515. $blockcount = count($blocks) - 1;
  516. if ($defop) {
  517. $varref = '$this->_tpldata[\'DEFINE\']';
  518. // Build up the string with everything but the last child.
  519. for ($i = 0; $i < $blockcount; $i++) {
  520. $varref .= "['" . $blocks[$i] . ".'][\$" . $blocks[$i] . '_i]';
  521. }
  522. // Add the block reference for the last child.
  523. $varref .= "['" . $blocks[$blockcount] . ".']";
  524. // Add the iterator for the last child if requried.
  525. if ($include_last_iterator) {
  526. $varref .= '[$' . $blocks[$blockcount] . '_i]';
  527. }
  528. return $varref;
  529. }
  530. if ($include_last_iterator) {
  531. return '$'. $blocks[$blockcount]. '_item';
  532. } else {
  533. return '$'. $blocks[$blockcount-1]. '_item[\''. $blocks[$blockcount]. '.\']';
  534. }
  535. }
  536. public function compile_code($filename, $code) {
  537. // $filename - file to load code from. used if $code is empty
  538. // $code - tpl code
  539. // $use_isset - if false then compiled code looks more beautiful and easier
  540. // to understand and it adds error_reporting() to supress php warnings.
  541. // if true then isset() is used to check variables instead of supressing
  542. // php warnings. note: for extreme styles mod 2.x it works only for
  543. // block variables and for usual variables its always true.
  544. // Load code from file
  545. if (!$code && !empty($filename)) {
  546. $code = @implode('', @file($filename));
  547. }
  548. // Break it up into lines and put " -->" back.
  549. $code_lines = explode(' -->', $code);
  550. $count = count($code_lines);
  551. for ($i = 0; $i < ($count - 1); $i++) {
  552. $code_lines[$i] .= ' -->';
  553. }
  554. $block_nesting_level = 0;
  555. $block_names = array();
  556. $block_names[0] = '.';
  557. $block_items = array();
  558. $count_if = 0;
  559. // prepare array for compiled code
  560. $compiled = array();
  561. $count_bugs = count($this->bugs);
  562. // array of switches
  563. $sw = array();
  564. // main loop
  565. $line_count = count($code_lines);
  566. for ($i = 0; $i < $line_count; $i++) {
  567. $line = $code_lines[$i];
  568. // Reset keyword type
  569. $keyword_type = XS_TAG_NONE;
  570. // Check if we have valid keyword in current line
  571. $pos1 = strpos($line, '<!-- ');
  572. if ($pos1 === false) {
  573. // no keywords in this line
  574. $compiled[] = $this->_compile_text($line);
  575. continue;
  576. }
  577. // Find end of html comment
  578. $pos2 = strpos($line, ' -->', $pos1);
  579. if ($pos2 !== false) {
  580. // find end of keyword in comment
  581. $pos3 = strpos($line, ' ', $pos1 + 5);
  582. if ($pos3 !== false && $pos3 <= $pos2) {
  583. $keyword = substr($line, $pos1 + 5, $pos3 - $pos1 - 5);
  584. // Check keyword against list of supported keywords. case-sensitive
  585. if($keyword === 'BEGIN') {
  586. $keyword_type = XS_TAG_BEGIN;
  587. } elseif($keyword === 'END') {
  588. $keyword_type = XS_TAG_END;
  589. } elseif($keyword === 'INCLUDE') {
  590. $keyword_type = XS_TAG_INCLUDE;
  591. } elseif($keyword === 'IF') {
  592. $keyword_type = XS_TAG_IF;
  593. } elseif($keyword === 'ELSE') {
  594. $keyword_type = XS_TAG_ELSE;
  595. } elseif($keyword === 'ELSEIF') {
  596. $keyword_type = XS_TAG_ELSEIF;
  597. } elseif($keyword === 'ENDIF') {
  598. $keyword_type = XS_TAG_ENDIF;
  599. } elseif($keyword === 'DEFINE') {
  600. $keyword_type = XS_TAG_DEFINE;
  601. } elseif($keyword === 'UNDEFINE') {
  602. $keyword_type = XS_TAG_UNDEFINE;
  603. } elseif($keyword === 'BEGINELSE') {
  604. $keyword_type = XS_TAG_BEGINELSE;
  605. }
  606. }
  607. }
  608. if (!$keyword_type) {
  609. // Not valid keyword. process the rest of line
  610. $compiled[] = $this->_compile_text(substr($line, 0, $pos1 + 4));
  611. $code_lines[$i] = substr($line, $pos1 + 4);
  612. $i --;
  613. continue;
  614. }
  615. // Remove code before keyword
  616. if ($pos1 > 0) {
  617. $compiled[] = $this->_compile_text(substr($line, 0, $pos1));
  618. }
  619. // Remove keyword
  620. $keyword_str = substr($line, $pos1, $pos2 - $pos1 + 4);
  621. $params_str = $pos2 == $pos3 ? '' : substr($line, $pos3 + 1, $pos2 - $pos3 - 1);
  622. $code_lines[$i] = substr($line, $pos2 + 4);
  623. $i--;
  624. //
  625. // Check keywords
  626. //
  627. /*
  628. * <!-- BEGIN -->
  629. */
  630. if ($keyword_type == XS_TAG_BEGIN) {
  631. $params = explode(' ', $params_str);
  632. $num_params = count($params);
  633. // get variable name
  634. if ($num_params == 1) {
  635. $var = $params[0];
  636. } elseif($num_params == 2) {
  637. if ($params[0] === '') {
  638. $var = $params[1];
  639. } elseif($params[1] === '') {
  640. $var = $params[0];
  641. } else {
  642. // invalid tag
  643. $compiled[] = $keyword_str;
  644. continue;
  645. }
  646. } else {
  647. // invalid tag
  648. $compiled[] = $keyword_str;
  649. continue;
  650. }
  651. // check variable for matching end
  652. if ($this->xs_check_switches) {
  653. $found = 0;
  654. $str = '<!-- END ' . $var . ' -->';
  655. for ($j = $i + 1; ($j < $line_count) && !$found; $j++) {
  656. $pos = strpos($code_lines[$j], $str);
  657. if($pos !== false) {
  658. $found = 1;
  659. $found_var = $var;
  660. }
  661. }
  662. if (!$found) {
  663. $compiled[] = $keyword_str;
  664. continue;
  665. }
  666. // adding to list of switches
  667. if (isset($sw[$found_var])) {
  668. $sw[$found_var]++;
  669. } else {
  670. $sw[$found_var] = 1;
  671. }
  672. }
  673. // adding code
  674. $block_nesting_level++;
  675. $block_names[$block_nesting_level] = $var;
  676. if (isset($block_items[$var])) {
  677. $block_items[$var]++;
  678. } else {
  679. $block_items[$var] = 1;
  680. }
  681. if ($block_nesting_level < 2) {
  682. // Block is not nested.
  683. $line = '<'."?php ";
  684. $line .= '$'. $var. '_count = ( isset($this->_tpldata[\''. $var. '.\']) ) ? count($this->_tpldata[\''. $var. '.\']) : 0;';
  685. $line .= ' for ($'. $var. '_i = 0; $'. $var. '_i < $'. $var. '_count; $'. $var. '_i++)';
  686. $line .= '{';
  687. $line .= ' $'. $var. '_item = &$this->_tpldata[\''. $var. '.\'][$'. $var. '_i];';
  688. $line .= " \${$var}_item['S_ROW_COUNT'] = \${$var}_i;";
  689. $line .= " \${$var}_item['S_NUM_ROWS'] = \${$var}_count;";
  690. $line .= " ?".">";
  691. } else {
  692. // This block is nested.
  693. // Generate a namespace string for this block.
  694. $namespace = implode('.', $block_names);
  695. // strip leading period from root level..
  696. $namespace = substr($namespace, 2);
  697. // Get a reference to the data array for this block that depends on the
  698. // current indices of all parent blocks.
  699. $varref = $this->generate_block_data_ref($namespace, false);
  700. // Create the for loop code to iterate over this block.
  701. $line = '<'."?php ";
  702. $line .= '$'. $var. '_count = ( isset('. $varref. ') ) ? count('. $varref. ') : 0;';
  703. $line .= ' for ($'. $var. '_i = 0; $'. $var. '_i < $'. $var. '_count; $'. $var. '_i++)';
  704. $line .= '{';
  705. $line .= ' $'. $var. '_item = &'. $varref. '[$'. $var. '_i];';
  706. $line .= " \${$var}_item['S_ROW_COUNT'] = \${$var}_i;";
  707. $line .= " \${$var}_item['S_NUM_ROWS'] = \${$var}_count;";
  708. $line .= " ?".">";
  709. }
  710. $compiled[] = $line;
  711. continue;
  712. }
  713. /*
  714. * <!-- END -->
  715. */
  716. if ($keyword_type == XS_TAG_END) {
  717. $params = explode(' ', $params_str);
  718. $num_params = count($params);
  719. if ($num_params == 1) {
  720. $var = $params[0];
  721. } elseif($num_params == 2 && $params[0] === '') {
  722. $var = $params[1];
  723. } elseif($num_params == 2 && $params[1] === '') {
  724. $var = $params[0];
  725. } else {
  726. $compiled[] = $keyword_str;
  727. continue;
  728. }
  729. if ($this->xs_check_switches) {
  730. // checking if this switch was opened
  731. if (!isset($sw[$var]) || ($sw[$var] < 1)) {
  732. // there is no opening switch
  733. $compiled[] = $keyword_str;
  734. continue;
  735. }
  736. $sw[$var] --;
  737. }
  738. // We have the end of a block.
  739. $line = '<'."?php".' } if(isset($' . $var . '_item)) { unset($' . $var . '_item); } '."?".">";
  740. if (isset($block_items[$var])) {
  741. $block_items[$var] --;
  742. } else {
  743. $block_items[$var] = -1;
  744. }
  745. unset($block_names[$block_nesting_level]);
  746. $block_nesting_level--;
  747. $compiled[] = $line;
  748. continue;
  749. }
  750. /*
  751. * <!-- BEGINELSE -->
  752. */
  753. if ($keyword_type == XS_TAG_BEGINELSE) {
  754. if ($block_nesting_level) {
  755. $var = $block_names[$block_nesting_level];
  756. $compiled[] = '<'.'?php } if(!$' . $var . '_count) { ?'.'>';
  757. } else {
  758. $compiled[] = $keyword_str;
  759. continue;
  760. }
  761. }
  762. /*
  763. * <!-- INCLUDE -->
  764. */
  765. if ($keyword_type == XS_TAG_INCLUDE) {
  766. $params = explode(' ', $params_str);
  767. if (count($params) != 1) {
  768. $compiled[] = $keyword_str;
  769. continue;
  770. }
  771. $filehash = md5($params_str . $this->include_count . time());
  772. $this->include_count++;
  773. $line = '<'.'?php $this->set_filename(\'xs_include_' . $filehash . '\', \'' . $params_str .'\', true); $this->pparse(\'xs_include_' . $filehash . '\'); ?'.'>';
  774. $compiled[] = $line;
  775. continue;
  776. }
  777. /*
  778. * <!-- IF -->
  779. */
  780. if ($keyword_type == XS_TAG_IF || $keyword_type == XS_TAG_ELSEIF) {
  781. if (!$count_if) {
  782. $keyword_type = XS_TAG_IF;
  783. }
  784. $str = $this->compile_tag_if($params_str, $keyword_type == XS_TAG_IF ? false : true);
  785. if ($str) {
  786. $compiled[] = '<?php ' . $str . ' ?>';
  787. if ($keyword_type == XS_TAG_IF) {
  788. $count_if++;
  789. }
  790. } else {
  791. $compiled[] = $keyword_str;
  792. }
  793. continue;
  794. }
  795. /*
  796. * <!-- ELSE -->
  797. */
  798. if ($keyword_type == XS_TAG_ELSE && $count_if > 0) {
  799. $compiled[] = '<?php } else { ?>';
  800. continue;
  801. }
  802. /*
  803. * <!-- ENDIF -->
  804. */
  805. if ($keyword_type == XS_TAG_ENDIF && $count_if > 0) {
  806. $compiled[] = '<?php } ?>';
  807. $count_if --;
  808. continue;
  809. }
  810. /*
  811. * <!-- DEFINE -->
  812. */
  813. if ($keyword_type == XS_TAG_DEFINE) {
  814. $str = $this->compile_tag_define($params_str);
  815. if ($str) {
  816. $compiled[] = '<?php ' . $str . ' ?>';
  817. } else {
  818. $compiled[] = $keyword_str;
  819. }
  820. }
  821. /*
  822. * <!-- UNDEFINE -->
  823. */
  824. if ($keyword_type == XS_TAG_UNDEFINE) {
  825. $str = $this->compile_tag_undefine($params_str);
  826. if ($str) {
  827. $compiled[] = '<?php ' . $str . ' ?>';
  828. } else {
  829. $compiled[] = $keyword_str;
  830. }
  831. }
  832. }
  833. // bring it back into a single string.
  834. $code_header = '';
  835. $code_footer = '';
  836. return $code_header . implode('', $compiled) . $code_footer;
  837. }
  838. /*
  839. * Compile code between tags
  840. */
  841. public function _compile_text($code) {
  842. if (strlen($code) < 3) {
  843. return $code;
  844. }
  845. // change template varrefs into PHP varrefs
  846. // This one will handle varrefs WITH namespaces
  847. $varrefs = array();
  848. preg_match_all('#\{(([a-z0-9\-_]+?\.)+?)([a-z0-9\-_]+?)\}#is', $code, $varrefs);
  849. $varcount = count($varrefs[1]);
  850. $search = array();
  851. $replace = array();
  852. for ($i = 0; $i < $varcount; $i++) {
  853. $namespace = $varrefs[1][$i];
  854. $varname = $varrefs[3][$i];
  855. $new = $this->generate_block_varref($namespace, $varname);
  856. $search[] = $varrefs[0][$i];
  857. $replace[] = $new;
  858. }
  859. if (count($search) > 0) {
  860. $code = str_replace($search, $replace, $code);
  861. }
  862. if (isset($this->files['body']) && strpos($this->files['body'], '.js') !== false) {
  863. $this->replace_vars = false;
  864. }
  865. // This will handle the remaining root-level varrefs
  866. if ($this->replace_vars) {
  867. $code = preg_replace('#\{([a-z0-9\-_]*?)\}#is', '<'.'?php echo isset($this->vars[\'\1\']) ? $this->vars[\'\1\'] : $this->lang(\'\1\'); ?'.'>', $code);
  868. $code = preg_replace('#\{\$([a-z0-9\-_]*?)\}#is', '<'.'?php echo isset($this->_tpldata[\'DEFINE\'][\'.\'][\'\\1\']) ? $this->_tpldata[\'DEFINE\'][\'.\'][\'\\1\'] : \'\'; ?'.'>', $code);
  869. }
  870. return $code;
  871. }
  872. //
  873. // Compile IF tags - much of this is from Smarty with
  874. // some adaptions for our block level methods
  875. //
  876. public function compile_tag_if($tag_args, $elseif) {
  877. /* Tokenize args for 'if' tag. */
  878. preg_match_all('/(?:
  879. "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" |
  880. \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' |
  881. [(),] |
  882. [^\s(),]+)/x', $tag_args, $match);
  883. $tokens = $match[0];
  884. $is_arg_stack = array();
  885. for ($i = 0; $i < count($tokens); $i++) {
  886. $token = &$tokens[$i];
  887. switch ($token) {
  888. case '!':
  889. case '%':
  890. case '!==':
  891. case '==':
  892. case '===':
  893. case '>':
  894. case '<':
  895. case '!=':
  896. case '<>':
  897. case '<<':
  898. case '>>':
  899. case '<=':
  900. case '>=':
  901. case '&&':
  902. case '||':
  903. case '|':
  904. case '^':
  905. case '&':
  906. case '~':
  907. case ')':
  908. case ',':
  909. case '+':
  910. case '-':
  911. case '*':
  912. case '/':
  913. case '@':
  914. break;
  915. case '(':
  916. array_push($is_arg_stack, $i);
  917. break;
  918. case 'is':
  919. $is_arg_start = ($tokens[$i-1] == ')') ? array_pop($is_arg_stack) : $i-1;
  920. $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start));
  921. $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));
  922. array_splice($tokens, $is_arg_start, count($tokens), $new_tokens);
  923. $i = $is_arg_start;
  924. default:
  925. if (preg_match('#^(([a-z0-9\-_]+?\.)+?)?(\$)?([A-Z]+[A-Z0-9\-_]+)$#s', $token, $varrefs)) {
  926. $token = (!empty($varrefs[1])) ? $this->generate_block_data_ref(substr($varrefs[1], 0, -1), true, $varrefs[3]) . '[\'' . $varrefs[4] . '\']' : (($varrefs[3]) ? '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $varrefs[4] . '\']' : '$this->vars[\'' . $varrefs[4] . '\']');
  927. }
  928. break;
  929. }
  930. }
  931. $code = (($elseif) ? '} elseif (' : 'if (') . (implode(' ', $tokens) . ') { ');
  932. return $code;
  933. }
  934. // This is from Smarty
  935. public function _parse_is_expr($is_arg, $tokens) {
  936. $expr_end = 0;
  937. $negate_expr = false;
  938. if (($first_token = array_shift($tokens)) == 'not') {
  939. $negate_expr = true;
  940. $expr_type = array_shift($tokens);
  941. } else {
  942. $expr_type = $first_token;
  943. }
  944. switch ($expr_type) {
  945. case 'even':
  946. if (@$tokens[$expr_end] == 'by') {
  947. $expr_end++;
  948. $expr_arg = $tokens[$expr_end++];
  949. $expr = "!(($is_arg / $expr_arg) % $expr_arg)";
  950. } else {
  951. $expr = "!($is_arg % 2)";
  952. }
  953. break;
  954. case 'odd':
  955. if (@$tokens[$expr_end] == 'by') {
  956. $expr_end++;
  957. $expr_arg = $tokens[$expr_end++];
  958. $expr = "(($is_arg / $expr_arg) % $expr_arg)";
  959. } else {
  960. $expr = "($is_arg % 2)";
  961. }
  962. break;
  963. case 'div':
  964. if (@$tokens[$expr_end] == 'by') {
  965. $expr_end++;
  966. $expr_arg = $tokens[$expr_end++];
  967. $expr = "!($is_arg % $expr_arg)";
  968. }
  969. break;
  970. default:
  971. break;
  972. }
  973. if ($negate_expr) {
  974. $expr = "!($expr)";
  975. }
  976. array_splice($tokens, 0, $expr_end, $expr);
  977. return $tokens;
  978. }
  979. public function compile_tag_define($tag_args) {
  980. preg_match('#^(([a-z0-9\-_]+?\.)+?)?\$([A-Z][A-Z0-9_\-]*?) = (\'?)(.*?)(\'?)$#', $tag_args, $match);
  981. if (empty($match[3]) || empty($match[5])) {
  982. return '';
  983. }
  984. // Are we a string?
  985. if ($match[4] && $match[6]) {
  986. $match[5] = "'" . addslashes(str_replace(array('\\\'', '\\\\'), array('\'', '\\'), $match[5])) . "'";
  987. } else {
  988. preg_match('#(true|false|\.)#i', $match[5], $type);
  989. switch (strtolower($type[1]))
  990. {
  991. case 'true':
  992. case 'false':
  993. $match[5] = strtoupper($match[5]);
  994. break;
  995. case '.';
  996. $match[5] = doubleval($match[5]);
  997. break;
  998. default:
  999. $match[5] = intval($match[5]);
  1000. break;
  1001. }
  1002. }
  1003. return (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[3] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[3] . '\']') . ' = ' . $match[5] . ';';
  1004. }
  1005. public function compile_tag_undefine($tag_args) {
  1006. preg_match('#^(([a-z0-9\-_]+?\.)+?)?\$([A-Z][A-Z0-9_\-]*?)$#', $tag_args, $match);
  1007. if (empty($match[3])) {
  1008. return '';
  1009. }
  1010. return 'unset(' . (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[3] . '\']' : '$this->_tpldata[\'DEFINE\'][\'.\'][\'' . $match[3] . '\']') . ');';
  1011. }
  1012. /**
  1013. * Compiles code and writes to cache if needed
  1014. */
  1015. public function compile2($code, $handle, $cache_file) {
  1016. $code = $this->compile_code('', $code);
  1017. if ($cache_file && !empty($this->use_cache) && !empty($this->auto_compile)) {
  1018. $res = $this->write_cache($cache_file, $code);
  1019. if ($handle && $res) {
  1020. $this->files_cache[$handle] = $cache_file;
  1021. }
  1022. }
  1023. $code = '?'.'>'.$code.'<'."?php ";
  1024. return $code;
  1025. }
  1026. /**
  1027. * Compiles the given string of code, and returns
  1028. * the result in a string.
  1029. * If "do_not_echo" is true, the returned code will not be directly
  1030. * executable, but can be used as part of a variable assignment
  1031. * for use in assign_code_from_handle().
  1032. * This function isn't used and kept only for compatibility with original template.php
  1033. */
  1034. public function compile($code, $do_not_echo = false, $retvar = '') {
  1035. $code = ' ?'.'>' . $this->compile_code('', $code) . '<'."?php \n";
  1036. if ($do_not_echo) {
  1037. $code = "ob_start();\n". $code. "\n\${$retvar} = ob_get_contents();\nob_end_clean();\n";
  1038. }
  1039. return $code;
  1040. }
  1041. /**
  1042. * Write cache to disk
  1043. */
  1044. public function write_cache($filename, $code) {
  1045. global $config;
  1046. // check if cache is writable
  1047. if (!$this->cache_writable) {
  1048. return false;
  1049. }
  1050. // check if filename is valid
  1051. if(substr($filename, 0, strlen($this->cachedir)) !== $this->cachedir) {
  1052. return false;
  1053. }
  1054. // try to open file
  1055. $file = @fopen($filename, 'w');
  1056. if(!$file) {
  1057. // try to create directories
  1058. $dir = substr($filename, strlen($this->cachedir), strlen($filename));
  1059. $dirs = explode('/', $dir);
  1060. $path = $this->cachedir;
  1061. @umask(0);
  1062. if (!@is_dir($path)) {
  1063. if (!@mkdir($path)) {
  1064. $this->cache_writable = 0;
  1065. return false;
  1066. }
  1067. _chmod($path, $config->mask);
  1068. }
  1069. $count = count($dirs);
  1070. if ($count > 0) {
  1071. for ($i = 0; $i < $count-1; $i++) {
  1072. if ($i>0) {
  1073. $path .= '/';
  1074. }
  1075. $path .= $dirs[$i];
  1076. if(!@is_dir($path)) {
  1077. if(!@mkdir($path)) {
  1078. $this->cache_writable = 0;
  1079. return false;
  1080. }
  1081. _chmod($path, $config->mask);
  1082. }
  1083. }
  1084. }
  1085. // try to open file again after directories were created
  1086. $file = @fopen($filename, 'w');
  1087. }
  1088. if (!$file) {
  1089. $this->cache_writable = 0;
  1090. return false;
  1091. }
  1092. fwrite($file, "<?php\n\n// Generated on " . date('r') . " (time=" . time() . ")\n\n?>");
  1093. fwrite($file, $code);
  1094. fclose($file);
  1095. _chmod($filename, $config->mask);
  1096. return true;
  1097. }
  1098. public function xs_startup() {
  1099. if (!empty($this->xs_started)) {
  1100. return;
  1101. }
  1102. $this->xs_started = 1;
  1103. // Adding current template
  1104. $tpl = $this->root . '/';
  1105. if(substr($tpl, 0, 2) === './') {
  1106. $tpl = substr($tpl, 2, strlen($tpl));
  1107. }
  1108. $extra_template = array(
  1109. 'TEMPLATE' => $tpl,
  1110. 'TEMPLATE_NAME' => $this->tpl
  1111. );
  1112. $this->vars = array_merge($this->vars, $extra_template);
  1113. }
  1114. /**
  1115. * Checks for empty variable and shows language variable if possible.
  1116. */
  1117. public function lang($var) {
  1118. global $user;
  1119. if (substr($var, 0, 2) === 'L_') {
  1120. $lang = substr($var, 2);
  1121. return lang($lang, $lang);
  1122. }
  1123. if (substr($var, 0, 2) === 'U_') {
  1124. $lang = strtolower(substr($var, 2));
  1125. return s_link($lang);
  1126. }
  1127. return '';
  1128. }
  1129. //
  1130. //
  1131. // Functions added for USERGROUP MOD (optimized)
  1132. //
  1133. //
  1134. public function append_var_from_handle_to_block($blockname, $varname, $handle) {
  1135. $this->assign_var_from_handle('_tmp', $handle);
  1136. // assign the value of the generated variable to the given varname.
  1137. $this->append_block_vars($blockname, array($varname => $this->vars['_tmp']));
  1138. return true;
  1139. }
  1140. public function append_block_vars($blockname, $vararray) {
  1141. if (strstr($blockname, '.')) {
  1142. // Nested block.
  1143. $blocks = explode('.', $blockname);
  1144. $blockcount = count($blocks) - 1;
  1145. $str = &$this->_tpldata;
  1146. for($i = 0; $i < $blockcount; $i++) {
  1147. $str = &$str[$blocks[$i].'.'];
  1148. $str = &$str[count($str)-1];
  1149. }
  1150. // Now we add the block that we're actually assigning to.
  1151. // We're adding a new iteration to this block with the given
  1152. // variable assignments.
  1153. $str = &$str[$blocks[$blockcount].'.'];
  1154. $count = count($str) - 1;
  1155. if ($count >= 0) {
  1156. // adding only if there is at least one item
  1157. $str[$count] = array_merge($str[$count], $vararray);
  1158. }
  1159. } else {
  1160. // Top-level block.
  1161. // Add a new iteration to this block with the variable assignments
  1162. // we were given.
  1163. $str = &$this->_tpldata[$blockname.'.'];
  1164. $count = count($str) - 1;
  1165. if ($count >= 0) {
  1166. // adding only if there is at least one item
  1167. $str[$count] = array_merge($str[$count], $vararray);
  1168. }
  1169. }
  1170. return true;
  1171. }
  1172. /*
  1173. * Flush a root level block, so it becomes empty.
  1174. */
  1175. public function flush_block_vars($blockname) {
  1176. // Top-level block.
  1177. // flush a existing block we were given.
  1178. $current_iteration = count($this->_tpldata[$blockname . '.']) - 1;
  1179. unset($this->_tpldata[$blockname . '.']);
  1180. return true;
  1181. }
  1182. /*
  1183. * Add style configuration
  1184. */
  1185. public function _add_config($tpl, $add_vars = true) {
  1186. return false;
  1187. }
  1188. public function add_config($tpl) {
  1189. $config_name = 'xs_style_' . $tpl;
  1190. global $config;
  1191. $result = false;
  1192. if(empty($config[$config_name])) {
  1193. $old = $this->style_config;
  1194. $result = $this->_add_config($tpl, false);
  1195. $this->style_config = $old;
  1196. }
  1197. return $result;
  1198. }
  1199. /*
  1200. * Refresh config data
  1201. */
  1202. public function _refresh_config($tpl, $add_vars = false) {
  1203. return false;
  1204. }
  1205. public function refresh_config($tpl = '') {
  1206. if ($tpl === '') {
  1207. $tpl = $this->tpl;
  1208. }
  1209. if ($tpl == $this->tpl) {
  1210. $result = $this->_refresh_config($tpl, true);
  1211. } else {
  1212. $old = $this->style_config;
  1213. $result = $this->_refresh_config($tpl, false);
  1214. $this->style_config = $old;
  1215. }
  1216. return $result;
  1217. }
  1218. /*
  1219. * Get style configuration
  1220. */
  1221. public function _get_config($tpl, $add_config) {
  1222. $this->style_config = array();
  1223. if (empty($tpl)) {
  1224. $tpl = $this->tpl;
  1225. }
  1226. $config_name = 'xs_style_' . $tpl;
  1227. global $config;
  1228. if (empty($config[$config_name])) {
  1229. if($add_config) {
  1230. $this->_add_config($tpl, $tpl === $this->tpl ? true : false);
  1231. }
  1232. return $this->style_config;
  1233. }
  1234. $this->style_config = $this->_unserialize($config[$config_name]);
  1235. if ($tpl === $this->tpl) {
  1236. foreach ($this->style_config as $var => $value) {
  1237. $this->vars['TPL_CFG_' . strtoupper($var)] = $value;
  1238. }
  1239. }
  1240. return $this->style_config;
  1241. }
  1242. public function get_config($tpl = '', $add_config = true) {
  1243. if (empty($tpl)) {
  1244. if (empty($this->tpl)) {
  1245. return array();
  1246. }
  1247. $this->_get_config($this->tpl, $add_config);
  1248. return $this->style_config;
  1249. } else {
  1250. $old_config = $this->style_config;
  1251. $result = $this->_get_config($tpl, $add_config);
  1252. $this->style_config = $old_config;
  1253. return $result;
  1254. }
  1255. }
  1256. /*
  1257. * Split/merge config data.
  1258. * Using this function instead of (un)serialize because it generates smaller string
  1259. */
  1260. public function _serialize($array) {
  1261. if (!is_array($array)) {
  1262. return '';
  1263. }
  1264. $str = '';
  1265. foreach ($array as $var => $value) {
  1266. if ($str) {
  1267. $str .= '|';
  1268. }
  1269. $str .= $var . '=' . str_replace('|', '', $value);
  1270. }
  1271. return $str;
  1272. }
  1273. public function _unserialize($str) {
  1274. $array = array();
  1275. $list = explode('|', $str);
  1276. for ($i = 0; $i < count($list); $i++) {
  1277. $row = explode('=', $list[$i], 2);
  1278. if (count($row) == 2) {
  1279. $array[$row[0]] = $row[1];
  1280. }
  1281. }
  1282. return $array;
  1283. }
  1284. }
  1285. if (!function_exists('xs_switch')) {
  1286. function xs_switch($tpl, $name) {
  1287. return (isset($tpl->_tpldata[$name.'.']) && count($tpl->_tpldata[$name.'.']) > 0);
  1288. }
  1289. }