PageRenderTime 67ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/quicky_plain/Quicky_compiler.class.php

https://bitbucket.org/korchasa/php-templates-test
PHP | 1269 lines | 1248 code | 10 blank | 11 comment | 157 complexity | 7b28621fc894cae81ebfca2db5723b33 MD5 | raw file
Possible License(s): LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  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_compiler.class.php: Template compiler
  11. /**************************************************************************/
  12. class Quicky_compiler
  13. {
  14. public $precompiled_vars = array();
  15. public $prefilters = array();
  16. public $postfilters = array();
  17. public $compiler_name = 'Quicky';
  18. public $compiler_version = '0.3';
  19. public $load_plugins = array();
  20. public $seq = array();
  21. public $seq_id = 0;
  22. public $_alt_tag = FALSE;
  23. public $prefs = array();
  24. public $template_defined_functions = array();
  25. public $_cast_undefined_token_to_strings = TRUE;
  26. public $allowed_php_tokens = array('array','date','strtotime','isset','empty','is_empty','count', 'sizeof',
  27. 'is_array','is_int','is_float','is_long','is_numeric','is_object',
  28. 'is_scalar','is_string','gettype','is_real',
  29. 'abs','acos','acosh','asin','asinh','atan2','atan','atanh','base_','bindec',
  30. 'ceil','cos','cosh','decbin','dechex','decoct','deg2rad','exp','expm1','floor',
  31. 'fmod','getrandmax','hexdec','hypot','is_finite','is_infinite','is_nan','lcg_','log10','log1p',
  32. 'log','max','min','mt_getrandmax','mt_rand','mt_srand','octdec','pi','pow','rad2deg','rand',
  33. 'round','sin','sinh','sqrt','srand','tan','tanh',
  34. 'constant','strlen','time','var_dump','var_export',
  35. 'gmp_*','ctype_*','array_*','addcslashes','addslashes','bin2hex','chop','chr',
  36. 'chunk_split','convert_cyr_string','convert_uudecode','convert_uuencode','count_chars',
  37. 'crc32','crypt','echo','explode','fprintf','get_html_translation_table','hebrev','hebrevc',
  38. 'html_entity_decode','htmlentities','htmlspecialchars_decode','htmlspecialchars','implode',
  39. 'join','levenshtein','localeconv','ltrim','md5_file','md5','metaphone','money_format',
  40. 'nl_langinfo','nl2br','number_format','ord','parse_str','print','printf',
  41. 'quoted_printable_decode','quotemeta','rtrim','sha1_file','sha1','similar_text',
  42. 'soundex','sprintf','sscanf','str_ireplace','str_pad','str_repeat','str_replace',
  43. 'str_rot13','str_shuffle','str_split','str_word_count','strcasecmp','strchr',
  44. 'strcmp','strcoll','strcspn','strip_tags','stripcslashes','stripos','stripslashes',
  45. 'stristr','strlen','strnatcasecmp','strnatcmp','strncasecmp','strncmp','strpbrk',
  46. 'strpos','strrchr','strrev','strripos','strrpos','strspn','strstr','strtok',
  47. 'strtolower','strtoupper','strtr','substr_compare','substr_count','substr_replace',
  48. 'substr','trim','ucfirst','ucwords','vfprintf','vprintf','vsprintf','wordwrap','and','or','xor');
  49. public $allowed_php_constants = array();
  50. public $syntax_error = NULL;
  51. public $template_from;
  52. public $blocks = array();
  53. public $left_delimiter = '{';
  54. public $right_delimiter = '}';
  55. public $magic_constants = array('tplpath','tplpathdir','ldelim','rdelim');
  56. public $block_props = array();
  57. public $_write_out_to = '';
  58. public $_halt = FALSE;
  59. public $_tag_stacks = array();
  60. public $_tag_stack_n = 0;
  61. public $_no_magic = FALSE;
  62. public $no_optimize = FALSE;
  63. public $_tmp = array();
  64. public $_cpl_vars = array();
  65. public $_cpl_config = array();
  66. function Quicky_compiler() {}
  67. static function escape_string($s)
  68. {
  69. static $escape = array(
  70. '\\' => '\\\\',
  71. '\'' => '\\\''
  72. );
  73. return strtr($s,$escape);
  74. }
  75. function push_block_props($props,$blocktype,$name)
  76. {
  77. for ($i = 0; $i < sizeof($props); $i++) {$this->block_props[$props[$i]] = array($name,$blocktype);}
  78. return TRUE;
  79. }
  80. function _syntax_error($error) {$this->syntax_error = $error; return UNIQUE_HASH.'~~error here~~';}
  81. function _write_seq($m)
  82. {
  83. if (!isset($this->seq[$this->seq_id])) {$this->seq[$this->seq_id] = array();}
  84. $this->seq[$this->seq_id][] = $m[1];
  85. return $this->seq_hash;
  86. }
  87. function _read_seq($reset = FALSE)
  88. {
  89. static $i = array();
  90. if ($reset === TRUE or !isset($i[$this->seq_id])) {$i[$this->seq_id] = 0; return;}
  91. return $this->seq[$this->seq_id][$i[$this->seq_id]++];
  92. }
  93. function register_block($block)
  94. {
  95. if (!in_array($block,$this->blocks)) {$this->blocks[] = $block;}
  96. return TRUE;
  97. }
  98. function unregister_block($block)
  99. {
  100. if ($k = array_search($block,$this->blocks)) {unset($this->blocks[$k]); return TRUE;}
  101. else {return FALSE;}
  102. }
  103. function _block_lang_callback($m)
  104. {
  105. $name = $m[2];
  106. $tag = $m[3];
  107. preg_match_all('~\{(\w+)\}(.*?)(?=\{\w+\}|\z)~s',$tag,$matches,PREG_SET_ORDER);
  108. $variants = array();
  109. foreach ($matches as $m) {$variants[strtolower($m[1])] = trim($m[2]);}
  110. $reqlang = $this->parent->lang;
  111. if (isset($variants[$reqlang])) {return $variants[$reqlang];}
  112. return isset($variants['default'])?$variants['default']:'Warning! Can\'t find phrase '.($name !== ''?'('.htmlspecialchars($name).')':'').' for this language.';
  113. }
  114. function _form_detect_field($m)
  115. {
  116. $tag = strtolower($m[1] !== ''?$m[1]:$m[3]);
  117. $params = $this->_parse_params($m[1] !== ''?$m[2]:$m[4],TRUE);
  118. if ($tag == 'option')
  119. {
  120. $params['text'] = $m[5];
  121. if (!isset($params['value'])) {$params['value'] = $params['text'];}
  122. }
  123. elseif ($tag == 'textarea')
  124. {
  125. $params['value'] = $m[5];
  126. }
  127. $p = '';
  128. if (isset($params['name']) and !isset($params['join'])) {$params['join'] = $params['name'];}
  129. foreach ($params as $k => $v) {$p .= $k.'=\''.$this->escape_string($this->_dequote($v)).'\' ';}
  130. $p = substr($p,0,-1);
  131. if ($tag == 'input' or $tag == 'textarea')
  132. {
  133. $return = $this->left_delimiter.$tag.' '.$p.$this->right_delimiter;
  134. }
  135. elseif ($tag == 'option')
  136. {
  137. $return = $this->left_delimiter.'option '.$p.$this->right_delimiter;
  138. }
  139. elseif ($tag == 'select')
  140. {
  141. $body = preg_replace_callback('~<(option)(\s+.*?)?>(.*?)</\3>~si',array($this,'_form_detect_field'),$m[2]);
  142. $return = $this->left_delimiter.$tag.' '.$p.$this->right_delimiter.$m[5].$this->left_delimiter.'/'.$tag.$this->right_delimiter;
  143. }
  144. return $return;
  145. }
  146. function _form_detect($m)
  147. {
  148. $params = $this->_parse_params($m[1],TRUE);
  149. $form_name = '';
  150. $p = '';
  151. $params['auto_object'] = 1;
  152. foreach ($params as $k => $v)
  153. {
  154. if (strtolower($this->_dequote($k)) == 'name') {$form_name = $this->_dequote($v);}
  155. $p .= $k.'=\''.$this->escape_string($this->_dequote($v)).'\' ';
  156. }
  157. if (!$this->parent->_auto_detect_forms and !in_array($form_name,$this->parent->_detect_forms)) {return $m[0];}
  158. $p = substr($p,0,-1);
  159. $body = preg_replace_callback('~<(input)(\s+.*?)?\s*/?\s*>|<(textarea|select)(\s+.*?)?>(.*?)</\3>~si',array($this,'_form_detect_field'),$m[2]);
  160. $return = '{form '.$p.'}'.$body.'{/form}';
  161. return $return;
  162. }
  163. function _compile_source_string($template,$from)
  164. {
  165. $old_load_plugins = $this->load_plugins;
  166. $this->load_plugins = array();
  167. $this->template_from = $from;
  168. //$template = preg_replace('~\r\n|\r(?!\n)~',"\n",$template);
  169. $template = preg_replace('~^/.*?/\r?\n~','',$template);
  170. $ldelim = preg_quote($this->left_delimiter,'~');
  171. $rdelim = preg_quote($this->right_delimiter,'~');
  172. $template = preg_replace_callback('~([\'"]).*?\1|('.$ldelim.'\*.*?\*'.$rdelim.')~s',create_function('$m','if (!isset($m[2])) return $m[0]; return \'\';'),$template);
  173. $a = array_values($this->prefilters);
  174. for ($i = 0,$s = sizeof($a); $i < $s; $i++) {$template = call_user_func($a[$i],$template,$this);}
  175. $source = $template;
  176. if ($this->parent->lang !== '')
  177. {
  178. $source = preg_replace_callback('~'.$ldelim.'_\s+(.*?)'.$rdelim.'~',$this->parent->lang_callback,$source);
  179. $source = preg_replace_callback('~'.$ldelim.'e_\s+(.*?)'.$rdelim.'~i',$this->parent->lang_callback_e,$source);
  180. $source = preg_replace_callback('~'.$ldelim.'LANG(?:=([\'|"])?(.*?)\1)?'.$rdelim.'(.*?)'.$ldelim.'/LANG'.$rdelim.'~si',array($this,'_block_lang_callback'),$source);
  181. }
  182. if ($this->parent->_auto_detect_forms or sizeof($this->parent->_detect_forms) > 0)
  183. {
  184. $source = preg_replace_callback('~<form(\s+.*?)?>(.*?)</form>~si',array($this,'_form_detect'),$source);
  185. }
  186. if (!isset($this->prefs['allow_php_native']) or !$this->prefs['allow_php_native'])
  187. {
  188. $source = preg_replace('~<\?(?:php)?|\?>~i','<?php echo \'$0\'; ?>',$source);
  189. }
  190. $this->seq_hash = md5(microtime());
  191. $ldelim = preg_quote($this->left_delimiter,'~');
  192. $rdelim = preg_quote($this->right_delimiter,'~');
  193. $source = preg_replace_callback('~'.$ldelim.'literal'.$rdelim.'(.*?)'.$ldelim.'/literal'.$rdelim.'~si',array($this,'_write_seq'),$source);
  194. $cur_seq = $this->seq;
  195. $cur_hash = $this->seq_hash;
  196. $this->seq = array();
  197. $source = $this->_tag_token($source);
  198. $this->seq = $cur_seq;
  199. $this->seq_hash = $cur_hash;
  200. $this->_read_seq(TRUE);
  201. $source = preg_replace_callback('~'.$this->seq_hash.'~si',array($this,'_read_seq'),$source);
  202. $this->seq = array();
  203. if (!$this->no_optimize and FALSE)
  204. {
  205. $source = preg_replace_callback('~\?>(.{0,20}?)<\?php~s',create_function('$m','if ($m[1] === \'\') {return \'\';} return \' echo \\\'\'.Quicky_compiler::escape_string($m[1]).\'\\\';'."\n".'\';'),$source);
  206. $source = preg_replace_callback('~^(.{1,20}?)(<\?php)~s',create_function('$m','return $m[2].\' echo \\\'\'.Quicky_compiler::escape_string($m[1]).\'\\\';'."\n".'\';'),$source);
  207. $source = preg_replace_callback('~(\?>)(.{1,20})$~s',create_function('$m','return \' echo \\\'\'.Quicky_compiler::escape_string($m[2]).\'\\\';'."\n".'\'.$m[1];'),$source);
  208. }
  209. $header = '<?php /* Quicky compiler version '.$this->compiler_version.', created on '.date('r').'
  210. compiled from '.$from.' */'."\n";
  211. for ($i = 0,$s = sizeof($this->load_plugins); $i < $s; $i++)
  212. {
  213. $header .= 'require_once '.var_export($this->load_plugins[$i],TRUE).';'."\n";
  214. }
  215. $header .= '?>';
  216. if ($this->syntax_error !== NULL)
  217. {
  218. $line = '~';
  219. $e = preg_split('~\r?\n|\r(?=\n)~',$source);
  220. for ($i = 0,$s = sizeof($e); $i < $s; $i++)
  221. {
  222. if (strpos($e[$i],UNIQUE_HASH.'~~error here~~') !== FALSE) {$line = $i+1; break;}
  223. }
  224. return 'Quicky syntax error '.$this->syntax_error.' in template '.$from.' on line '.$line;
  225. }
  226. $this->_halt = FALSE;
  227. $a = array_values($this->postfilters);
  228. for ($i = 0,$s = sizeof($a); $i < $s; $i++) {$soruce = call_user_func($a[$i],$source,$this);}
  229. $this->load_plugins = $old_load_plugins;
  230. $source = preg_replace('~^(<\?php.*?)\?><\?php~si','$1',$header.$source);
  231. return $source;
  232. }
  233. function _compile_source($path) {return $this->_compile_source_string(file_get_contents($path),substr($path,strlen($this->parent->template_dir)));}
  234. function string_or_expr($s)
  235. {
  236. if (ctype_digit(substr($s,0,1) == '-'?substr($s,1):$s)) {return $s;}
  237. if (preg_match('~^\w+$~',$s))
  238. {
  239. if (defined($s) or in_array(strtolower($s),$this->magic_constants) or isset($this->_block_props[strtolower($s)]))
  240. {
  241. return $s;
  242. }
  243. return '\''.$s.'\'';
  244. }
  245. return $s;
  246. }
  247. function _parse_params($p,$plain = FALSE)
  248. {
  249. $params = array();
  250. preg_match_all('~\w+\s*=|(([\'"]).*?(?<!\\\\)\2|\w*\s*\(((?:(?R)|.)*?)\)'
  251. .'|_?[\$#]\w+#?(?:\\[(?:(?R)|((?:[^\\]\'"]*(?:([\'"]).*?(?<!\\\\)\5)?)*))*?\\]|\.[\$#]?\w+#?|->\s*[\$#]?\w+(?:\(((?:(?R)|.)*?)\))?)*'
  252. .'|-?\d+|(?<=^|[\s\)\:\.=+\-<>])(?:\w+)(?=$|[\s\|\.\:\(=+\-<>]))~s',$p,$m,PREG_SET_ORDER);
  253. $lastkey = '';
  254. foreach ($m as $v)
  255. {
  256. if (trim($v[0]) === '') {continue;}
  257. if (sizeof($v) == 1) {$lastkey = ltrim(rtrim($v[0]," =\t")); continue;}
  258. if ($lastkey === '') {$params[] = $plain?$v[0]:$this->_expr_token($this->string_or_expr($v[0]));}
  259. else {$params[$lastkey] = $plain?$v[0]:$this->_expr_token($this->string_or_expr($v[0]));}
  260. $lastkey = '';
  261. }
  262. return $params;
  263. }
  264. function _dequote($string)
  265. {
  266. $a = substr($string,0,1);
  267. $string = preg_replace('~^\s*([\'"])(.*)\1\s*$~','$2',$string);
  268. return preg_replace('~(?<!\\\\)\\\\'.preg_quote($a,'~').'~',$a,$string);
  269. }
  270. function _get_expr_blockprop($name,$blocktype,$prop)
  271. {
  272. $blocktype = strtolower($blocktype);
  273. $prop = strtolower($prop);
  274. $a = '$'.$blocktype.'['.var_export($name,TRUE).']';
  275. if ($blocktype == 'foreach')
  276. {
  277. if ($prop == 'iteration' or $prop == 'i') {$prop = 'i';}
  278. elseif ($prop == 'total') {$prop = 's';}
  279. elseif ($prop == 'first') {return '('.$a.'[\'i\'] == 1)';}
  280. elseif ($prop == 'last') {return '('.$a.'[\'i\']+1 == '.$a.'[\'s\'])';}
  281. }
  282. elseif ($blocktype == 'section')
  283. {
  284. if ($prop == 'iteration' or $prop == 'rownum') {return '('.$a.'[\'i\']+1)';}
  285. elseif ($prop == 'index' or $prop == $name) {return 'Quicky::ind('.$a.')';}
  286. elseif ($prop == 'index_prev' or $prop == $name) {return 'Quicky::ind('.$a.',-1)';}
  287. elseif ($prop == 'index_next' or $prop == $name) {return 'Quicky::ind('.$a.',1)';}
  288. elseif ($prop == 'total') {$prop = 's';}
  289. elseif ($prop == 'first') {return '('.$a.'[\'i\'] == 0)';}
  290. elseif ($prop == 'last') {return '('.$a.'[\'i\']+1 == '.$a.'[\'s\'])';}
  291. }
  292. elseif ($blocktype == 'form')
  293. {
  294. if ($prop == 'form') {return 'Quicky_form::$forms['.var_export($name,TRUE).']';}
  295. }
  296. return $a.'['.var_export($prop,TRUE).']';
  297. }
  298. function _joincalc_callback($m)
  299. {
  300. if (isset($this->_tmp[$m[0]])) {return 'document.getElementById(\''.$this->_tmp[$m[0]].'\').value';}
  301. else {return $m[0];}
  302. }
  303. function _optimize_callback($m)
  304. {
  305. $prefix = ' '.$this->_write_out_to !== ''?$this->_write_out_to.' .= ':'echo ';
  306. if (isset($m[1]) and $m[1] !== '') {$return = $prefix.var_export($m[1],TRUE).';';}
  307. elseif (isset($m[2]) and $m[2] !== '') {$return = $prefix.var_export($m[2],TRUE).';';}
  308. elseif (isset($m[3]) and $m[3] !== '') {$return = $prefix.var_export($m[3],TRUE).';';}
  309. else {$return = '';}
  310. return $return;
  311. }
  312. function _optimize($block)
  313. {
  314. $block = preg_replace_callback((!preg_match('~<\?php|\?>~i',$block))?'~(.*)~s':'~\?>(.*?)<\?php|^(.*?)<\?php|\?>(.*?)$~si',array($this,'_optimize_callback'),$block);
  315. return $block;
  316. }
  317. function _fetch_expr($expr)
  318. {
  319. $var = &$this->_cpl_vars;
  320. $config = &$this->_cpl_config;
  321. return @eval('return '.$expr.';');
  322. }
  323. function _tag_token($mixed,$block_parent = '')
  324. {
  325. if (!isset($this->_tag_stacks[$this->_tag_stack_n])) {$this->_tag_stacks[$this->_tag_stack_n] = array();}
  326. if ($this->_halt && !(is_array($mixed) && isset($mixed[4]) && strtolower($mixed[4]) == 'resumecompiler'))
  327. {
  328. return is_array($mixed)?$mixed[0]:$mixed;
  329. }
  330. if (is_array($mixed))
  331. {
  332. if ((isset($mixed[6]) && $mixed[6] !== '') || (isset($mixed[10]) && $mixed[10] !== ''))
  333. {
  334. $a = array(
  335. 0 => $mixed[0],
  336. 1 => $mixed[6]
  337. );
  338. if (isset($mixed[7])) {$a[2] = $mixed[7];}
  339. if (isset($mixed[9])) {$a[3] = $mixed[9];}
  340. if (isset($mixed[10])) {$a[4] = $mixed[10];}
  341. $mixed = $a;
  342. $this->_alt_tag = FALSE;
  343. }
  344. else {$this->_alt_tag = TRUE;}
  345. if (isset($mixed[4]) && $mixed[4] !== '')
  346. {
  347. preg_match('~^\s*(\S+)(.*)~s',$mixed[4],$m);
  348. if (!isset($m[0])) {$m[0] = '';}
  349. if (!isset($m[1])) {$m[1] = '';}
  350. $tag = strtolower($m[1]);
  351. if ($tag == 'if' or $tag == 'elseif' or $tag == 'else if')
  352. {
  353. if (trim($m[2]) == '') {return $this->_syntax_error('Empty condition.');}
  354. return '<?php '.$tag.' ('.$this->_expr_token($m[2],FALSE,TRUE).'): ?>';
  355. }
  356. elseif ($tag == 'case')
  357. {
  358. if (trim($m[2]) == '') {return $this->_syntax_error('Empty condition.');}
  359. return '<?php '.$tag.' '.$this->_expr_token($m[2],FALSE,TRUE).': ?>';
  360. }
  361. elseif ($tag == 'else' or $tag == 'default') {return '<?php '.$tag.': ?>';}
  362. elseif ($tag == '/if') {return '<?php endif; ?>';}
  363. elseif ($tag == 'return' or $tag == 'halt') {if ($tag == 'halt') {$this->_halt = TRUE;} $code = $this->_expr_token($m[2]); return '<?php return'.($code !== ''?' '.$code:'').'; ?>';}
  364. elseif ($tag == 'haltcompiler') {$this->_halt = TRUE;}
  365. elseif ($tag == 'resumecompiler') {$this->_halt = FALSE;}
  366. elseif ($tag == 'break') {$code = $this->_expr_token($m[2]); return '<?php break'.($code !== ''?' '.$code:'').'; ?>';}
  367. elseif ($tag == 'continue') {return '<?php continue; ?>';}
  368. elseif (preg_match('~^\w+$~',$tag) && ($p = $this->parent->fetch_plugin('compiler.'.$tag)))
  369. {
  370. require_once $p;
  371. $params = $this->_parse_params($m[2]);
  372. $a = 'quicky_compiler_'.$tag;
  373. $return = $a($params,$this);
  374. return $return;
  375. }
  376. elseif (preg_match('~^\w+$~',$tag) && (($c = in_array($tag,$this->template_defined_functions)) || ($p = $this->parent->fetch_plugin('function.'.$tag))))
  377. {
  378. $params = $this->_parse_params($m[2]);
  379. $key_params = array();
  380. foreach ($params as $k => $v) {$key_params[] = var_export($k,TRUE).' => '.$v;}
  381. if (!in_array($p,$this->load_plugins) and !$c) {$this->load_plugins[] = $p;}
  382. return '<?php '.($this->_write_out_to !== ''?$this->_write_out_to.' .=':'echo').' quicky_function_'.$tag.'(array('.implode(',',$key_params).'),$this,TRUE);'."\n".'?>';
  383. }
  384. elseif ($tag == 'foreachelse')
  385. {
  386. $this->_tag_stacks[$this->_tag_stack_n][] = $tag;
  387. return '<?php endforeach; else: ?>';
  388. }
  389. elseif ($tag == 'sectionelse')
  390. {
  391. $this->_tag_stacks[$this->_tag_stack_n][] = $tag;
  392. return '<?php endfor; else: ?>';
  393. }
  394. elseif ($tag == 'optgroup')
  395. {
  396. $params = $this->_parse_params($m[2]);
  397. $params['text'] = isset($params['text'])?$params['text']:'';
  398. $params['text'] = strpos($params['text'],'$') !== FALSE?'<?php echo htmlspecialchars('.$params['text'].',ENT_QUOTES); ?>':htmlspecialchars($this->_dequote($params['text']));
  399. return '<optgroup label="'.$params['text'].'">';
  400. }
  401. elseif ($tag == '/optgroup') {return '</optgroup>';}
  402. elseif ($tag == 'option')
  403. {
  404. $tk = -1;
  405. for ($i = sizeof($this->_tag_stacks)-1; $i >= 0; $i--)
  406. {
  407. if (isset($this->_tag_stacks[$i]['type']) && $this->_tag_stacks[$i]['type'] == 'select') {$tk = $i;}
  408. }
  409. if ($tk != -1)
  410. {
  411. $params = $this->_parse_params($m[2]);
  412. $s = '';
  413. foreach ($params as $k => $v)
  414. {
  415. if ($k == 'checked') {$s .= '<?php if ('.$v.($params['type'] == '\'radio\''?' == '.$params['value'].(is_int(array_search('\'default\'',$params))?' or '.$v.' == \'\'':''):'').') {echo \' checked\';} ?>';}
  416. elseif (strpos($v,'$') !== FALSE) {$s .= ' '.$k.'="<?php echo htmlspecialchars('.$v.',ENT_QUOTES); ?>"';}
  417. else {$s .= ' '.$k.'="'.htmlspecialchars($this->_dequote($v,ENT_QUOTES)).'"';}
  418. }
  419. $params['text'] = isset($params['text'])?$params['text']:'';
  420. if (!isset($params['value'])) {$params['value'] = $params['text'];}
  421. $params['text'] = strpos($params['text'],'$') !== FALSE?'<?php echo htmlspecialchars('.$params['text'].',ENT_QUOTES); ?>':htmlspecialchars($this->_dequote($params['text']));
  422. if ($this->_tag_stacks[$tk]['value'] !== '' and isset($params['value']))
  423. {
  424. $s .= '<?php if ('.$this->_tag_stacks[$tk]['value'].' == '.$params['value'].') {echo \' selected\';} ?>';
  425. }
  426. return '<option'.$s.'>'.$params['text'].'</option>';
  427. }
  428. else {return $this->_syntax_error('Unexcepted tag \'option\'');}
  429. }
  430. elseif (preg_match('~^'.preg_quote($this->left_delimiter,'~').'\\*.*\\*'.preg_quote($this->right_delimiter,'~').'$~s',$mixed[0])) {return '';}
  431. else
  432. {
  433. if ($this->_alt_tag and preg_match('~^\w+$~',trim($m[0])))
  434. {
  435. $m[0] = '$'.trim($m[0]);
  436. }
  437. $outoff = FALSE;
  438. $plain = FALSE;
  439. if (substr($m[0],0,1) == '_')
  440. {
  441. $m[0] = substr($m[0],1);
  442. if (substr($m[0],0,1) == '_') {$m[0] = substr($m[0],1);}
  443. if (substr($m[0],0,1) == '?') {$m[0] = substr($m[0],1); $outoff = TRUE;}
  444. $e = $this->_fetch_expr($this->_expr_token($m[0],FALSE,TRUE));
  445. $plain = TRUE;
  446. }
  447. else
  448. {
  449. if (substr($m[0],0,1) == '?')
  450. {
  451. $e = $this->_expr_token(substr($m[0],1),FALSE,TRUE);
  452. $outoff = TRUE;
  453. }
  454. else {$e = $this->_expr_token($m[0],FALSE,TRUE);}
  455. }
  456. if ($plain) {return $e;}
  457. if ($e === '' or $e === '\'\'') {return '';}
  458. return '<?php '.($outoff?'':($this->_write_out_to !== ''?$this->_write_out_to.' .=':'echo').' ').$e.'; ?>';
  459. }
  460. return;
  461. }
  462. ++$this->_tag_stack_n;
  463. $block_name = strtolower($mixed[1]);
  464. $block_content = $mixed[3];
  465. if ($block_name == 'foreach')
  466. {
  467. $block_params = $this->_parse_params($mixed[2]);
  468. if (!isset($block_params['from'])) {return $this->_syntax_error('Missing parameter \'from\' in foreach tag.');}
  469. if (!isset($block_params['item']) && !isset($block_params['value'])) {return $this->_syntax_error('Missing parameter \'item\' in foreach tag.');}
  470. $return = '<?php $_from = '.$block_params['from'].';'."\n";
  471. if (isset($block_params['name']) and ($name = trim($this->_dequote($block_params['name']))) !== '')
  472. {
  473. $props = array('first','last','index','iteration','i','total');
  474. $a = $this->block_props;
  475. $this->push_block_props($props,$block_name,$name);
  476. $block = $this->_tag_token($block_content,$block_name);
  477. $this->block_props = $a;
  478. $name = var_export($name,TRUE);
  479. $return .= "\n".'$foreach['.$name.'] = array();'
  480. ."\n".'$foreach['.$name.'][\'i\'] = 0;'
  481. ."\n".'$foreach['.$name.'][\'s\'] = sizeof($_from);'
  482. ."\n";
  483. }
  484. else {$return .= ' '; $name = ''; $block = $this->_tag_token($block_content,$block_name);}
  485. $return .= 'if ('.($name !== ''?'$foreach['.$name.'][\'show\'] = ':'').($name !== ''?'$foreach['.$name.'][\'s\']':'sizeof($_from)').' > 0):'
  486. .' foreach ($_from as'.(isset($block_params['key'])?' $var['.$block_params['key'].'] =>':'').' $var['.(isset($block_params['item'])?$block_params['item']:$block_params['value']).']): '
  487. .($name !== ''?"\n".'++$foreach['.$name.'][\'i\'];'.'':'')
  488. .'?>'
  489. .$block;
  490. if (($k = array_search('foreachelse',$this->_tag_stacks[$this->_tag_stack_n])) !== FALSE)
  491. {
  492. $return .= '<?php endif; ?>';
  493. unset($this->_tag_stacks[$this->_tag_stack_n][$k]);
  494. }
  495. else {$return .= '<?php endforeach; endif; ?>';}
  496. }
  497. elseif ($block_name == 'joincalculator')
  498. {
  499. $block_params = $this->_parse_params($mixed[2]);
  500. if (!isset($block_params['name'])) {return $this->_syntax_error('Missing parameter \'name\' in joincalculator tag.');}
  501. if (!isset($block_params['fields'])) {return $this->_syntax_error('Missing parameter \'fields\' in joincalculator tag.');}
  502. $block_params['name'] = strpos($block_params['name'],'$') !== FALSE?'<?php echo '.$block_params['name'].'; ?>':$this->_dequote($block_params['name']);
  503. $block_params['fields'] = explode(',',$this->_dequote($block_params['fields']));
  504. $fields = array();
  505. $return = '<script type="text/javascript">
  506. function calculator_'.$block_params['name'].'(field)
  507. {
  508. ';
  509. foreach ($block_params['fields'] as $k => $v)
  510. {
  511. if (preg_match('~(.*?)\s+as\s+(.*)~i',$v,$q))
  512. {
  513. if (isset($fields[$q[2]])) {return $this->_syntax_error('Field name \''.$q[2].'\' alredy in use ');}
  514. $fields[$q[2]] = $q[1];
  515. $fields[$q[1]] = $q[1];
  516. }
  517. else {$fields[$v] = $v;}
  518. }
  519. $f = '';
  520. foreach ($fields as $k => $v) {$f .= '|'.preg_quote($k,'~');}
  521. if ($f === '') {return $this->_syntax_error('No fields');}
  522. $this->_tmp = $fields;
  523. preg_match_all('~\s*(.*?)\s*=\s*(.*?)(?:[\r\n]+|$)~m',$block_content,$m,PREG_SET_ORDER);
  524. foreach ($m as $v)
  525. {
  526. $name = $v[1];
  527. $expr = $v[2];
  528. $left = preg_replace_callback($a = '~([\'"]).*?\1'.$f.'~',array($this,'_joincalc_callback'),$name);
  529. $right = preg_replace_callback('~([\'"]).*?\1'.$f.'~',array($this,'_joincalc_callback'),$expr);
  530. $return .= 'if (field != \''.$name.'\') '.$left.' = '.$right.';
  531. ';
  532. }
  533. $this->_tmp = array();
  534. $return .= '}';
  535. foreach ($fields as $k => $v)
  536. {
  537. if ($k != $v) {continue;}
  538. $return .= '
  539. document.getElementById(\''.$v.'\').onchange = function() {setTimeout(function() {calculator_'.$block_params['name'].'("'.$v.'");},50);}';
  540. if (is_int(array_search('\'onkeydown\'',$block_params)))
  541. {
  542. $return .= '
  543. document.getElementById(\''.$v.'\').onkeydown = function() {setTimeout(function() {calculator_'.$block_params['name'].'("'.$v.'");},50);}';
  544. }
  545. }
  546. $return .= '
  547. </script>';
  548. }
  549. elseif ($block_name == 'for')
  550. {
  551. $block_params = $this->_parse_params($mixed[2]);
  552. if (!isset($block_params['start'])) {$block_params['start'] = 0;}
  553. if (!isset($block_params['step'])) {$block_params['step'] = 1;}
  554. if (!isset($block_params['loop'])) {return $this->_syntax_error('Missing parameter \'loop\' in for tag.');}
  555. if (!isset($block_params['value'])) {return $this->_syntax_error('Missing parameter \'value\' in for tag.');}
  556. $return = '<?php'
  557. ."\n".'for ('.$block_params['value'].' = '.$block_params['start'].'; '.$block_params['value'].' < '.$block_params['loop'].'; '.$block_params['value'].' += '.$block_params['step'].'): ?>'
  558. .$this->_tag_token($block_content,$block_name)
  559. .'<?php endfor; ?>';
  560. }
  561. elseif ($block_name == 'form')
  562. {
  563. $block_params = $this->_parse_params($mixed[2]);
  564. if (!isset($block_params['name']) && !isset($block_params['no_quicky_form']) && !is_int(array_search('no_quicky_form',$block_params))) {return $this->_syntax_error('Missing parameter \'name\' in section tag.');}
  565. $mode = !isset($block_params['no_quicky_form']) and !is_int(array_search('no_quicky_form',$block_params));
  566. $auto_object = isset($block_params['auto_object']);
  567. unset($block_params['auto_object']);
  568. $code = '';
  569. if ($mode)
  570. {
  571. if (!class_exists('Quicky_form'))
  572. {
  573. if ($auto_object) {require_once QUICKY_DIR.'Quicky.form.class.php';}
  574. else {return $this->_syntax_error('Class Quicky_form isn\'t loaded');}
  575. }
  576. $name = $this->_dequote($block_params['name']);
  577. if (!isset(Quicky_form::$forms[$name]))
  578. {
  579. if ($auto_object)
  580. {
  581. $code = '<?php'."\n".'if (!class_exists(\'Quicky_form\')) {require_once QUICKY_DIR.\'Quicky.form.class.php\';}'."\n".'if (!isset(Quicky_form::$forms[\''.$name.'\'])) {$form = new Quicky_form(\''.$name.'\');'."\n";
  582. preg_match_all('~'.preg_quote($this->left_delimiter,'~').'(input|textarea)(\s+.*?)?'.preg_quote($this->right_delimiter,'~').'~',$block_content,$m,PREG_SET_ORDER);
  583. foreach ($m as $v)
  584. {
  585. $params = $this->_parse_params($v[2],TRUE);
  586. if (!isset($params['name'])) {continue;}
  587. foreach ($params as $k => $v) {$params[$k] = $this->_dequote($v);}
  588. $code .= '$form->addElement('.var_export($params['name'],TRUE).','.var_export($params,TRUE).');'."\n";
  589. }
  590. $code .= '} ?>';
  591. eval('?>'.$code);
  592. }
  593. else {return $this->_syntax_error('Form \''.$name.'\' is not recognized');}
  594. }
  595. $objform = Quicky_form::$forms[$name];
  596. $props = array('form');
  597. $a = $this->block_props;
  598. $this->push_block_props($props,$block_name,$name);
  599. $block_content = $this->_tag_token($block_content,$block_name);
  600. $this->block_props = $a;
  601. }
  602. else {$block_content = $this->_tag_token($block_content,$block_name);}
  603. $s = '';
  604. foreach ($block_params as $k => $v)
  605. {
  606. if (strpos($v,'$') !== FALSE) {$s .= ' '.$k.'="<?php echo htmlspecialchars('.$v.',ENT_QUOTES); ?>"';}
  607. else {$s .= ' '.$k.'="'.htmlspecialchars($this->_dequote($v,ENT_QUOTES)).'"';}
  608. }
  609. $return = $code.'<form'.$s.'>'.$block_content.'</form>';
  610. }
  611. elseif ($block_name == '_if')
  612. {
  613. if (trim($mixed[2]) === '') {return $this->_syntax_error('Empty condition.');}
  614. $return = $this->_fetch_expr($this->_expr_token($mixed[2],FALSE,TRUE))?$this->_tag_token($block_content,$block_name):'';
  615. }
  616. elseif ($block_name == '_foreach')
  617. {
  618. $block_params = $this->_parse_params($mixed[2]);
  619. if (!isset($block_params['from'])) {return $this->_syntax_error('Missing parameter \'from\' in foreach tag.');}
  620. if (!isset($block_params['item']) && !isset($block_params['value'])) {return $this->_syntax_error('Missing parameter \'item\' in foreach tag.');}
  621. if (!isset($block_params['item'])) {$block_params['item'] = $block_params['value'];}
  622. $val = $this->_fetch_expr($block_params['from']);
  623. if (!is_array($val) and !is_object($val)) {return $this->_syntax_error('Parameter \'from\' must be an array or object, '.gettype($val).' given');}
  624. $return = '';
  625. if (isset($block_params['key']))
  626. {
  627. foreach ($val as $this->_cpl_vars[$this->_dequote($block_params['key'])] => $this->_cpl_vars[$this->_dequote($block_params['item'])]) {$return .= $this->_tag_token($block_content,$block_name);}
  628. }
  629. else
  630. {
  631. foreach ($val as $this->_cpl_vars[$this->_dequote($block_params['item'])]) {$return .= $this->_tag_token($block_content,$block_name);}
  632. }
  633. }
  634. elseif ($block_name == 'function' or $block_name == 'helper')
  635. {
  636. if (!preg_match('~^\s*(.*?)\s*\((.*)\)\s*$~',$mixed[2],$g)) {return $this->_syntax_error('Parse error in Function header.');}
  637. if (trim($g[2]) === '') {return $this->_syntax_error('Missing expression in Function tag.');}
  638. $this->_tag_stacks[$this->_tag_stack_n]['type'] = 'function';
  639. $this->_tag_stacks[$this->_tag_stack_n]['name'] = $g[1];
  640. $args = explode(',',$g[2]);
  641. $args_a = array();
  642. foreach ($args as $v)
  643. {
  644. if (!preg_match('~^\$(\w+)$~',$v,$q)) {return $this->_syntax_error('Parse error in Function header.');}
  645. $args_names[] = $q[1];
  646. }
  647. $args_s = '';
  648. foreach ($args_names as $k => $v)
  649. {
  650. $args_s .= '$args[\''.$v.'\'],';
  651. }
  652. $args_s = rtrim($args_s,',');
  653. $return = '<?php'
  654. ."\n".'function quicky_function_'.$g[1].' ($args,$quicky)'
  655. ."\n".'{'
  656. ."\n".'$var = &$quicky->_tpl_vars;'
  657. ."\n".'$save_vars = array('.$args_s.');';
  658. foreach ($args as $k => $v)
  659. {
  660. $return .= "\n".'if (isset($args[\''.$args_names[$k].'\'])) {$var[\''.$args_names[$k].'\'] = $args[\''.$args_names[$k].'\'];}'.
  661. "\n".'elseif (isset($args['.$k.'])) {$var[\''.$args_names[$k].'\'] = $args['.$k.'];}';
  662. }
  663. $return .=
  664. "\n".'$config = &$quicky->_tpl_config;'
  665. ."\n".'$capture = &$quicky->_block_props[\'capture\'];'
  666. ."\n".'$foreach = &$quicky->_block_props[\'foreach\'];'
  667. ."\n".'$section = &$quicky->_block_props[\'section\'];'
  668. ."\n?>";
  669. $this->template_defined_functions[] = $g[1];
  670. $return .= $this->_tag_token($block_content,$block_name)
  671. ."\n".'<?php list('.$args_s.') = $save_vars;'
  672. ."\n".'} ?>';
  673. }
  674. elseif ($block_name == 'while')
  675. {
  676. $expr = $this->_expr_token($mixed[2]);
  677. if (trim($expr) === '') {return $this->_syntax_error('Missing expression in while tag.');}
  678. $return = '<?php'
  679. ."\n".'while ('.$expr.'): ?>'
  680. .$this->_tag_token($block_content,$block_name)
  681. .'<?php endwhile; ?>';
  682. }
  683. elseif ($block_name == 'switch')
  684. {
  685. $expr = $this->_expr_token($mixed[2]);
  686. if (trim($expr) === '') {return $this->_syntax_error('Missing expression in switch tag.');}
  687. $block = $this->_tag_token($block_content,$block_name);
  688. $block = ltrim($block);
  689. $return = '<?php'
  690. ."\n".'switch ('.$expr.'): ?>'
  691. .$block
  692. .'<?php endswitch; ?>';
  693. }
  694. elseif ($block_name == 'section')
  695. {
  696. $block_params = $this->_parse_params($mixed[2]);
  697. if (!isset($block_params['name'])) {return $this->_syntax_error('Missing parameter \'name\' in section tag.');}
  698. if (!isset($block_params['loop'])) {return $this->_syntax_error('Missing parameter \'loop\' in section tag.');}
  699. else {$block_params['loop'] = $this->_dequote($block_params['loop']);}
  700. if (!isset($block_params['start'])) {$block_params['start'] = '0';}
  701. else {$block_params['start'] = $this->_dequote($block_params['start']);}
  702. if (!isset($block_params['max'])) {$block_params['max'] = '-1';}
  703. else {$block_params['max'] = $this->_dequote($block_params['max']);}
  704. if (!isset($block_params['step'])) {$block_params['step'] = '1';}
  705. else {$block_params['step'] = $this->_dequote($block_params['step']);}
  706. $name = $this->_dequote($block_params['name']);
  707. $props = array('index','index_prev','index_next','iteration','first','last','rownum','loop','show','total');
  708. if (in_array($name,$props)) {return $this->_syntax_error('Disallowed value (\''.$block_params['name'].'\') of parameter \'name\' in section tag.');}
  709. $props[] = $name;
  710. $a = $this->block_props;
  711. $this->push_block_props($props,$block_name,$name);
  712. $block = $this->_tag_token($block_content,$block_name);
  713. $this->block_props = $a;
  714. $name = var_export($name,TRUE);
  715. $return = '<?php'
  716. ."\n".'$section['.$name.'] = array();'
  717. ."\n".'$section['.$name.'][\'s\'] = '.(isInteger($block_params['loop'])?$block_params['loop']:'isInteger('.$block_params['loop'].')?'.$block_params['loop'].':sizeof('.$block_params['loop'].')').';'
  718. ."\n".'$section['.$name.'][\'st\'] = '.(isInteger($block_params['start'])?$block_params['start']:'isInteger('.$block_params['start'].')?'.$block_params['start'].':sizeof('.$block_params['start'].')').';'
  719. ."\n".'$section['.$name.'][\'step\'] = '.(isInteger($block_params['step'])?$block_params['step']:'isInteger('.$block_params['step'].')?'.$block_params['step'].':sizeof('.$block_params['step'].')').';'
  720. ."\n".'if ($section['.$name.'][\'s\'] > 0):'
  721. .' for ($section['.$name.'][\'i\'] = 0; $section['.$name.'][\'i\'] < $section['.$name.'][\'s\']-$section['.$name.'][\'st\']'.($block_params['max'] != '-1'?' and $section['.$name.'][\'i\'] < '.$block_params['max']:'').'; ++$section['.$name.'][\'i\']): '
  722. .'?>'.$block;
  723. if (($k = array_search('sectionelse',$this->_tag_stacks[$this->_tag_stack_n])) !== FALSE)
  724. {
  725. $return .= '<?php endif; ?>';
  726. unset($this->_tag_stacks[$this->_tag_stack_n][$k]);
  727. }
  728. else {$return .= '<?php endfor; endif; ?>';}
  729. }
  730. elseif ($block_name == 'literal') {$return = $block_content;}
  731. elseif ($block_name == 'strip')
  732. {
  733. $block_content = preg_replace('~[\t ]*[\r\n]+[\t ]*~','',$block_content);
  734. $return = $this->_tag_token($block_content,$block_name);
  735. }
  736. elseif ($block_name == 'php')
  737. {
  738. if (!isset($this->prefs['allow_php_native'])) {return $this->_syntax_error('Disallowed PHP-tag');}
  739. $return = '<?php '.$block_content.' ?>';
  740. }
  741. elseif ($block_name == 'capture')
  742. {
  743. $block_params = $this->_parse_params($mixed[2]);
  744. $name = isset($block_params['name'])?trim($this->_dequote($block_params['name'])):'default';
  745. $assign = isset($block_params['assign'])?trim($this->_dequote($block_params['assign'])):'';
  746. if (is_int(array_search('ob',$block_params))) {$return = '<?php ob_start(); ?>'.$this->_tag_token($block_content,$block_name).'<?php $capture[\''.$name.'\'] = ob_get_contents(); ob_end_clean();'.($assign !== ''?' $var[\''.$assign.'\'] = $capture[\''.$name.'\'];':'').' ?>';}
  747. else
  748. {
  749. $old_write_out_to = $this->_write_out_to;
  750. $this->_write_out_to = '$capture[\''.$name.'\']';
  751. $block = $this->_tag_token($block_content,$block_name);
  752. $block = $this->_optimize($block);
  753. $return = '<?php $capture[\''.$name.'\'] = \'\';'."\n".$block
  754. .($assign !== ''?'$var[\''.$assign.'\'] = $capture[\''.$name.'\'];':'').' ?>';
  755. $this->_write_out_to = $old_write_out_to;
  756. }
  757. }
  758. elseif ($block_name == 'dynamic')
  759. {
  760. $return = '<?php /*'.UNIQUE_HASH_STATIC.'{dynamic}*/ ?>'.$this->_tag_token($block_content,$block_name).'<?php /*{/dynamic}'.UNIQUE_HASH_STATIC.'*/ ?>';
  761. }
  762. elseif (preg_match('~^\w+$~',$block_name) && (function_exists('quicky_block_'.$block_name) || file_exists($p = QUICKY_DIR.'plugins/block.'.$block_name.'.php')))
  763. {
  764. $block_params = $this->_parse_params($mixed[2]);
  765. require_once $p;
  766. $a = 'quicky_block_'.$block_name;
  767. return $a($block_params,$block_content,$this);
  768. }
  769. elseif ($block_name == 'select')
  770. {
  771. $block_params = $this->_parse_params($mixed[2]);
  772. $this->_tag_stacks[$this->_tag_stack_n]['type'] = $block_name;
  773. $this->_tag_stacks[$this->_tag_stack_n]['value'] = isset($block_params['value'])?$block_params['value']:'';
  774. unset($block_params['value']);
  775. if (isset($block_params['join']))
  776. {
  777. $fieldname = $this->_dequote($block_params['join']);
  778. if (!isset($this->block_props['form'])) {return $this->_syntax_error('Parameter \'join\' in tag select must be into a form.');}
  779. $form = Quicky_form::$forms[$this->block_props['form'][0]];
  780. if (!isset($form->elements->$fieldname)) {return $this->_syntax_error('There are no field \''.$fieldname.'\' in form \''.$form->name.'\'');}
  781. unset($block_params['join']);
  782. foreach ($form->elements->$fieldname as $k => $v)
  783. {
  784. if ($k == 'elements') {continue;}
  785. if (substr($k,0,1) != '_' and !isset($params[$k])) {$block_params[$k] = var_export($v,TRUE);}
  786. }
  787. foreach ($form->elements->$fieldname->elements as $k => $v)
  788. {
  789. $t = gettype($v);
  790. if ($t == 'string') {$block_content .= '{option text=\''.$this->escape_string($v).'\'}'."\n";}
  791. elseif ($t == 'array' or $t == 'object')
  792. {
  793. if ($t == 'array') {$v = (object) $v;}
  794. $type = isset($v->type)?$v->type:'option';
  795. unset($v->type);
  796. if ($type != 'option' and $type != 'optgroup') {return $this->_syntax_error('Unexcepted type of dropdown\'s child element: \''.$type.'\'');}
  797. $s = '';
  798. foreach ($v as $h => $b)
  799. {
  800. $s .= $h.'=\''.$this->escape_string($b).'\' ';
  801. }
  802. $block_content .= '{'.$type.' '.rtrim($s,' ').'}'."\n";
  803. }
  804. }
  805. }
  806. $s = '';
  807. foreach ($block_params as $k => $v)
  808. {
  809. if ($k == 'type') {continue;}
  810. if (strpos($v,'$') !== FALSE) {$s .= ' '.$k.'="<?php echo htmlspecialchars('.$v.',ENT_QUOTES); ?>"';}
  811. else {$s .= ' '.$k.'="'.htmlspecialchars($this->_dequote($v,ENT_QUOTES)).'"';}
  812. }
  813. $return = '<select'.$s.'>'.$this->_tag_token($block_content,$block_name).'</select>';
  814. }
  815. elseif ($block_name == 'begin')
  816. {
  817. $name = trim($mixed[2]);
  818. $this->_tag_stacks[$this->_tag_stack_n]['type'] = 'begin';
  819. $this->_tag_stacks[$this->_tag_stack_n]['name'] = $name;
  820. $fullpath = '/';
  821. $tk = 0;
  822. for ($i = sizeof($this->_tag_stacks)-1; $i >= 0; $i--)
  823. {
  824. if (isset($this->_tag_stacks[$i]['type']) && $this->_tag_stacks[$i]['type'] == 'begin') {$fullpath = '/'.$this->_tag_stacks[$i]['name'].$fullpath; ++$tk;}
  825. }
  826. $s_name = var_export($name,TRUE);
  827. $s_fullpath = var_export($fullpath,TRUE);
  828. $sf_name = 'quicky_context_'.$name;
  829. $old_write_out_to = $this->_write_out_to;
  830. $this->_write_out_to = '$return';
  831. $block = $this->_tag_token($block_content,$block_name);
  832. $block = $this->_optimize($block);
  833. $this->_write_out_to = $old_write_out_to;
  834. $return = '<?php'
  835. ."\n".'if (!function_exists(\''.$sf_name.'\')) {function '.$sf_name.' () {$var = &Quicky::$obj->_tpl_vars; $return = \'\';'
  836. ."\n".'if (isset(Quicky::$obj->_contexts_data['.$s_fullpath.']) and sizeof(Quicky::$obj->_contexts_data['.$s_fullpath.']) > 0) {'
  837. ."\n".'$old = $var;'
  838. ."\n".'foreach (Quicky::$obj->_contexts_data['.$s_fullpath.'] as $k => $v):'
  839. ."\n".'$var = array_merge($var,$v);'
  840. .$block
  841. .'endforeach; $var = $old;} return $return; }} '.($tk > 1?'$return .=':'echo').' '.$sf_name.'(); ?>';
  842. }
  843. else {return $this->_syntax_error('Unrecognized block-type \''.$block_name.'\'');}
  844. unset($this->_tag_stacks[$this->_tag_stack_n]);
  845. --$this->_tag_stack_n;
  846. return $return;
  847. }
  848. $blocks = array_values($this->blocks);
  849. for ($i = 0,$s = sizeof($blocks); $i < $s; $i++) {$blocks[$i] = preg_quote($blocks[$i],'~');}
  850. $blocks[] = 'foreach';
  851. $blocks[] = 'section';
  852. $blocks[] = 'for';
  853. $blocks[] = 'while';
  854. $blocks[] = 'switch';
  855. $blocks[] = 'literal';
  856. $blocks[] = 'capture';
  857. $blocks[] = 'php';
  858. $blocks[] = 'strip';
  859. $blocks[] = 'textformat';
  860. $blocks[] = 'dynamic';
  861. $blocks[] = 'select';
  862. $blocks[] = 'joincalculator';
  863. $blocks[] = 'function|helper';
  864. $blocks[] = 'form';
  865. $blocks[] = '_if|_foreach';
  866. $ldelim = preg_quote($this->left_delimiter,'~');
  867. $rdelim = preg_quote($this->right_delimiter,'~');
  868. $return = preg_replace_callback('~'
  869. .'\{\{?\s*(begin)(?:\s+(.*?))?\}\}?((?:(?R)|.)*?)\{\{?\s*(?:end(?:\s+\2)?)?\s*\}\}?'
  870. .'|\{\{(\\??(?:[^'.$rdelim.'\'"]*([\'"]).*?(?<!\\\\)\5)*.*?)\}\}'
  871. .'|'.$ldelim.'\s*('.implode('|',$blocks).')(\s(?:[^'.$rdelim.'\'"]*([\'"]).*?(?<!\\\\)\8)*.*?)?'.$rdelim.'((?:(?R)|.)*?)'.$ldelim.'/\s*\6?\s*'.$rdelim
  872. .'|'.$ldelim.'(\\??(?:[^'.$rdelim.'\'"]*([\'"]).*?(?<!\\\\)\11)*.*?)'.$rdelim
  873. .'~si',array($this,'_tag_token'),$mixed);
  874. return $return;
  875. }
  876. function _var_token($token)
  877. {
  878. preg_match_all($a = '~([\'"]).*?(?<!\\\\)\1|\(((?:(?R)|.)*?)\)|->((?:_?[\$#]?\w*(?:\(((?:(?R)|.)*?)\)|(\\[((?:(?R)|(?:[^\\]\'"]*([\'"]).*?(?<!\\\\)\4)*.*?))*?\\]|\.[\$#]?\w+#?|(?!a)a->\w*(?:\(((?:(?R)|.)*?)\))?)?)?)+)~',$token,$properties,PREG_SET_ORDER);
  879. $token = preg_replace_callback($a,create_function('$m','if (!isset($m[3])) {return $m[0];} return \'\';'),$token);
  880. $obj_appendix = '';
  881. for ($i = 0,$s = sizeof($properties); $i < $s; $i++)
  882. {
  883. if (isset($properties[$i][3]))
  884. {
  885. $plain = FALSE;
  886. preg_match('~^((?:_?[\$#])?\w+#?)(.*)$~',$properties[$i][3],$q);
  887. if (preg_match('~^_?[\$#]~',$q[1]))
  888. {
  889. if (substr($q[1],0,1) == '_') {$plain = TRUE; $q[1] = substr($q[1],1);}
  890. $q[1] = $this->_var_token($q[1]);
  891. if ($plain) {$q[1] = $this->_fetch_expr($q[1]);}
  892. }
  893. $obj_appendix .= '->'.$q[1];
  894. preg_match_all('~(\\[((?:(?R)|(?:[^\\]\'"]*([\'"]).*?(?<!\\\\)\3)*.*?))*?\\]|\.[\$#]?\w+#?)~',$q[2],$w,PREG_SET_ORDER);
  895. for ($j = 0,$n = sizeof($w); $j < $n; $j++)
  896. {
  897. if (substr($w[$j][1],0,1) == '.')
  898. {
  899. $expr = substr($w[$j][1],1);
  900. if (!isset($this->block_props[$expr]))
  901. {
  902. $expr = '"'.$expr.'"';
  903. $instring = TRUE;
  904. }
  905. else {$instring = FALSE;}
  906. }
  907. else {$expr = substr($w[$j][1],1,-1); $instring = FALSE;}
  908. $r = $this->_expr_token($expr,$instring);
  909. $obj_appendix .= '['.(preg_match('~^\w+$~',$r)?'\''.$r.'\'':$r).']';
  910. }
  911. if (isset($properties[$i][4]) && ($properties[$i][4] !== '' || !isset($properties[$i][5])))
  912. {
  913. $params = $this->_expr_token_parse_params($properties[$i][4]);
  914. $obj_appendix .= '('.implode(',',$params).')';
  915. }
  916. }
  917. }
  918. if (is_numeric($token)) {return $token;}
  919. if (substr($token,0,1) == '#' or substr($token,0,1) == '$' or (isset($this->block_props[$token]) and !$this->_no_magic))
  920. {
  921. $this->_no_magic = preg_match('~^\$(?:quicky|smarty)[\.\[]~i',$token);
  922. preg_match_all('~([\$#]?\w*#?)(\\[((?:(?R)|(?:[^\\]\'"]*([\'"]).*?(?<!\\\\)\4)*.*?))*?\\]|\.[\$#]?\w+#?|->\w*(?:\(((?:(?R)|.)*?)\))?)~',$token,$w,PREG_SET_ORDER);
  923. $appendix_set = array();
  924. for ($i = 0,$s = sizeof($w); $i < $s; $i++)
  925. {
  926. if ($w[$i][1] !== '') {$token = $w[$i][1];}
  927. if (substr($w[$i][2],0,1) == '.')
  928. {
  929. $expr = substr($w[$i][2],1);
  930. if (!isset($this->block_props[$expr]))
  931. {
  932. $expr = '"'.$expr.'"';
  933. $instring = TRUE;
  934. }
  935. else {$instring = FALSE;}
  936. }
  937. else {$expr = substr($w[$i][2],1,-1); $instring = FALSE;}
  938. $r = $this->_expr_token($expr,$instring);
  939. $appendix_set[] = preg_match('~^\w+$~',$r)?'\''.$r.'\'':$r;
  940. }
  941. $this->_no_magic = FALSE;
  942. }
  943. static $operators = array('or','xor','and','true','false','null');
  944. $mode = 0;
  945. $mode_special_var = FALSE;
  946. if (substr($token,0,1) == '\'' or substr($token,0,1) == '"')
  947. {
  948. if (substr($token,-1) != $token[0]) {return $this->_syntax_error('Bad string definition.');}
  949. if ($token[0] == '"') {return $this->_expr_token($token,TRUE);}
  950. return var_export($this->_dequote($token),TRUE);
  951. }
  952. elseif ($token == '$tplpath') {return '$path';}
  953. elseif ($token == '$tplpathdir') {return '$dir';}
  954. elseif ($token == '$rdelim') {return var_export($this->right_delimiter,TRUE);}
  955. elseif ($token == '$ldelim') {return var_export($this->left_delimiter,TRUE);}
  956. elseif ($token == '$SCRIPT_NAME') {return '$_SERVER[\'SCRIPT_NAME\']';}
  957. elseif ($token[0] == '$')
  958. {
  959. $token = substr($token,1);
  960. if (array_key_exists($token,$this->precompiled_vars)) {return var_export($this->precompiled_vars[$token],TRUE);}
  961. $type = 'var';
  962. if (strtolower($token) == 'quicky' || strtolower($token) == 'smarty')
  963. {
  964. $t = isset($appendix_set[0])?strtolower($this->_dequote($appendix_set[0])):'';
  965. $appendix_set = array_slice($appendix_set,1);
  966. $type = '';
  967. if ($t == 'rdelim') {return var_export($this->right_delimiter,TRUE);}
  968. elseif ($t == 'ldelim') {return var_export($this->left_delimiter,TRUE);}
  969. elseif ($t == 'request') {$type = '_REQUEST'; $mode = 1;}
  970. elseif ($t == 'tplscope') {$type = 'var'; $mode = 1;}
  971. elseif ($t == 'cfgscope') {$type = 'config'; $mode = 1;}
  972. elseif ($t == 'get') {$type = '_GET'; $mode = 1;}
  973. elseif ($t == 'post') {$type = '_POST'; $mode = 1;}
  974. elseif ($t == 'cookie' or $t == 'cookies') {$type = '_COOKIE'; $mode = 1;}
  975. elseif ($t == 'requeststring') {$type = '_REQUEST'; $mode = 2;}
  976. elseif ($t == 'getstring') {$type = '_GET'; $mode = 2;}
  977. elseif ($t == 'poststring') {$type = '_POST'; $mode = 2;}
  978. elseif ($t == 'cookiestring' or $t == 'cookiesstring') {$type = '_COOKIE'; $mode = 2;}
  979. elseif ($t == 'session') {$type = '_SESSION';}
  980. elseif ($t == 'server') {$type = '_SERVER';}
  981. elseif ($t == 'env') {$type = '_ENV';}
  982. elseif ($t == 'capture') {$type = 'capture';}
  983. elseif ($t == 'now') {return 'time()';}
  984. elseif ($t == 'const') {return 'constant('.(isset($appendix_set[0])?$appendix_set[0]:'').')';}
  985. elseif ($t == 'template') {return '$path';}
  986. elseif ($t == 'version') {return '$this->version';}
  987. elseif ($t == 'foreach' or $t == 'section')
  988. {
  989. $name = isset($appendix_set[0])?strtolower($this->_dequote($appendix_set[0])):'';
  990. $prop = isset($appendix_set[1])?strtolower($this->_dequote($appendix_set[1])):'';
  991. return $this->_get_expr_blockprop($name,$t,$prop);
  992. }
  993. else {return $this->_syntax_error('Unknown property \''.$t.'\' of $quicky');}
  994. $token = '';
  995. }
  996. }
  997. elseif (substr($token,0,1) == '#')
  998. {
  999. if (substr($token,-1) != '#') {return var_export($token,TRUE);}
  1000. $type = 'config'; $token = substr($token,1,-1);
  1001. }
  1002. elseif ($token == 'tplpath') {return var_export($this->template_from,TRUE);}
  1003. elseif ($token == 'tplpathdir') {$a = dirname($this->template_from); return var_export($a !== ''?$a:'.',TRUE);}
  1004. elseif ($token == 'rdelim') {return var_export($this->right_delimiter,TRUE);}
  1005. elseif ($token == 'ldelim') {return var_export($this->left_delimiter,TRUE);}
  1006. elseif (isset($this->block_props[$token]) and !$this->_no_magic)
  1007. {
  1008. $return = $this->_get_expr_blockprop($this->block_props[$token][0],$this->block_props[$token][1],$token);
  1009. $mode_special_var = TRUE;
  1010. }
  1011. elseif (isset($this->block_props[$token])) {return $token;}
  1012. elseif (in_array($token,$this->allowed_php_constants) || in_array(strtolower($token),$operators) || (defined($token) && preg_match('~^M_\w+$~',$token))) {return $token;}
  1013. elseif (preg_match('~^\w+$~',$token))
  1014. {
  1015. if ($this->_cast_undefined_token_to_strings) {return var_export($token,TRUE);}
  1016. return $this->_syntax_error('Unexpected constant \''.$token.'\'');
  1017. }
  1018. else {return $this->_syntax_error('Unrecognized token \''.$token.'\'');}
  1019. $appendix = '';
  1020. for ($i = 0,$s = sizeof($appendix_set); $i < $s; $i++) {$appendix .= '['.$appendix_set[$i].']';}
  1021. if ($mode_special_var) {return $return.$appendix.$obj_appendix;}
  1022. $return = '$'.$type.($token !== ''?'['.var_export($token,TRUE).']':'').$appendix.$obj_appendix;
  1023. if ($mode == 2) {$return = 'gpcvar_strnull('.$return.')';}
  1024. return $return;
  1025. }
  1026. function _expr_token_parse_params($expr)
  1027. { // This function without regular expressions just for fun
  1028. $params = array();
  1029. $cpos = 0;
  1030. $instring = FALSE;
  1031. $instring_delim = '';
  1032. $bnl = 0;
  1033. $size = strlen($expr);
  1034. $param = '';
  1035. while ($cpos <= $size)
  1036. {
  1037. if ($cpos == $size) {$params[] = $this->_expr_token($param); break;}
  1038. $char = $expr[$cpos];
  1039. if (!$instring)
  1040. {
  1041. if ($char == '"' or $char == '\'') {$instring = TRUE; $instring_delim = $char;}
  1042. elseif ($char == '(') {$bnl++;}
  1043. elseif ($char == ')') {$bnl--;}
  1044. }
  1045. else
  1046. {
  1047. if ($char == $instring_delim and $expr[$cpos-1] != '\\') {$instring = FALSE;}
  1048. }
  1049. if (!$instring and $bnl == 0 and $char == ',') {$params[] = $this->_expr_token($param); $param = '';}
  1050. else {$param .= $char;}
  1051. $cpos++;
  1052. }
  1053. return $params;
  1054. }
  1055. function _expr_token_callback($m)
  1056. {
  1057. if (isset($m[13]) and $m[13] !== '')
  1058. {
  1059. preg_match('~^(\s*)(.*)(\s*)$~',$m[13],$q);
  1060. $lspace = $q[1];
  1061. $operator = $q[2];
  1062. $rspace = $q[3];
  1063. $operator = trim(preg_replace('~\s+~',' ',strtolower($operator)));
  1064. if ($operator == 'eq' or $operator == 'is') {$code = '==';}
  1065. elseif ($operator == 'ne' || $operator == 'neq') {$code = '!=';}
  1066. elseif ($operator == 'gt') {$code = '>';}
  1067. elseif ($operator == 'lt') {$code = '<';}
  1068. elseif ($operator == 'ge' || $operator == 'gte') {$code = '>=';}
  1069. elseif ($operator == 'le' || $operator == 'lte') {$code = '<=';}
  1070. elseif ($operator == 'not') {$code = '!'; $rspace = '';}
  1071. elseif ($operator == 'mod') {$code = '%';}
  1072. elseif ($operator == 'not eq' or $operator == 'is not') {$code = '!=';}
  1073. else {return $this->_syntax_error('Unknown operator '.var_export($operator,TRUE));}
  1074. return $code;
  1075. }
  1076. elseif (isset($m[3]) and $m[3] !== '' || preg_match('~^(\w+)\s*\(~',$m[1]))
  1077. {
  1078. if (preg_match('~^(\w+)\s*\(~',$m[1],$q)) {$func = $q[1];}
  1079. else {$func = '';}
  1080. $expr = $m[3];
  1081. if (trim($func.$expr) == '') {return;}
  1082. if ($func != '')
  1083. {
  1084. $a = strtolower($func);
  1085. $b = $p = $c = FALSE;
  1086. foreach ($this->allowed_php_tokens as $i)
  1087. {
  1088. if (preg_match($e = '~^'.str_replace('\*','.*',preg_quote($i,'~')).'$~i',$a)) {$b = TRUE; break;}
  1089. }
  1090. if (!$b) {$c = in_array($a,$this->template_defined_functions);}
  1091. if (!$b and !$c)
  1092. {
  1093. $y = $this->_alt_tag && !in_array($a,get_class_methods('Quicky'));
  1094. }
  1095. if (preg_match('~^\w+$~',$a

Large files files are truncated, but you can click here to view the full file