PageRenderTime 61ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/quicky/classes/Quicky_compiler.class.php

https://bitbucket.org/seyar/startech.local
PHP | 1016 lines | 989 code | 15 blank | 12 comment | 205 complexity | f1c4db35d70f649aff913ef2eb289df2 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /**************************************************************************/
  3. /* Quicky: smart and fast templates
  4. /* ver. 0.5.0.0
  5. /* ===========================
  6. /*
  7. /* Copyright (c)oded 2007-2008 by WP
  8. /* http://quicky-tpl.net
  9. /*
  10. /* Quicky_compiler.class.php: Template compiler
  11. /**************************************************************************/
  12. class Quicky_compiler
  13. {
  14. public $pcre_trace = FALSE;
  15. public $precompiled_vars = array();
  16. public $prefilters = array();
  17. public $postfilters = array();
  18. public $compiler_name = 'Quicky';
  19. public $compiler_version = '0.5.0.0';
  20. public $load_plugins = array();
  21. public $seq = array();
  22. public $seq_id = 0;
  23. public $_alt_tag = FALSE;
  24. public $prefs = array();
  25. public $template_defined_functions = array();
  26. public $allowed_php_tokens = array('array','date','strtotime','isset','empty','is_empty','count', 'sizeof', 'shuffle',
  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. 'json_encode','lang_om_number','intval','floatval','strval','setcookie','in_array',
  50. 'long2ip','ip2long','defined','file_exists','basename','mb_substr','mb_strlen','getdate');
  51. public $_def_mode = NULL;
  52. public $_scope_override = NULL;
  53. public $allowed_php_constants = array();
  54. public $syntax_errors = array();
  55. public $template_from;
  56. public $blocks = array();
  57. public $left_delimiter = '{';
  58. public $right_delimiter = '}';
  59. public $magic_constants = array('tplpath','tplpathdir','ldelim','rdelim');
  60. public $block_props = array();
  61. public $_write_out_to = '';
  62. public $_halt = FALSE;
  63. public $_line = array();
  64. public $_line_count = array();
  65. public $_current_tag = array();
  66. public $_tag_stacks = array();
  67. public $_tag_stack_n = 0;
  68. public $_no_magic = FALSE;
  69. public $no_optimize = FALSE;
  70. public $_tmp = array();
  71. public $_cpl_vars = array();
  72. public $_cpl_config = array();
  73. public $_cplmode = FALSE;
  74. public $_no_auto_escape = FALSE;
  75. public $_shortcuts = array();
  76. public $_var_map = array();
  77. public function Quicky_compiler() {}
  78. static function escape_string($s)
  79. {
  80. static $escape = array(
  81. '\\' => '\\\\',
  82. '\'' => '\\\''
  83. );
  84. return strtr($s,$escape);
  85. }
  86. public function push_block_props($props,$blocktype,$name)
  87. {
  88. for ($i = 0; $i < sizeof($props); $i++) {$this->block_props[$props[$i]] = array($name,$blocktype);}
  89. return TRUE;
  90. }
  91. public function _resolve_var($name)
  92. {
  93. if (isset($this->_scope_override)) {$type = $this->_scope_override;}
  94. elseif (isset($this->_var_map[$name])) {$type = $this->_var_map[$name];}
  95. else {$type = ($this->parent->depart_scopes || $this->parent->local_depart_scopes)?'local':'global';}
  96. if ($type == 'local') {return 'local';}
  97. elseif ($type == 'global') {return 'var';}
  98. else {$this->_syntax_error('Unknown scope "'.$type.'" for variable "'.$name.'"');}
  99. }
  100. public function _syntax_error($msg)
  101. {
  102. $error = 'Quicky syntax error '.$msg.' in template '.$this->template_from.' on line '.$this->_line[$this->template_from];
  103. if ($this->_line_count[$this->template_from] > 0) {$error .= ' (starts at line '.($this->_line[$this->template_from]-$this->_line_count[$this->template_from]).')';}
  104. $error .= '<br />Tag: '.$this->_current_tag[$this->template_from];
  105. $this->syntax_errors[] = $error;
  106. }
  107. public function register_block($block)
  108. {
  109. if (!in_array($block,$this->blocks)) {$this->blocks[] = $block;}
  110. return TRUE;
  111. }
  112. public function unregister_block($block)
  113. {
  114. if ($k = array_search($block,$this->blocks)) {unset($this->blocks[$k]); return TRUE;}
  115. else {return FALSE;}
  116. }
  117. public function _block_lang_callback($m)
  118. {
  119. $name = $m[2];
  120. $tag = $m[3];
  121. preg_match_all('~\{(\w+)\}(.*?)(?=\{\w+\}|\z)~s',$tag,$matches,PREG_SET_ORDER);
  122. $variants = array();
  123. foreach ($matches as $m) {$variants[strtolower($m[1])] = trim($m[2]);}
  124. $reqlang = $this->parent->lang;
  125. if (isset($variants[$reqlang])) {return $variants[$reqlang];}
  126. return isset($variants['default'])?$variants['default']:'Warning! Can\'t find phrase '.($name !== ''?'('.htmlspecialchars($name).')':'').' for this language.';
  127. }
  128. public function _form_detect_field($m)
  129. {
  130. $tag = strtolower($m[1] !== ''?$m[1]:$m[3]);
  131. $params = $this->_parse_params($m[1] !== ''?$m[2]:$m[4],TRUE);
  132. if ($tag == 'option')
  133. {
  134. $params['text'] = $m[5];
  135. if (!isset($params['value'])) {$params['value'] = $params['text'];}
  136. }
  137. elseif ($tag == 'textarea')
  138. {
  139. $params['value'] = $m[5];
  140. }
  141. $p = '';
  142. if (isset($params['name']) and !isset($params['join'])) {$params['join'] = $params['name'];}
  143. foreach ($params as $k => $v) {$p .= $k.'=\''.$this->escape_string($this->_dequote($v)).'\' ';}
  144. $p = substr($p,0,-1);
  145. if ($tag == 'input' or $tag == 'textarea')
  146. {
  147. $return = $this->left_delimiter.$tag.' '.$p.$this->right_delimiter;
  148. }
  149. elseif ($tag == 'option')
  150. {
  151. $return = $this->left_delimiter.'option '.$p.$this->right_delimiter;
  152. }
  153. elseif ($tag == 'select')
  154. {
  155. $body = preg_replace_callback('~<(option)(\s+.*?)?>(.*?)</\3>~si',array($this,'_form_detect_field'),$m[2]);
  156. $return = $this->left_delimiter.$tag.' '.$p.$this->right_delimiter.$m[5].$this->left_delimiter.'/'.$tag.$this->right_delimiter;
  157. }
  158. return $return;
  159. }
  160. public function _form_detect($m)
  161. {
  162. $params = $this->_parse_params($m[1],TRUE);
  163. $form_name = '';
  164. $p = '';
  165. $params['auto_object'] = 1;
  166. foreach ($params as $k => $v)
  167. {
  168. if (strtolower($this->_dequote($k)) == 'name') {$form_name = $this->_dequote($v);}
  169. $p .= $k.'=\''.$this->escape_string($this->_dequote($v)).'\' ';
  170. }
  171. if (!$this->parent->_auto_detect_forms and !in_array($form_name,$this->parent->_detect_forms)) {return $m[0];}
  172. $p = substr($p,0,-1);
  173. $body = preg_replace_callback('~<(input)(\s+.*?)?\s*/?\s*>|<(textarea|select)(\s+.*?)?>(.*?)</\3>~si',array($this,'_form_detect_field'),$m[2]);
  174. $return = '{form '.$p.'}'.$body.'{/form}';
  175. return $return;
  176. }
  177. public function _write_comment($m)
  178. {
  179. if (!isset($m[2])) {return $m[0];}
  180. return $this->_write_seq(array($m[0],$m[2]));
  181. }
  182. public function _read_comment($m)
  183. {
  184. $this->_read_seq($m);
  185. return '';
  186. }
  187. public function _write_seq($m)
  188. {
  189. if (!isset($this->seq[$this->seq_id])) {$this->seq[$this->seq_id] = array();}
  190. $this->seq[$this->seq_id][] = $m[1];
  191. //$this->_line[$this->template_from] += substr_count($m[0],"\n");
  192. return '~'.$this->seq_hash.'_'.$this->seq_id.str_repeat("\n",substr_count($m[1],"\n")).'~';
  193. }
  194. public function _read_seq($reset = FALSE)
  195. {
  196. static $i = array();
  197. if ($reset === TRUE or !isset($i[$this->seq_id])) {$i[$this->seq_id] = 0; return;}
  198. $r = $this->seq[$this->seq_id][$i[$this->seq_id]++];
  199. return $r;
  200. }
  201. public function _read_sequences($source)
  202. {
  203. $this->seq_id = 'comment';
  204. $this->_read_seq(TRUE);
  205. $source = preg_replace_callback('~\~'.$this->seq_hash.'_'.$this->seq_id.'\s*\~~si',array($this,'_read_comment'),$source);
  206. return $source;
  207. }
  208. public function _literal_callback($m)
  209. {
  210. if (isset($m[2]) && ($m[2] !== ''))
  211. {
  212. return $this->left_delimiter.'rdelim'.$this->right_delimiter;
  213. }
  214. return $this->left_delimiter.'ldelim'.$this->right_delimiter;
  215. }
  216. public function _literal($m)
  217. {
  218. $ldelim = preg_quote($this->left_delimiter,'~');
  219. $rdelim = preg_quote($this->right_delimiter,'~');
  220. return preg_replace_callback('~('.$ldelim.')|('.$rdelim.')~',array($this,'_literal_callback'),$m[1]);
  221. }
  222. public function _compile_source_string($template,$from)
  223. {
  224. $this->parent->local_depart_scopes = FALSE;
  225. $old_load_plugins = $this->load_plugins;
  226. $this->load_plugins = array();
  227. $old_template_from = $this->template_from;
  228. $this->template_from = $from;
  229. $this->_line[$this->template_from] = 1;
  230. $this->_line_count[$this->template_from] = 0;
  231. //$template = str_replace("\r",'',$template);
  232. $template = preg_replace('~^/.*?/\r?\n~','',$template);
  233. $ldelim = preg_quote($this->left_delimiter,'~');
  234. $rdelim = preg_quote($this->right_delimiter,'~');
  235. $this->seq_hash = md5(microtime());
  236. $this->seq = array();
  237. $this->seq_id = 'comment';
  238. $template = preg_replace_callback('~([\'"]).*?\1|('.$ldelim.'\*.*?\*'.$rdelim.')~s',array($this,'_write_comment'),$template);
  239. $a = array_values($this->prefilters);
  240. for ($i = 0,$s = sizeof($a); $i < $s; $i++) {$template = call_user_func($a[$i],$template,$this);}
  241. $source = $template;
  242. if ($this->parent->lang !== '')
  243. {
  244. $source = preg_replace_callback('~'.$ldelim.'_\s+(.*?)'.$rdelim.'~',$this->parent->lang_callback,$source);
  245. $source = preg_replace_callback('~'.$ldelim.'e_\s+(.*?)'.$rdelim.'~i',$this->parent->lang_callback_e,$source);
  246. $source = preg_replace_callback('~'.$ldelim.'LANG(?:=([\'|"])?(.*?)\1)?'.$rdelim.'(.*?)'.$ldelim.'/LANG'.$rdelim.'~si',array($this,'_block_lang_callback'),$source);
  247. }
  248. if ($this->parent->_auto_detect_forms or sizeof($this->parent->_detect_forms) > 0)
  249. {
  250. $source = preg_replace_callback('~<form(\s+.*?)?>(.*?)</form>~si',array($this,'_form_detect'),$source);
  251. }
  252. if (!isset($this->prefs['allow_php_native']) or !$this->prefs['allow_php_native'])
  253. {
  254. $source = preg_replace('~<\?(?:php)?|\?>~i','<?php echo \'$0\'; ?>',$source);
  255. }
  256. $source = preg_replace_callback('~'.$ldelim.'literal'.$rdelim.'(.*?)'.$ldelim.'/literal'.$rdelim.'~si',array($this,'_literal'),$source);
  257. $cur_seq = $this->seq;
  258. $cur_hash = $this->seq_hash;
  259. $source = $this->_tag_token($source);
  260. $this->seq = $cur_seq;
  261. $this->seq_hash = $cur_hash;
  262. $source = $this->_read_sequences($source);
  263. if (!$this->no_optimize and FALSE)
  264. {
  265. $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);
  266. $source = preg_replace_callback('~^(.{1,20}?)(<\?php)~s',create_function('$m','return $m[2].\' echo \\\'\'.Quicky_compiler::escape_string($m[1]).\'\\\';'."\n".'\';'),$source);
  267. $source = preg_replace_callback('~(\?>)(.{1,20})$~s',create_function('$m','return \' echo \\\'\'.Quicky_compiler::escape_string($m[2]).\'\\\';'."\n".'\'.$m[1];'),$source);
  268. }
  269. $header = '<?php /* Quicky compiler version '.$this->compiler_version.', created on '.date('r').'
  270. compiled from '.$from.' */'."\n";
  271. for ($i = 0,$s = sizeof($this->load_plugins); $i < $s; $i++) {$header .= 'require_once '.var_export($this->load_plugins[$i],TRUE).';'."\n";}
  272. $header .= '$local = &$this->_local_vars['.var_export($from,TRUE).'];'."\n";
  273. $header .= '$var_buff = &$this->_tpl_vars_buff['.var_export($from,TRUE).'];'."\n";
  274. $header .= '$var_buff = array();'."\n";
  275. $header .= 'if ($local === NULL) {$local = array();}'."\n";
  276. $header .= 'else
  277. {
  278. foreach ($local as $k => $v)
  279. {
  280. $var_buff[$k] = isset($var[$k])?$var[$k]:NULL;
  281. $var[$k] = &$local[$k];
  282. }
  283. }
  284. ';
  285. $header .= '?>';
  286. $footer = '<?php foreach ($this->_tpl_vars_buff['.var_export($from,TRUE).'] as $k => $v) {unset($var[$k]); $var[$k] = $v;} '."\n"
  287. .' $this->_local_vars['.var_export($from,TRUE).'] = array(); ?>';
  288. if (sizeof($this->syntax_errors))
  289. {
  290. return implode("<br />\n",$this->syntax_errors);
  291. }
  292. $this->_halt = FALSE;
  293. $a = array_values($this->postfilters);
  294. for ($i = 0,$s = sizeof($a); $i < $s; $i++) {$source = call_user_func($a[$i],$source,$this);}
  295. $this->load_plugins = $old_load_plugins;
  296. $this->template_from = $old_template_from;
  297. $source = preg_replace('~^(<\?php.*?)\?><\?php~si','$1',$header.$source.$footer);
  298. return $source;
  299. }
  300. public function _compile_source($path,$from) {return $this->_compile_source_string(file_get_contents($path),$from);}
  301. public function string_or_expr($s)
  302. {
  303. if (ctype_digit(substr($s,0,1) == '-'?substr($s,1):$s)) {return $s;}
  304. if (preg_match('~^\w+$~',$s))
  305. {
  306. if (defined($s) or in_array(strtolower($s),$this->magic_constants) or isset($this->_block_props[strtolower($s)]))
  307. {
  308. return $s;
  309. }
  310. return '\''.$s.'\'';
  311. }
  312. return $s;
  313. }
  314. public function _parse_params($p,$plain = FALSE)
  315. {
  316. $params = array();
  317. preg_match_all('~(?:\w+\s*=|(([\'"]).*?(?<!\\\\)\2|\w*\s*\(((?:(?R)|.)*?)\)'
  318. .'|_?[\$#]\w+#?(?:\\[(?:(?R)|((?:[^\\]\'"]*(?:([\'"]).*?(?<!\\\\)\5)?)*))*?\\]|\.[\$#]?\w+#?|->\s*[\$#]?\w+(?:\(((?:(?R)|.)*?)\))?)*'
  319. .'|-?\d+|(?<=^|[\s\)\:\.=+\-<>])(?:\w+)(?=$|[\s\|\.\:\(=+\-<>])))'
  320. .'(?:\|@?\s*\w+(?:\:\s*(?:[^\:\|\'"\s]*(?:([\'"]).*?(?<!\\\\)\1[^\:\|\'"]*)*))*)*'
  321. .'|.+?~s',$p,$m,PREG_SET_ORDER);
  322. $lastkey = '';
  323. foreach ($m as $v)
  324. {
  325. $s = sizeof($v);
  326. if (($s == 1) || ($s == 2) || ($s == 3))
  327. {
  328. if (preg_match('~^\w+\s*=$~',$v[0])) {$lastkey = ltrim(rtrim($v[0]," =\t"));}
  329. elseif ($lastkey !== '') {if (!isset($params[$lastkey])) {$params[$lastkey] = '';} $params[$lastkey] .= $v[0];}
  330. else {}
  331. continue;
  332. }
  333. if (trim($v[0]) === '') {continue;}
  334. if ($lastkey === '') {$params[] = $v[0];}
  335. else {$params[$lastkey] = $v[0];}
  336. $lastkey = '';
  337. }
  338. if (!$plain)
  339. {
  340. foreach ($params as $k => $v)
  341. {
  342. $v = trim($v);
  343. $params[$k] = $this->_expr_token($this->string_or_expr($v));
  344. }
  345. }
  346. return $params;
  347. }
  348. public function _dequote($string)
  349. {
  350. $a = substr($string,0,1);
  351. $string = preg_replace('~^\s*([\'"])(.*)\1\s*$~','$2',$string);
  352. return preg_replace('~(?<!\\\\)\\\\'.preg_quote($a,'~').'~',$a,$string);
  353. }
  354. public function _get_expr_blockprop($name,$blocktype,$prop)
  355. {
  356. $blocktype = strtolower($blocktype);
  357. $prop = strtolower($prop);
  358. $a = '$'.$blocktype.'['.var_export($name,TRUE).']';
  359. if ($blocktype == 'foreach')
  360. {
  361. if ($prop == 'iteration' or $prop == 'i') {$prop = 'i';}
  362. elseif ($prop == 'total') {$prop = 's';}
  363. elseif ($prop == 'first') {return '('.$a.'[\'i\'] == 1)';}
  364. elseif ($prop == 'last') {return '('.$a.'[\'i\'] == '.$a.'[\'s\'])';}
  365. }
  366. elseif ($blocktype == 'section')
  367. {
  368. if ($prop == 'iteration' or $prop == 'rownum') {return '('.$a.'[\'i\']+1)';}
  369. elseif ($prop == 'index' or $prop == $name) {return 'Quicky::ind('.$a.')';}
  370. elseif ($prop == 'index_prev' or $prop == $name) {return 'Quicky::ind('.$a.',-1)';}
  371. elseif ($prop == 'index_next' or $prop == $name) {return 'Quicky::ind('.$a.',1)';}
  372. elseif ($prop == 'total') {$prop = 's';}
  373. elseif ($prop == 'first') {return '('.$a.'[\'i\'] == 0)';}
  374. elseif ($prop == 'last') {return '('.$a.'[\'i\']+1 == '.$a.'[\'s\'])';}
  375. }
  376. elseif ($blocktype == 'form')
  377. {
  378. if ($prop == 'form') {return 'Quicky_form::$forms['.var_export($name,TRUE).']';}
  379. }
  380. return $a.'['.var_export($prop,TRUE).']';
  381. }
  382. public function _optimize_callback($m)
  383. {
  384. $prefix = ' '.$this->_write_out_to !== ''?$this->_write_out_to.' .= ':'echo ';
  385. if (isset($m[1]) and $m[1] !== '') {$return = $prefix.var_export($m[1],TRUE).';';}
  386. elseif (isset($m[2]) and $m[2] !== '') {$return = $prefix.var_export($m[2],TRUE).';';}
  387. elseif (isset($m[3]) and $m[3] !== '') {$return = $prefix.var_export($m[3],TRUE).';';}
  388. else {$return = '';}
  389. return $return;
  390. }
  391. public function _optimize($block)
  392. {
  393. $block = preg_replace_callback((!preg_match('~<\?php|\?>~i',$block))?'~(.*)~s':'~\?>(.*?)<\?php|^(.*?)<\?php|\?>(.*?)$~si',array($this,'_optimize_callback'),$block);
  394. return $block;
  395. }
  396. public function _fetch_expr($expr)
  397. {
  398. $var = &$this->_cpl_vars;
  399. $config = &$this->_cpl_config;
  400. return eval('return '.$expr.';');
  401. }
  402. public function _varname($s)
  403. {
  404. if (preg_match('~^\w+$~',$s)) {$s = $this->_var_token('$'.$s);}
  405. elseif ((isset($this->prefs['interpret_varname_params']) && $this->prefs['interpret_varname_params']) || (substr($s,0,1) == '\'') || (substr($s,-1) == '\''))
  406. {
  407. $type = $this->_resolve_var($this->_dequote($s));
  408. $s = '$'.$type.'['.$s.']';
  409. }
  410. return $s;
  411. }
  412. public function _tag_token($mixed,$block_parent = '')
  413. {
  414. if (!isset($this->_tag_stacks[$this->_tag_stack_n])) {$this->_tag_stacks[$this->_tag_stack_n] = array();}
  415. if ($this->_halt && !(is_array($mixed) && isset($mixed[4]) && strtolower($mixed[4]) == 'resumecompiler'))
  416. {
  417. return is_array($mixed)?$mixed[0]:$mixed;
  418. }
  419. if (is_array($mixed))
  420. {
  421. if ((sizeof($mixed) == 1) && (($mixed[0] === "\r\n") || $mixed[0] === "\n"))
  422. {
  423. ++$this->_line[$this->template_from];
  424. return $mixed[0];
  425. }
  426. else
  427. {
  428. if (isset($mixed[6]) && ($mixed[6] !== '')) {$heap = $mixed[7];}
  429. else {$heap = $mixed[0];}
  430. $this->_line_count[$this->template_from] = substr_count($heap,"\n");
  431. if ($this->_tag_stack_n == 0) {$this->_line[$this->template_from] += $this->_line_count[$this->template_from];}
  432. $this->_current_tag[$this->template_from] = $mixed[0];
  433. }
  434. if ((isset($mixed[6]) && $mixed[6] !== '') || (isset($mixed[10]) && $mixed[10] !== ''))
  435. {
  436. $a = array(
  437. 0 => $mixed[0],
  438. 1 => $mixed[6]
  439. );
  440. if (isset($mixed[7])) {$a[2] = $mixed[7];}
  441. if (isset($mixed[9])) {$a[3] = $mixed[9];}
  442. if (isset($mixed[10])) {$a[4] = $mixed[10];}
  443. $mixed = $a;
  444. $this->_alt_tag = FALSE;
  445. }
  446. else {$this->_alt_tag = TRUE;}
  447. if (isset($mixed[4]) && $mixed[4] !== '')
  448. {
  449. $this->_no_auto_escape = FALSE;
  450. preg_match('~^\s*(\S+)(.*)$~s',$mixed[4],$m);
  451. if (!isset($m[0])) {$m[0] = '';}
  452. if (!isset($m[1])) {$m[1] = '';}
  453. $tag = strtolower($m[1]);
  454. if (preg_match('~^#(\w+)$~',$tag,$sm))
  455. {
  456. $name = $sm[1];
  457. $params = $m[2];
  458. return isset($this->_shortcuts[$name])?$this->_shortcuts[$name]:'';
  459. }
  460. elseif (preg_match('~^(/?)(\w+)$~',$tag,$tm) && ($p = $this->parent->fetch_plugin('compiler.'.($tag = $tm[2]))))
  461. {
  462. require_once $p;
  463. $params = $m[2];
  464. $close = $tm[1] !== '';
  465. $a = 'quicky_compiler_'.$tag;
  466. if ($close) {$return = $a($params,$this,TRUE);}
  467. else {$return = $a($params,$this);}
  468. return $return;
  469. }
  470. elseif (preg_match('~^\w+$~',$tag) && (isset($this->parent->reg_func[$tag])))
  471. {
  472. $params = $this->_parse_params($m[2]);
  473. $key_params = array();
  474. foreach ($params as $k => $v) {$key_params[] = var_export($k,TRUE).' => '.$v;}
  475. $t = $this->parent->reg_func[$tag];
  476. $pstr = 'array('.implode(',',$key_params).'),'.($this->_cplmode?'$this->parent':'$this').',TRUE';
  477. if (is_array($t) || is_object($t)) {$t = 'call_user_func('.($this->_cplmode?'$this->parent->reg_func['.var_export($tag,TRUE).']':'$this->reg_func['.var_export($tag,TRUE).']').','.$pstr.')';}
  478. else {$t = $t.'('.$pstr.')';}
  479. return '<?php '.($this->_write_out_to !== ''?$this->_write_out_to.' .=':'echo').' '.$t.';'."\n".'?>';
  480. }
  481. elseif (preg_match('~^\w+$~',$tag) && (($c = in_array($tag,$this->template_defined_functions)) || ($p = $this->parent->fetch_plugin('function.'.$tag))))
  482. {
  483. $params = $this->_parse_params($m[2]);
  484. $key_params = array();
  485. foreach ($params as $k => $v) {$key_params[] = var_export($k,TRUE).' => '.$v;}
  486. if (!in_array($p,$this->load_plugins) and !$c) {$this->load_plugins[] = $p;}
  487. return '<?php '.(($this->_cplmode and !$c)?'require_once '.var_export($p,TRUE).'; ':'').($this->_write_out_to !== ''?$this->_write_out_to.' .=':'echo').' quicky_function_'.$tag.'(array('.implode(',',$key_params).'),'.($this->_cplmode?'$this->parent':'$this').',TRUE);'."\n".'?>';
  488. }
  489. elseif (preg_match('~^'.preg_quote($this->left_delimiter,'~').'\\*.*\\*'.preg_quote($this->right_delimiter,'~').'$~s',$mixed[0])) {return '';}
  490. else
  491. {
  492. if ($this->_alt_tag and preg_match('~^\w+$~',trim($m[0])))
  493. {
  494. $m[0] = '$'.trim($m[0]);
  495. }
  496. $outoff = FALSE;
  497. $plain = FALSE;
  498. if (substr($m[0],0,1) == '_')
  499. {
  500. $m[0] = substr($m[0],1);
  501. if (substr($m[0],0,1) == '_') {$m[0] = substr($m[0],1);}
  502. if (substr($m[0],0,1) == '?') {$m[0] = substr($m[0],1); $outoff = TRUE;}
  503. $e = $this->_fetch_expr($this->_expr_token($m[0],FALSE,TRUE,TRUE));
  504. $plain = TRUE;
  505. }
  506. else
  507. {
  508. if (substr($m[0],0,1) == '?')
  509. {
  510. $e = $this->_expr_token(substr($m[0],1),FALSE,TRUE);
  511. $outoff = TRUE;
  512. }
  513. else {$e = $this->_expr_token($m[0],FALSE,TRUE);}
  514. }
  515. if ($plain) {return $e;}
  516. if ($e === '' or $e === '\'\'') {return '';}
  517. $auto_escape = isset($this->prefs['auto_escape']) && $this->prefs['auto_escape'] && (!$this->_no_auto_escape) && (!$outoff);
  518. $line = $this->parent->debug_mode?'$line = '.$this->_line[$this->template_from].'; ':'';
  519. return '<?php '.$line.($outoff?'':($this->_write_out_to !== ''?$this->_write_out_to.' .=':'echo').' ').($auto_escape?'htmlspecialchars(':'').$e.($auto_escape?')':'').'; ?>';
  520. }
  521. return;
  522. }
  523. ++$this->_tag_stack_n;
  524. $block_name = strtolower($mixed[1]);
  525. $block_content = $mixed[3];
  526. $p = FALSE;
  527. if (preg_match('~^[\w+\-_]+$~',$block_name) && ((function_exists('quicky_block_'.$block_name) || ($p = $this->parent->fetch_plugin('block.'.$block_name)))))
  528. {
  529. $block_params = $mixed[2];
  530. if ($p) {require_once $p;}
  531. $a = 'quicky_block_'.$block_name;
  532. $return = $a($block_params,$block_content,$this);
  533. }
  534. else {$return = $this->_syntax_error('Unrecognized block-type \''.$block_name.'\'');}
  535. unset($this->_tag_stacks[$this->_tag_stack_n]);
  536. --$this->_tag_stack_n;
  537. return $return;
  538. }
  539. $blocks = array_values($this->blocks + $this->parent->_blocks);
  540. for ($i = 0,$s = sizeof($blocks); $i < $s; $i++) {$blocks[$i] = preg_quote($blocks[$i],'~');}
  541. $blocks[] = 'if';
  542. $blocks[] = 'foreach';
  543. $blocks[] = 'section';
  544. $blocks[] = 'for';
  545. $blocks[] = 'while';
  546. $blocks[] = 'switch';
  547. $blocks[] = 'literal';
  548. $blocks[] = 'capture';
  549. $blocks[] = 'php';
  550. $blocks[] = 'strip';
  551. $blocks[] = 'textformat';
  552. $blocks[] = 'dynamic';
  553. $blocks[] = 'select';
  554. $blocks[] = 'joincalculator';
  555. $blocks[] = 'function|helper';
  556. $blocks[] = 'form';
  557. $blocks[] = '_if|_foreach|_for';
  558. $blocks[] = 'shortcut|block';
  559. $blocks[] = 'optgroup';
  560. $blocks[] = 'blockelement';
  561. $ldelim = preg_quote($this->left_delimiter,'~');
  562. $rdelim = preg_quote($this->right_delimiter,'~');
  563. $return = $this->preg_replace_callback('~'
  564. .'\{\{?\s*(begin)(?:\s+(.*?))?\}\}?((?:(?R)|.)*?)\{\{?\s*(?:end(?:\s+\2)?)?\s*\}\}?'
  565. .'|\{\{(\\??(?:[^'.$rdelim.'\'"]*([\'"]).*?(?<!\\\\)\5)*.*?)\}\}'
  566. .'|'.$ldelim.'\s*('.implode('|',$blocks).')(\s(?:[^'.$rdelim.'\'"]*([\'"]).*?(?<!\\\\)\8)*.*?)?'.$rdelim.'((?:(?R)|.)*?)'.$ldelim.'/\s*\6?\s*'.$rdelim
  567. .'|'.$ldelim.'(\\??(?:[^'.$rdelim.'\'"]*([\'"]).*?(?<!\\\\)\11)*.*?)'.$rdelim
  568. .'|\r?\n'
  569. .'~si',array($this,'_tag_token'),$mixed);
  570. return $return;
  571. }
  572. public function _pcre_trace($regexp,$subject)
  573. {
  574. if ($this->pcre_trace)
  575. {
  576. $fp = fopen(QUICKY_DIR.'pcre-trace.php.txt','w');
  577. fwrite($fp,'<?php preg_replace('.var_export($regexp,TRUE).',\'\','.var_export($subject,TRUE)."); ?>");
  578. fclose($fp);
  579. }
  580. }
  581. public function preg_replace_callback($e,$c,$s)
  582. {
  583. $this->_pcre_trace($e,$s);
  584. return preg_replace_callback($e,$c,$s);
  585. }
  586. public function _var_token($token)
  587. {
  588. preg_match_all($a = '~([\'"]).*?(?<!\\\\)\1|\(((?:(?R)|.)*?)\)|->((?:_?[\$#]?\w*(?:\(((?:(?R)|.)*?)\)|(\\[((?:(?R)|(?:[^\\]\'"]*([\'"]).*?(?<!\\\\)\4)*.*?))*?\\]|\.[\$#]?\w+#?|(?!a)a->\w*(?:\(((?:(?R)|.)*?)\))?)?)?)+)~',$token,$properties,PREG_SET_ORDER);
  589. $token = preg_replace_callback($a,create_function('$m','if (!isset($m[3])) {return $m[0];} return \'\';'),$token);
  590. $obj_appendix = '';
  591. $type_c = FALSE;
  592. for ($i = 0,$s = sizeof($properties); $i < $s; $i++)
  593. {
  594. if (isset($properties[$i][3]))
  595. {
  596. $plain = FALSE;
  597. preg_match('~^((?:_?[\$#])?\w+#?)(.*)$~',$properties[$i][3],$q);
  598. if (preg_match('~^_?[\$#]~',$q[1]))
  599. {
  600. if (substr($q[1],0,1) == '_') {$plain = TRUE; $q[1] = substr($q[1],1);}
  601. $q[1] = $this->_var_token($q[1]);
  602. if ($plain) {$q[1] = $this->_fetch_expr($q[1],FALSE,FALSE,TRUE);}
  603. }
  604. $obj_appendix .= '->'.$q[1];
  605. if (substr($q[2],0,1) == '(') {$w = array();}
  606. else {preg_match_all('~(\\[((?:(?R)|(?:[^\\]\'"]*([\'"]).*?(?<!\\\\)\3)*.*?))*?\\]|\.[\$#]?\w+#?)~',$q[2],$w,PREG_SET_ORDER);}
  607. for ($j = 0,$n = sizeof($w); $j < $n; $j++)
  608. {
  609. if (substr($w[$j][1],0,1) == '.')
  610. {
  611. $expr = substr($w[$j][1],1);
  612. if (!isset($this->block_props[$expr]))
  613. {
  614. $expr = '"'.$expr.'"';
  615. $instring = TRUE;
  616. }
  617. else {$instring = FALSE;}
  618. }
  619. else {$expr = substr($w[$j][1],1,-1); $instring = FALSE;}
  620. $r = $this->_expr_token($expr,$instring);
  621. $obj_appendix .= '['.(preg_match('~^\w+$~',$r)?'\''.$r.'\'':$r).']';
  622. }
  623. if (isset($properties[$i][4]) && ($properties[$i][4] !== '' || !isset($properties[$i][5])))
  624. {
  625. $params = $this->_expr_token_parse_params($properties[$i][4]);
  626. $obj_appendix .= '('.implode(',',$params).')';
  627. }
  628. }
  629. }
  630. if (is_numeric($token)) {return $token;}
  631. if (substr($token,0,1) == '#' or substr($token,0,1) == '$' or (isset($this->block_props[$token]) and !$this->_no_magic))
  632. {
  633. $this->_no_magic = preg_match('~^\$(?:quicky|smarty)[\.\[]~i',$token);
  634. preg_match_all('~([\$#]?\w*#?)(\\[((?:(?R)|(?:[^\\]\'"]*([\'"]).*?(?<!\\\\)\4)*.*?))*?\\]|\.[\$#]?\w+#?|->\w*(?:\(((?:(?R)|.)*?)\))?)~',$token,$w,PREG_SET_ORDER);
  635. $appendix_set = array();
  636. for ($i = 0,$s = sizeof($w); $i < $s; $i++)
  637. {
  638. if ($w[$i][1] !== '') {$token = $w[$i][1];}
  639. if (substr($w[$i][2],0,1) == '.')
  640. {
  641. $expr = substr($w[$i][2],1);
  642. if (!isset($this->block_props[$expr]))
  643. {
  644. $expr = '"'.$expr.'"';
  645. $instring = TRUE;
  646. }
  647. else {$instring = FALSE;}
  648. }
  649. else {$expr = substr($w[$i][2],1,-1); $instring = FALSE;}
  650. $r = $this->_expr_token($expr,$instring);
  651. $appendix_set[] = preg_match('~^\w+$~',$r)?'\''.$r.'\'':$r;
  652. }
  653. $this->_no_magic = FALSE;
  654. }
  655. static $operators = array('or','xor','and','true','false','null');
  656. $mode = 0;
  657. $mode_special_var = FALSE;
  658. if (substr($token,0,1) == '\'' or substr($token,0,1) == '"')
  659. {
  660. if (substr($token,-1) != $token[0]) {return $this->_syntax_error('Bad string definition.');}
  661. if ($token[0] == '"') {return $this->_expr_token($token,TRUE);}
  662. return var_export($this->_dequote($token),TRUE);
  663. }
  664. elseif ($token == '$tplpath') {return '$path';}
  665. elseif ($token == '$tplpathdir') {return '$dir';}
  666. elseif ($token == '$rdelim') {return var_export($this->right_delimiter,TRUE);}
  667. elseif ($token == '$ldelim') {return var_export($this->left_delimiter,TRUE);}
  668. elseif ($token == '$SCRIPT_NAME') {return '$_SERVER[\'SCRIPT_NAME\']';}
  669. elseif ($token[0] == '$')
  670. {
  671. $token = substr($token,1);
  672. if (array_key_exists($token,$this->precompiled_vars)) {return var_export($this->precompiled_vars[$token],TRUE);}
  673. if (isset($this->_def_mode)) {$this->_var_map[$token] = $this->_def_mode;}
  674. $type = $this->_resolve_var($token);
  675. if (strtolower($token) == 'quicky' || strtolower($token) == 'smarty')
  676. {
  677. $t = isset($appendix_set[0])?strtolower($this->_dequote($appendix_set[0])):'';
  678. $appendix_set = array_slice($appendix_set,1);
  679. $type = '';
  680. if ($t == 'rdelim') {return var_export($this->right_delimiter,TRUE);}
  681. elseif ($t == 'ldelim') {return var_export($this->left_delimiter,TRUE);}
  682. elseif ($t == 'request') {$type = '_REQUEST'; $mode = 1;}
  683. elseif ($t == 'tplscope') {$type = 'var'; $mode = 1;}
  684. elseif ($t == 'cfgscope') {$type = 'config'; $mode = 1;}
  685. elseif ($t == 'get') {$type = '_GET'; $mode = 1;}
  686. elseif ($t == 'post') {$type = '_POST'; $mode = 1;}
  687. elseif ($t == 'cookie' or $t == 'cookies') {$type = '_COOKIE'; $mode = 1;}
  688. elseif ($t == 'requeststring') {$type = '_REQUEST'; $mode = 2;}
  689. elseif ($t == 'getstring') {$type = '_GET'; $mode = 2;}
  690. elseif ($t == 'poststring') {$type = '_POST'; $mode = 2;}
  691. elseif ($t == 'cookiestring' or $t == 'cookiesstring') {$type = '_COOKIE'; $mode = 2;}
  692. elseif ($t == 'session') {$type = '_SESSION';}
  693. elseif ($t == 'session_name') {return 'session_name()';}
  694. elseif ($t == 'session_id') {return 'session_id()';}
  695. elseif ($t == 'server') {$type = '_SERVER';}
  696. elseif ($t == 'env') {$type = '_ENV';}
  697. elseif ($t == 'capture') {$type = 'capture';}
  698. elseif ($t == 'now') {return 'time()';}
  699. elseif ($t == 'const') {return 'constant('.(isset($appendix_set[0])?$appendix_set[0]:'').')';}
  700. elseif ($t == 'compiler_prefs') {return $this->parent->_fetch_expr('$this->compiler_prefs['.(isset($appendix_set[0])?$appendix_set[0]:'\'\'').']');}
  701. elseif ($t == 'form') {$type = 'Quicky_form::$forms'; $mode = 1; $type_c = TRUE;}
  702. elseif ($t == 'template') {return '$path';}
  703. elseif ($t == 'version') {return '$this->version';}
  704. elseif ($t == 'foreach' or $t == 'section')
  705. {
  706. $name = isset($appendix_set[0])?strtolower($this->_dequote($appendix_set[0])):'';
  707. $prop = isset($appendix_set[1])?strtolower($this->_dequote($appendix_set[1])):'';
  708. return $this->_get_expr_blockprop($name,$t,$prop);
  709. }
  710. else {return $this->_syntax_error('Unknown property \''.$t.'\' of $quicky');}
  711. $token = '';
  712. }
  713. }
  714. elseif (substr($token,0,1) == '#')
  715. {
  716. if (substr($token,-1) != '#') {return var_export($token,TRUE);}
  717. $type = 'config'; $token = substr($token,1,-1);
  718. }
  719. elseif ($token == 'tplpath') {return var_export($this->template_from,TRUE);}
  720. elseif ($token == 'tplpathdir') {$a = dirname($this->template_from); return var_export($a !== ''?$a:'.',TRUE);}
  721. elseif ($token == 'rdelim') {return var_export($this->right_delimiter,TRUE);}
  722. elseif ($token == 'ldelim') {return var_export($this->left_delimiter,TRUE);}
  723. elseif (isset($this->block_props[$token]) and !$this->_no_magic)
  724. {
  725. $return = $this->_get_expr_blockprop($this->block_props[$token][0],$this->block_props[$token][1],$token);
  726. $mode_special_var = TRUE;
  727. }
  728. elseif (isset($this->block_props[$token])) {return $token;}
  729. elseif (in_array($token,$this->allowed_php_constants) || in_array(strtolower($token),$operators) || (defined($token) && preg_match('~^M_\w+$~',$token))) {return $token;}
  730. elseif (preg_match('~^\w+$~',$token))
  731. {
  732. if (isset($this->prefs['cast_undefined_token_to_strings']) && $this->prefs['cast_undefined_token_to_strings']) {return var_export($token,TRUE);}
  733. return $this->_syntax_error('Unexpected constant "'.$token.'"');
  734. }
  735. else {return $this->_syntax_error('Unrecognized token \''.$token.'\'');}
  736. $appendix = '';
  737. for ($i = 0,$s = sizeof($appendix_set); $i < $s; $i++) {$appendix .= '['.$appendix_set[$i].']';}
  738. if ($mode_special_var) {return $return.$appendix.$obj_appendix;}
  739. $return = ((!$type_c)?'$':'').$type.($token !== ''?'['.var_export($token,TRUE).']':'').$appendix.$obj_appendix;
  740. if ($mode == 2) {$return = 'gpcvar_strnull('.$return.')';}
  741. return $return;
  742. }
  743. public function _expr_token_parse_params($expr)
  744. { // This function without regular expressions just for fun
  745. $params = array();
  746. $cpos = 0;
  747. $instring = FALSE;
  748. $instring_delim = '';
  749. $bnl = 0;
  750. $size = strlen($expr);
  751. $param = '';
  752. while ($cpos <= $size)
  753. {
  754. if ($cpos == $size) {$params[] = $this->_expr_token($param); break;}
  755. $char = $expr[$cpos];
  756. if (!$instring)
  757. {
  758. if ($char == '"' or $char == '\'') {$instring = TRUE; $instring_delim = $char;}
  759. elseif ($char == '(') {$bnl++;}
  760. elseif ($char == ')') {$bnl--;}
  761. }
  762. else
  763. {
  764. if ($char == $instring_delim and $expr[$cpos-1] != '\\') {$instring = FALSE;}
  765. }
  766. if (!$instring and $bnl == 0 and $char == ',') {$params[] = $this->_expr_token($param); $param = '';}
  767. else {$param .= $char;}
  768. $cpos++;
  769. }
  770. return $params;
  771. }
  772. public function _expr_token_callback($m)
  773. {
  774. if (isset($m[13]) and $m[13] !== '')
  775. {
  776. preg_match('~^(\s*)(.*)(\s*)$~',$m[13],$q);
  777. $lspace = $q[1];
  778. $operator = $q[2];
  779. $rspace = $q[3];
  780. $operator = trim(preg_replace('~\s+~',' ',strtolower($operator)));
  781. if ($operator == 'eq' or $operator == 'is') {$code = '==';}
  782. elseif ($operator == 'ne' || $operator == 'neq') {$code = '!=';}
  783. elseif ($operator == 'gt') {$code = '>';}
  784. elseif ($operator == 'lt') {$code = '<';}
  785. elseif ($operator == 'ge' || $operator == 'gte') {$code = '>=';}
  786. elseif ($operator == 'le' || $operator == 'lte') {$code = '<=';}
  787. elseif ($operator == 'not') {$code = '!'; $rspace = '';}
  788. elseif ($operator == 'mod') {$code = '%';}
  789. elseif ($operator == 'not eq' or $operator == 'is not') {$code = '!=';}
  790. else {return $this->_syntax_error('Unknown operator '.var_export($operator,TRUE));}
  791. return $code;
  792. }
  793. elseif (isset($m[3]) and $m[3] !== '' || preg_match('~^(\w+)\s*\(~',$m[1]))
  794. {
  795. if (preg_match('~^(\w+)\s*\(~',$m[1],$q)) {$func = $q[1];}
  796. else {$func = '';}
  797. $expr = $m[3];
  798. if (trim($func.$expr) == '') {return;}
  799. if ($func != '')
  800. {
  801. $tag = $a = strtolower($func);
  802. if (preg_match('~^\w+$~',$tag) && (isset($this->parent->reg_func[$tag])))
  803. {
  804. $params = $this->_expr_token_parse_params($expr);
  805. $t = $this->parent->reg_func[$tag];
  806. $pstr = implode(',',$params);
  807. if (is_array($t) || is_object($t)) {$t = 'call_user_func('.($this->_cplmode?'$this->parent->reg_func['.var_export($tag,TRUE).']':'$this->reg_func['.var_export($tag,TRUE).']').($pstr !== ''?',':'').$pstr.')';}
  808. else {$t = $t.'('.$pstr.')';}
  809. return $t;
  810. }
  811. $b = $p = $c = FALSE;
  812. foreach ($this->allowed_php_tokens as $i)
  813. {
  814. if (preg_match($e = '~^'.str_replace('\*','.*',preg_quote($i,'~')).'$~i',$a)) {$b = TRUE; break;}
  815. }
  816. if (!$b) {$c = in_array($a,$this->template_defined_functions) || function_exists('quicky_function_'.$a);}
  817. if (!$b and !$c)
  818. {
  819. $y = $this->_alt_tag && !in_array($a,get_class_methods('Quicky'));
  820. }
  821. if (preg_match('~^\w+$~',$a) && ($b || $c || $y || ($p = $this->parent->fetch_plugin('function.'.$a))))
  822. {
  823. $params = $this->_expr_token_parse_params($expr);
  824. if ($p || $c)
  825. {
  826. if ($p !== FALSE and !in_array($p,$this->load_plugins)) {$this->load_plugins[] = $p;}
  827. $return = '';
  828. if ($p && (!$c)) {$return .= '((require_once('.var_export($p,TRUE).'))?';}
  829. $return .= 'quicky_function_'.$a.'(array('.implode(',',$params).'),'.($this->_cplmode?'$this->parent':'$this').',TRUE)';
  830. if ($p && (!$c)) {$return .= ':NULL)';}
  831. }
  832. elseif ($b)
  833. {
  834. if ($a == 'count') {$a = 'sizeof';}
  835. $return = $a.'('.implode(',',$params).')';
  836. }
  837. elseif ($y)
  838. {
  839. $tk = FALSE;
  840. $ta = array('begin','function');
  841. for ($i = sizeof($this->_tag_stacks)-1; $i >= 0; $i--)
  842. {
  843. if (isset($this->_tag_stacks[$i]['type']) && in_array($this->_tag_stacks[$i]['type'],$ta)) {$tk = TRUE; break;}
  844. }
  845. if ($tk) {$prefix = 'Quicky::$obj->';}
  846. else {$prefix = '$this->';}
  847. return $prefix.$a.'('.implode(',',$params).')';
  848. }
  849. else {return $this->_syntax_error('Function \''.$func.'\' not available');}
  850. }
  851. else {return $this->_syntax_error('Function \''.$func.'\' not available');}
  852. }
  853. else {$return = '('.$this->_expr_token($expr).')';}
  854. }
  855. elseif (isset($m[1]) and $m[1] !== '')
  856. {
  857. $return = $this->_var_token($m[1]);
  858. }
  859. else {$return = '';}
  860. if (isset($m[7]) and $m[7] !== '')
  861. {
  862. preg_match('~^(\s*)(.*)(\s*)$~',$m[7],$q);
  863. $lspace = $q[1];
  864. $operator = $q[2];
  865. $rspace = $q[3];
  866. $operator = trim(preg_replace('~\s+~',' ',strtolower($operator)));
  867. if ($operator == 'is not odd') {$return = '(('.$return.') % 2 != 0)';}
  868. if ($operator == 'is not even') {$return = '(('.$return.') % 2 == 0)';}
  869. elseif ($operator == 'is odd') {$return = '(('.$return.') % 2 == 0)';}
  870. elseif ($operator == 'is even') {$return = '(('.$return.') % 2 != 0)';}
  871. elseif (preg_match('~^instanceof (.*)$~',$operator,$e))
  872. {
  873. $cn = preg_match('~^\w+$~',$e[1])?$e[1]:$this->_expr_token($e[1]);
  874. $return = '('.$return.' instanceof '.$cn.')';
  875. }
  876. elseif (preg_match('~^is( not)? odd by (.*)$~',$operator,$e))
  877. {
  878. $return = '(('.$return.' / '.$this->_expr_token($e[2]).') % 2 '.($e[1] != ''?'!':'=').'= 0)';
  879. }
  880. elseif (preg_match('~^is( not)? even by (.*)$~',$operator,$e))
  881. {
  882. $return = '(('.$return.' / '.$this->_expr_token($e[2]).') % 2 '.($e[1] == ''?'!':'=').'= 0)';
  883. }
  884. elseif (preg_match('~^is( not)? div by (.*)$~',$operator,$e))
  885. {
  886. $return = '(('.$return.' % '.$this->_expr_token($e[2]).') '.($e[1] != ''?'!':'=').'= 0)';
  887. }
  888. else {return $this->_syntax_error('Unexpected operator \''.$operator.'\'');}
  889. }
  890. if (isset($m[8]) and $m[8] !== '')
  891. {
  892. $mods_token = $m[8];
  893. preg_match_all('~\|@?\s*\w+(?:\:(?:[^\:\|\'"]*(?:([\'"]).*?(?<!\\\\)\1[^\:\|\'"]*)*))*~',$mods_token,$mods_m,PREG_SET_ORDER);
  894. $mods = array();
  895. for ($i = 0,$s = sizeof($mods_m); $i < $s; $i++)
  896. {
  897. preg_match('~\|(@?\w+)(.*)~',$mods_m[$i][0],$q);
  898. $mod_name = $q[1];
  899. $params_token = $q[2];
  900. preg_match_all('~\:([^\:\|\'"]*(?:([\'"]).*?(?<!\\\\)\2[^\:\|\'"]*)*)~',$params_token,$p,PREG_SET_ORDER);
  901. $params = array();
  902. $mod = array($mod_name,array());
  903. for ($j = 0,$ps = sizeof($p); $j < $ps; $j++) {$mod[1][] = $this->_expr_token($p[$j][1]);}
  904. $mods[] = $mod;
  905. }
  906. $internal_mods = array('html');
  907. for ($i = 0,$s = sizeof($mods); $i < $s; $i++)
  908. {
  909. if (substr($mods[$i][0],0,1) == '@') {$no_errors = TRUE; $mods[$i][0] = substr($mods[$i][0],1);}
  910. else {$no_errors = FALSE;}
  911. $mod_name = strtolower($mods[$i][0]);
  912. $mod_params = $mods[$i][1];
  913. if ($mod_name == 'upper' or $mod_name == 'lower') {$mod_name = 'strto'.$mod_name;}
  914. if (($mod_name == 'default') && (substr($return,0,1) == '$')) {$mod_name = 'default_var';}
  915. $short = FALSE;
  916. foreach ($this->allowed_php_tokens as $av)
  917. {
  918. if (preg_match($e = '~^'.str_replace('\*','.*',preg_quote($av,'~')).'$~i',$mod_name)) {$short = TRUE; break;}
  919. }
  920. if ($short || in_array($mod_name,$internal_mods)) {}
  921. elseif (!preg_match('~^\w+$~',$mod_name) || !($p = $this->parent->fetch_plugin('modifier.'.$mod_name)))
  922. {
  923. return $this->_syntax_error('Undefined modifier \''.$mod_name.'\'');
  924. }
  925. if ($mod_name == 'escape' or $mod_name == 'html') {$this->_no_auto_escape = TRUE;}
  926. if ($mod_name == 'escape' && sizeof($mod_params) == 0) {$return = 'htmlspecialchars('.$return.')'; continue;}
  927. elseif ($mod_name == 'html') {continue;}
  928. elseif ($mod_name == 'escape' && sizeof($mod_params) > 0 && $mod_params[0] == '\'urlencode\'') {$return = 'urlencode('.$return.')'; continue;}
  929. elseif ($mod_name == 'escape' && sizeof($mod_params) > 0 && $mod_params[0] == '\'urldecode\'') {$return = 'urldecode('.$return.')'; continue;}
  930. elseif ($mod_name == 'count' || $mod_name == 'sizeof') {$return = 'sizeof('.$return.')'; continue;}
  931. elseif ($mod_name == 'urlencode') {$return = 'urlencode('.$return.')'; continue;}
  932. elseif ($mod_name == 'cat' && isset($mod_params[0])) {$return = $return.'.'.$mod_params[0]; continue;}
  933. if (!$short and !in_array($p,$this->load_plugins)) {$this->load_plugins[] = $p;}
  934. $return = ($no_errors?'@':'').(!$short?'quicky_modifier_':'').$mod_name.'('.$return.(sizeof($mod_params)?','.implode(',',$mod_params):'').')';
  935. }
  936. }
  937. return $return;
  938. }
  939. function _var_string_callback($m)
  940. {
  941. if (isset($m[6])) {return stripslashes($m[6]);}
  942. if ($m[0] == '\\"') {return '"';}
  943. $prefix = '';
  944. if (strlen($m[1]) != 0)
  945. {
  946. if (strlen($m[1]) % 2 != 0) {return stripslashes($m[1]).$m[2];}
  947. else {$prefix = var_export(stripslashes($m[1]),TRUE).'.';}
  948. }
  949. $expr = $m[2];
  950. if ((substr($expr,0,1) == $this->left_delimiter and substr($expr,-1) == $this->right_delimiter) ||
  951. (substr($expr,0,1) == '`' and substr($expr,-1) == '`'))
  952. {
  953. $expr = substr($expr,1,-1);
  954. $return = $this->_expr_token(stripslashes($expr));
  955. }
  956. elseif (substr($expr,0,1) == '_') {$return = $this->_expr_token(stripslashes($expr));}
  957. else {$return = $prefix.$this->_var_token($m[2]);}
  958. return '\'.'.$return.'.\'';
  959. }
  960. function _expr_token($token,$instring = FALSE,$emptynull = FALSE,$cplmode = FALSE)
  961. {
  962. while ((substr($token,0,1) == '`') && (substr($token,-1) == '`')) {$token = substr($token,1,-1);}
  963. if ($cplmode) {$_cplmode_old = $this->_cplmode; $this->_cplmode = TRUE;}
  964. if ($token === '') {return '';}
  965. if (substr($token,0,1) == '_')
  966. {
  967. if (substr($token,1,1) == '_') {$token = substr($token,1);}
  968. $token = substr($token,1);
  969. $return = var_export($this->_fetch_expr($this->_expr_token($token,FALSE,TRUE,TRUE)),TRUE);
  970. return $return;
  971. }
  972. $in = $token;
  973. $token = ltrim($token);
  974. if ($instring)
  975. {
  976. $a = $token;
  977. if ($a[0] == '"')
  978. {
  979. $a = '\''.strtr(substr($a,1,-1),array('\'' => '\\\'', '\\' => '\\\\')).'\'';
  980. $ldelim = preg_quote($this->left_delimiter,'~');
  981. $rdelim = preg_quote($this->right_delimiter,'~');
  982. $o = isset($this->prefs['cast_undefined_token_to_strings'])?$this->prefs['cast_undefined_token_to_strings']:FALSE;
  983. $this->prefs['cast_undefined_token_to_strings'] = TRUE;
  984. $a = preg_replace_callback('~(\\\*)('.$ldelim.'.*?'.$rdelim.'|`.*?`|_?[\$#]\w+#?(?:\[[\$#]?\w+#?\])*)|((?<!\\\\)\\\\")~',array($this,'_var_string_callback'),$a);
  985. $this->prefs['cast_undefined_token_to_strings'] = $o;
  986. $a = preg_replace('~\.\'(?<!\\\\)\'|(?<!\\\\)\'\'\.|^\'\.(?=[\$\(])|(?<=[\)\'])\.\'$|\'\.\'~','',$a);
  987. }
  988. return $a;
  989. }
  990. $return = preg_replace_callback(
  991. '~(([\'"]).*?(?<!\\\\)\2|\w*\s*\(((?:(?R)|.)*?)\)'
  992. .'|(?!(?:is\s+not|is|not\s+eq|eq|neq?|gt|lt|gt?e|ge|lt?e|mod)\W)_?[\$#]?\w+#?(?:\\[(?:(?R)|\w+|((?:[^\\]\'"]*(?:([\'"]).*?(?<!\\\\)\5)?)*))*?\\]|\.[\$#]?\w+#?|->\s*_?[\$#]?\w+#?(?:\(((?:(?R)|.)*?)\))?)*'
  993. .'|-?\d+|(?<=^|[\s\)\:\.=+\-<>])(?!(?:is\s+not|is|not\s+eq|eq|neq?|gt|lt|gt?e|ge|lt?e|mod)\W)(?:\w+)(?=$|[\s\|\.\:\(=+\-<>]))(\s+(?:instanceof (?:\w+|(?R))|is(?:\s+not)?\s+(?:odd|div|even)\s+by\s+(?:-?\d+|(?R))|is(?:\s+not)?\s+(?:odd|even)))?((?:\|@?\w+(?:\\:(?:'.'\w*\(((?:(?R)|.)*?)\)|[\$#]\w+#?(?:\\[(?:(?R)|((?:[^\\]\'"]*(?:([\'"]).*?(?<!\\\\)\11)?)*))*?\\]|\.[\$#]?\w+#?)*|[^\'"\:]*(?:[^\'"\:]*([\'"]).*?(?<!\\\\)\12[^\'"\:]*)*'.'))*)*)'
  994. .'|((?<=\s|\))(?:is\s+not|is|not\s+eq|eq|neq?|gt|lt|gt?e|ge|lt?e|mod)(?=\s|\()|(?:not\s+))'
  995. .'~si',array($this,'_expr_token_callback'),$token);
  996. if ($emptynull and trim($return) === '') {return 'NULL';}
  997. if ($cplmode) {$this->_cplmode = $_cplmode_old;}
  998. return $return;
  999. }
  1000. }
  1001. if (!function_exists('ctype_digit')) {function ctype_digit($s) {return (bool) preg_match('~^\d+$~',$s);}}