PageRenderTime 57ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/quicky_plain/Quicky.class.php

https://bitbucket.org/korchasa/php-templates-test
PHP | 488 lines | 477 code | 1 blank | 10 comment | 90 complexity | 1d0402c4d05c0fc3ee3fd0e2da5a6037 MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**************************************************************************/
  3. /* Quicky: smart and fast templates
  4. /* ver. 0.3
  5. /* ===========================
  6. /*
  7. /* Copyright (c)oded 2007 by white phoenix
  8. /* http://whitephoenix.ru
  9. /*
  10. /* Quicky.class.php: API class
  11. /**************************************************************************/
  12. ini_set('zend.ze1_compatibility_mode','Off');
  13. define('QUICKY_DIR',dirname(__FILE__).DIRECTORY_SEPARATOR);
  14. if (!defined('UNIQUE_HASH')) {define('UNIQUE_HASH',md5(microtime(TRUE).microtime(TRUE)));}
  15. if (!defined('UNIQUE_HASH_STATIC')) {define('UNIQUE_HASH_STATIC',md5('^tJI!j8gRjb1qhGMZ8Lxus4ZFc%7@kY0'));}
  16. if (!function_exists('isInteger'))
  17. {
  18. function isInteger($var)
  19. {
  20. if (is_int($var)) {return TRUE;}
  21. if (!is_string($var)) {return FALSE;}
  22. return ctype_digit(substr($var,0,1) == '-'?substr($var,1):$var);
  23. }
  24. }
  25. if (!function_exists('gpcvar_str'))
  26. {
  27. function gpcvar_str(&$var) {if (is_array($var)) {return '';} return strval($var);}
  28. function gpcvar_strnull(&$var) {if ($var === NULL) {return NULL;} if (is_array($var)) {return '';} return strval($var);}
  29. function gpcvar_int(&$var,$empty = FALSE)
  30. {
  31. $var = strval($var);
  32. if ($empty && !strlen($var)) {return $var;}
  33. return ctype_digit(substr($var,0,1) == '-'?substr($var,1):$var)?$var:0;
  34. }
  35. function gpcvar_float(&$var,$empty = FALSE) {if ($empty and strlen($var) == 0) {return '';} return floatval($var);}
  36. function gpcvar_array(&$var) {return is_array($var)?$var:array();}
  37. function gpcvar_mixed(&$var) {return $var;}
  38. }
  39. class Quicky
  40. {
  41. public $template_dir = './templates/';
  42. public $compile_dir = './templates_c/';
  43. public $config_dir = './configs/';
  44. public $cache_dir = './templates_cache/';
  45. public $plugins_dir = array();
  46. public $_tpl_vars = array();
  47. public $_tpl_config = array();
  48. public $_block_props = array();
  49. public $auto_filename_prefix = '';
  50. public $compilers = array();
  51. public $prefilters = array();
  52. public $postfilters = array();
  53. public $outputfilters = array();
  54. public $compile_check = TRUE;
  55. public $force_compile = FALSE;
  56. public $max_recursion_depth = 128;
  57. public $_auto_detect_forms = FALSE;
  58. public $_detect_forms = array();
  59. public $compiler_prefs = array('inline_includes' => TRUE, 'allow_php_native' => FALSE);
  60. public $error_reporting;
  61. public $version = '0.2';
  62. public $caching = 0;
  63. public $cache_lifetime = 60;
  64. public $precompiled_vars = array();
  65. public $lang = '';
  66. public $use_sub_dirs = FALSE;
  67. public $cache_id = '';
  68. public $compile_id = '';
  69. static $obj;
  70. public $context_path = '/';
  71. public $_contexts_data = array();
  72. function __construct()
  73. {
  74. $this->init();
  75. }
  76. function init()
  77. {
  78. $this->error_reporting = E_ALL^E_NOTICE;
  79. $this->plugins_dir = array(QUICKY_DIR.'plugins');
  80. $this->_smarty_vars = &$this->_block_props;
  81. $this->_block_props['capture'] = array();
  82. $this->_block_props['foreach'] = array();
  83. $this->_block_props['section'] = array();
  84. $this->_block_props['begin'] = array();
  85. Quicky::$obj = $this;
  86. }
  87. function detect_form($name) {$this->_detect_forms[] = $name;}
  88. function getFormByName($name)
  89. {
  90. if (!class_exists('Quicky_form')) {require_once QUICKY_DIR.'Quicky.form.class.php';}
  91. return isset(Quicky_form::$forms[$name])?Quicky_form::$forms[$name]:FALSE;
  92. }
  93. function context_fetch($name)
  94. {
  95. $path = $this->context_path($name,FALSE);
  96. if (!function_exists($a = 'quicky_context_'.$name)) {return $this->warning('Context \''.$path.'\' does not exists');}
  97. return $a();
  98. }
  99. function context_set($value = array())
  100. {
  101. $this->_contexts_data[$this->context_path] = $value;
  102. }
  103. function context_iterate($name = '')
  104. {
  105. if ($name === '') {$name = $this->context_path;}
  106. $this->_contexts_data[$this->context_path($name,FALSE)] = array(array());
  107. }
  108. function load_string($name,$string)
  109. {
  110. require_once QUICKY_DIR.'plugins/addons/stringtemplate.class.php';
  111. Quicky_Stringtemplate::$strings[$name] = $string;
  112. }
  113. function context_path($path,$onlyget = FALSE)
  114. {
  115. if ($path === '') {return $this->context_path;}
  116. if (substr($path,0,1) != '/') {$path = $this->context_path.$path.'/';}
  117. if (strpos($path,'../') !== FALSE)
  118. {
  119. $e = explode('/',$path);
  120. for ($i = 0, $s = sizeof($e); $i < $s ; ++$i)
  121. {
  122. if ($e[$i] == '..')
  123. {
  124. unset($e[$i-1]);
  125. unset($e[$i]);
  126. $e = array_values($e);
  127. $i -= 2;
  128. $s -= 2;
  129. }
  130. elseif ($e[$i] == '.') {unset($e[$i]);}
  131. }
  132. $path = implode('/',$e);
  133. }
  134. if (!$onlyget) {return $this->context_path = $path;}
  135. else {return $path;}
  136. }
  137. function _unlink($resource, $exp_time = null)
  138. {
  139. if (isset($exp_time)) {if (time() - @filemtime($resource) >= $exp_time) {return @unlink($resource);}}
  140. else {return @unlink($resource);}
  141. }
  142. function fetch_plugin($name)
  143. {
  144. if (!is_array($this->plugins_dir)) {$a = array($this->plugins_dir);}
  145. else {$a = $this->plugins_dir;}
  146. for ($i = 0,$s = sizeof($a); $i < $s; $i++)
  147. {
  148. $path = rtrim($a[$i],'/\\').DIRECTORY_SEPARATOR.$name.'.php';
  149. if (is_file($path) && is_readable($path)) {return $path;}
  150. }
  151. return FALSE;
  152. }
  153. function register_prefilter($a,$b) {$this->prefilters[$a] = $b;}
  154. function unregister_prefilter($a) {unset($this->prefilters[$a]);}
  155. function register_postfilter($a,$b) {$this->postfilters[$a] = $b;}
  156. function unregister_postfilter($a) {unset($this->postfilters[$a]);}
  157. function register_outputfilter($a,$b) {$this->outputfilters[$a] = $b;}
  158. function unregister_outputfilter($a) {unset($this->outputfilters[$a]);}
  159. function template_exists($file) {return file_exists($this->template_dir.$file);}
  160. function config_load($file,$section = '')
  161. {
  162. $path = $this->config_dir.$file;
  163. if (!is_file($path) || !is_readable($path)) {return $this->warning('Can\'t open config-file \''.$file.'\' ');}
  164. $ini = parse_ini_file($path,TRUE);
  165. if (!$ini) {return $this->warning('Errorneus ini-file \''.$file.'\'');}
  166. $section = strval($section);
  167. if ($section !== '') {$ini = (isset($ini[$section]) and is_array($ini[$section]))?$ini[$section]:array();}
  168. foreach ($ini as $k => $v)
  169. {
  170. if (is_array($v)) {$this->_tpl_config = array_merge($this->_tpl_config,$v);}
  171. else {$this->_tpl_config[$k] = $v;}
  172. }
  173. return;
  174. }
  175. function load_filter($type,$name)
  176. {
  177. if (!in_array($type,array('output','pre','post'))) {return $this->warning('Unknown filter-type \''.$type.'\'');}
  178. if (!$p = $this->fetch_plugin($type.'filter.'.$name)) {return $this->warning('Can\'t load '.$type.'-filter \''.$name.'\'');}
  179. $a = $type.'filters';
  180. if ($type == 'output') {$this->outputfilters[$name] = 'quicky_'.$type.'filter_'.$name;}
  181. elseif ($type == 'pre') {$this->prefilters[$name] = 'quicky_'.$type.'filter_'.$name;}
  182. elseif ($type == 'post') {$this->postfilters[$name] = 'quicky_'.$type.'filter_'.$name;}
  183. include $p;
  184. }
  185. function load_compiler($a)
  186. {
  187. if (!isset($this->compilers[$a]))
  188. {
  189. $path = QUICKY_DIR.$a.'_compiler.class.php';
  190. if (!is_file($path) || !is_readable($path)) {$this->warning('Can\'t load compiler \''.$a.'\'.'); return FALSE;}
  191. require_once $path;
  192. $class_name = $a.'_compiler';
  193. $this->compilers[$a] = new $class_name;
  194. $this->compilers[$a]->parent = $this;
  195. $this->compilers[$a]->prefilters = &$this->prefilters;
  196. $this->compilers[$a]->postfilters = &$this->postfilters;
  197. $this->compilers[$a]->prefs = &$this->compiler_prefs;
  198. $this->compilers[$a]->precompiled_vars = &$this->precompiled_vars;
  199. }
  200. return TRUE;
  201. }
  202. function _eval($string)
  203. {
  204. $var = &$this->_tpl_vars;
  205. $config = &$this->_tpl_config;
  206. $capture = &$this->_block_props['capture'];
  207. $foreach = &$this->_block_props['foreach'];
  208. $section = &$this->_block_props['section'];
  209. return eval($string);
  210. }
  211. function register_object($a,$b = NULL) {return $this->assign($a,$b);}
  212. function unregister_object($a) {return $this->clear_assign($a,$b);}
  213. function get_register_object($a) {return isset($this->_tpl_vars[$a])?$this->_tpl_vars[$a]:NULL;}
  214. function get_templates_vars($a = NULL) {return is_null($a)?$this->_tpl_vars:$this->_tpl_vars[$a];}
  215. function assign($a,$b = NULL)
  216. {
  217. if (is_array($a)) {$this->_tpl_vars = array_merge($this->_tpl_vars,$a);}
  218. else {$this->_tpl_vars[$a] = $b;}
  219. return TRUE;
  220. }
  221. function assign_by_ref($a,&$b) {$this->_tpl_vars[$a] = &$b; return TRUE;}
  222. function clear_assign($a)
  223. {
  224. if (is_array($a))
  225. {
  226. $a = array_values($a);
  227. $s = sizeof($a);
  228. for ($i = 0; $i < $s; $i++) {unset($this->_tpl_vars[$a[$i]]);}
  229. }
  230. else {unset($this->_tpl_vars[$a]);}
  231. }
  232. function reset() {$this->_tpl_vars = array();}
  233. function clear_all_assign() {$this->reset();}
  234. function clear_cache($path,$cache_id = NULL,$compile_id = NULL, $exp = -1)
  235. {
  236. if ($compile_id === NULL) {$compile_id = $this->compile_id;}
  237. if ($cache_id === NULL) {$cache_id = $this->cache_id;}
  238. $p = $this->_get_cache_path($path,$cache_id,$compile_id);
  239. if ($cache_id == '*')
  240. {
  241. $h = opendir($this->cache_dir);
  242. if (!$h) {return $this->warning('Can\'t open cache-dir \''.$this->cache_dir.'\'');}
  243. $e = explode('.',$p);
  244. while (($f = readdir($h)) !== FALSE)
  245. {
  246. if (is_file($this->cache_dir.$f) && strpos($f,'.'.$e[6].'.') !== FALSE) {unlink($this->cache_dir.$f);}
  247. }
  248. return TRUE;
  249. }
  250. if (is_file($p) && ($exp == -1 || (filemtime($p) < time()-$exp))) {return unlink($p);}
  251. return FALSE;
  252. }
  253. function clear_all_cache($exp = -1)
  254. {
  255. $h = opendir($this->cache_dir);
  256. if (!$h) {return $this->warning('Can\'t open cache-dir \''.$this->cache_dir.'\'');}
  257. while (($f = readdir($h)) !== FALSE)
  258. {
  259. if (is_file($this->cache_dir.$f) && ($exp == -1 || (filemtime($this->cache_dir.$f) < time()-$exp))) {unlink($this->cache_dir.$f);}
  260. }
  261. }
  262. function clear_compiled_tpl($path,$compile_id = NULL, $exp = -1)
  263. {
  264. if ($compile_id === NULL) {$compile_id = $this->compile_id;}
  265. if ($cache_id === NULL) {$cache_id = $this->cache_id;}
  266. $p = $this->_get_compile_path($path,$compile_id);
  267. if ($compile_id == '*')
  268. {
  269. $h = opendir($this->compile_dir);
  270. if (!$h) {return $this->warning('Can\'t open compile-dir \''.$this->compile_dir.'\'');}
  271. $e = explode('.',$p);
  272. while (($f = readdir($h)) !== FALSE)
  273. {
  274. if (is_file($this->compile_dir.$f) && strpos($f,'.'.$e[6].'.') !== FALSE) {unlink($this->compile_dir.$f);}
  275. }
  276. return TRUE;
  277. }
  278. if (is_file($p) && ($exp == -1 || (filemtime($p) < time()-$exp))) {return unlink($p);}
  279. return FALSE;
  280. }
  281. function clear_all_compiled_tpl($exp = -1)
  282. {
  283. $h = opendir($this->compile_dir);
  284. if (!$h) {return $this->warning('Can\'t open compile-dir \''.$this->cache_dir.'\'');}
  285. while (($f = readdir($h)) !== FALSE)
  286. {
  287. if (is_file($this->compile_dir.$f) && ($exp == -1 || (filemtime($this->compile_dir.$f) < time()-$exp))) {unlink($this->compile_dir.$f);}
  288. }
  289. }
  290. function warning($err) {trigger_error($err,E_USER_WARNING); return FALSE;}
  291. function _get_template_path($path)
  292. {
  293. if ($path == '|debug.tpl') {return QUICKY_DIR.'debug.tpl';}
  294. if (strpos($path,'://') === FALSE) {return $this->template_dir.$path;}
  295. return $path;
  296. }
  297. function _get_auto_filename($path,$cache_id = NULL,$compile_id = NULL)
  298. {
  299. if ($compile_id === NULL) {$compile_id = $this->compile_id;}
  300. if ($cache_id === NULL) {$cache_id = $this->cache_id;}
  301. $path = $this->_get_template_path($path);
  302. $name = basename($path).($this->auto_filename_prefix !== ''?'.'.$this->auto_filename_prefix:'').($compile_id !== ''?'.'.$compile_id:'').($cache_id !== ''?'.'.$cache_id:'').'.'.substr(md5($path),0,6).'.php';
  303. return $name;
  304. }
  305. function display($path,$cache_id = NULL,$compile_id = NULL, $compiler = 'Quicky') {return $this->fetch($path,$cache_id,$compile_id,TRUE,$compiler);}
  306. function is_cached($path,$cache_id = NULL,$compile_id = NULL)
  307. {
  308. if ($compile_id === NULL) {$compile_id = $this->compile_id;}
  309. if ($cache_id === NULL) {$cache_id = $this->cache_id;}
  310. if (!$this->caching) {return FALSE;}
  311. $p = $this->_get_cache_path($path,$cache_id,$compile_id);
  312. return (is_file($p) && (($this->cache_lifetime == -1) || (filemtime($p) > time()-$this->cache_lifetime)))?$p:FALSE;
  313. }
  314. function _get_compile_path($path,$compile_id)
  315. {
  316. if ($compile_id === NULL) {$compile_id = $this->compile_id;}
  317. static $cache = array();
  318. if (isset($cache[$path])) {return $cache[$path];}
  319. return $cache[$path] = $this->compile_dir.$this->_get_auto_filename($path,'',$compile_id);
  320. }
  321. function _get_cache_path($path,$cache_id = NULL,$compile_id = NULL)
  322. {
  323. if ($compile_id === NULL) {$compile_id = $this->compile_id;}
  324. if ($cache_id === NULL) {$cache_id = $this->cache_id;}
  325. return $this->cache_dir.$this->_get_auto_filename($path,$cache_id,$compile_id);
  326. }
  327. function dynamic_callback($m)
  328. {
  329. return ((isset($m[1]) && $m[1] !== '')?$m[1]:'').'echo \'!'.UNIQUE_HASH.'!non_cache='.base64_encode('<?php '.trim($m[4]).' ?>').'! \'; '.((isset($m[5]) && $m[5] !== '')?$m[5]:'');
  330. }
  331. function fetch($path,$cache_id = NULL,$compile_id = NULL,$display = FALSE,$compiler = 'Quicky')
  332. {
  333. if ($path === '' or is_null($path)) {return $this->warning('Empty path given');}
  334. if (is_dir($this->_get_template_path($path))) {return $this->warning('Path is directory');}
  335. if ($compile_id === NULL) {$compile_id = $this->compile_id;}
  336. if ($cache_id === NULL) {$cache_id = $this->cache_id;}
  337. static $nesting_path = array();
  338. static $_old_block_props = array();
  339. $return = TRUE;
  340. $var = &$this->_tpl_vars;
  341. $const = &$this->_tpl_consts;
  342. $config = &$this->_tpl_config;
  343. $capture = &$this->_block_props['capture'];
  344. $foreach = &$this->_block_props['foreach'];
  345. $section = &$this->_block_props['section'];
  346. $cache = $compile = FALSE;
  347. if (($cache = $this->is_cached($path,$cache_id,$compile_id)) or ($compile = $this->_compile($path,$compile_id,$compiler)))
  348. {
  349. $p = $cache !== FALSE?$cache:$compile;
  350. if (error_reporting() != $this->error_reporting)
  351. {
  352. $old_err_rep = error_reporting();
  353. error_reporting($this->error_reporting);
  354. }
  355. else {$old_err_rep = -1;}
  356. $nesting_path[] = $path;
  357. $recursion_depth = sizeof(array_intersect($nesting_path,array($path)));
  358. if ($recursion_depth > $this->max_recursion_depth) {$this->warning('Max recursion depth exceed.'); return;}
  359. $dir = dirname($path);
  360. if ($dir === '') {$dir = '.';}
  361. if ($this->caching && !$cache)
  362. {
  363. $c = file_get_contents($p);
  364. $a = preg_replace_callback($e = '~(<\?php )?/\*('.preg_quote(UNIQUE_HASH_STATIC,'~').')\{(dynamic)\}\*/(.*?)(?:<\?php )?/\*\{/\3\}\2\*/( \?>)?~si',array($this,'dynamic_callback'),$c);
  365. $fn = tempnam($this->cache_dir,'tmp');
  366. $fp = fopen($fn,'w');
  367. fwrite($fp,$a);
  368. fclose($fp);
  369. ob_start();
  370. $old = ob_get_contents();
  371. ob_clean();
  372. if ($this->caching == 1) {$this->caching = 0;}
  373. include $fn;
  374. $a = ob_get_contents();
  375. ob_end_clean();
  376. echo $old;
  377. unlink($fn);
  378. $a = preg_replace($e = '~!'.preg_quote(UNIQUE_HASH,'~').'!non_cache=(.*?)!~sie','base64_decode("$1")',$a);
  379. $cache = $this->_get_cache_path($path,$cache_id,$compile_id);
  380. $fp = fopen($cache,'w');
  381. fwrite($fp,$a);
  382. fclose($fp);
  383. $p = $cache;
  384. }
  385. if (!$display or sizeof($this->outputfilters) > 0)
  386. {
  387. ob_start();
  388. $old = ob_get_contents();
  389. ob_clean();
  390. if ($this->caching == 1) {$this->caching = 0;}
  391. include $p;
  392. $a = ob_get_contents();
  393. ob_end_clean();
  394. echo $old;
  395. if (sizeof($this->outputfilters) > 0)
  396. {
  397. $filters = array_values($this->outputfilters);
  398. for ($i = 0,$s = sizeof($filters); $i < $s; ++$i) {$a = call_user_func($filters[$i],$a,$this);}
  399. }
  400. if ($display) {echo $a;}
  401. else {$return = $a;}
  402. }
  403. else
  404. {
  405. if ($this->caching == 1) {$this->caching = 0;}
  406. include $p;
  407. }
  408. array_pop($nesting_path);
  409. if ($old_err_rep !== -1) {error_reporting($old_err_rep);}
  410. return $return;
  411. }
  412. else {return FALSE;}
  413. }
  414. function _is_compiled($path,$compile_id = NULL)
  415. {
  416. if ($compile_id === NULL) {$compile_id = $this->compile_id;}
  417. if ($this->force_compile) {return FALSE;}
  418. $p = $this->_get_compile_path($path,$compile_id);
  419. if (!is_file($p)) {return FALSE;}
  420. if ($this->compile_check)
  421. {
  422. if (filemtime($this->_get_template_path($path)) <= filemtime($p)) {return $p;}
  423. else {return FALSE;}
  424. }
  425. else {return $p;}
  426. }
  427. function _compile($path,$compile_id = NULL,$compiler)
  428. {
  429. if ($compile_id === NULL) {$compile_id = $this->compile_id;}
  430. if ($p = $this->_is_compiled($path,$compile_id)) {return $p;}
  431. else
  432. {
  433. $compiler_ver = array();
  434. $fp = fopen($this->_get_template_path($path),'r');
  435. if (!$fp)
  436. {
  437. $this->warning('Can\'t read template file: '.$path);
  438. return FALSE;
  439. }
  440. if ($l = fgets($fp))
  441. {
  442. preg_match_all('~/(\w+)\=(.*?)(?=/|$)~',$l,$p,PREG_SET_ORDER);
  443. for ($i = 0,$s = sizeof($p); $i < $s; $i++)
  444. {
  445. $name = strtolower($p[$i][1]);
  446. $value = $p[$i][2];
  447. if ($name == 'compiler')
  448. {
  449. preg_match('~^(\w+)\s*(?:(>=|==|<=|<|>)?\s*(\S*))?~',$value,$q);
  450. $compiler = $q[1];
  451. if (isset($q[2])) {$compiler_ver = array($q[2],$q[3]);}
  452. }
  453. }
  454. }
  455. fclose($fp);
  456. if (!$this->load_compiler($compiler)) {return FALSE;}
  457. if (sizeof($compiler_ver) > 0)
  458. {
  459. preg_match('~^[\d.]+~',$this->compilers[$compiler]->compiler_version,$q);
  460. $ver = (int) str_replace('.','',$q);
  461. if (!eval('return '.$ver.' '.$compiler_ver[0].' '.$compiler_ver[1].';'))
  462. {
  463. $this->warning('Incompatible version of compiler '.$compiler.' ('.$this->compilers[$compiler]->compiler_version.') for template '.$path.' needed '.$compiler_ver[1]);
  464. return FALSE;
  465. }
  466. }
  467. $source = $this->compilers[$compiler]->_compile_source($this->_get_template_path($path));
  468. $fp = fopen($c = $this->_get_compile_path($path,$compile_id),'w');
  469. if (!$fp) {return FALSE;}
  470. fwrite($fp,$source);
  471. fclose($fp);
  472. return $c;
  473. }
  474. }
  475. function _compile_string($string,$compiler = 'Quicky')
  476. {
  477. $this->load_compiler($compiler);
  478. return $this->compilers[$compiler]->_compile_source_string($string);
  479. }
  480. static function ind($a,$b = 0)
  481. {
  482. $s = $a['st'] + abs($a['step']) * ($a['i']+$b);
  483. if ($s < 0) {return -1;}
  484. if ($a['step'] < 0) {$s = $a['s'] - $s;}
  485. return $s;
  486. }
  487. }