Marius Burkard
2016-04-20 4569cae57f127afd093794310ccd290d2d9fdf36
commit | author | age
b5a2f8 1 <?php
9026a4 2 /**
7fe908 3  * vlibTemplate is a class used to seperate PHP and HTML.
MC 4  * For instructions on how to use vlibTemplate, see the
5  * vlibTemplate.html file, located in the 'docs' directory.
6  *
7  * @since 07/03/2002
8  * @author Kelvin Jones <kelvin@kelvinjones.co.uk>
9  * @package vLIB
10  * @access public
11  * @see vlibTemplate.html
12  */
13
b5a2f8 14
T 15 /* vim: set expandtab tabstop=4 shiftwidth=4: */
16 // +----------------------------------------------------------------------+
17 // | PHP version 4.0                                                      |
18 // +----------------------------------------------------------------------+
19 // | Copyright (c) 2002 Active Fish Group                                 |
20 // +----------------------------------------------------------------------+
21 // | Authors: Kelvin Jones <kelvin@kelvinjones.co.uk>                     |
22 // +----------------------------------------------------------------------+
23 //
24 // $Id: class.tpl.inc.php,v 1.1 2003/07/08 12:31:10 platinum Exp $
25
dcff57 26 //** check and avoid multiple loading of class
b5a2f8 27 if (!defined('vlibTemplateClassLoaded')) {
dcff57 28
7fe908 29     define('vlibTemplateClassLoaded', 1);
MC 30     include_once ISPC_CLASS_PATH.'/tpl_error.inc.php';
31     include_once ISPC_CLASS_PATH.'/tpl_ini.inc.php';
b5a2f8 32
7fe908 33     class tpl{
MC 34
35         /*-----------------------------------------------------------------------------\
d9bb62 36         |                                 ATTENTION                                    |
P 37         |  Do not touch the following variables. vlibTemplate will not work otherwise. |
38         \-----------------------------------------------------------------------------*/
7fe908 39         private $OPTIONS = array(
MC 40             'MAX_INCLUDES'          =>   10,
41             'TEMPLATE_DIR'          => null,
42             'GLOBAL_VARS'           => null,
43             'GLOBAL_CONTEXT_VARS'   => null,
44             'LOOP_CONTEXT_VARS'     => null,
45             'SET_LOOP_VAR'          => null,
46             'DEFAULT_ESCAPE'        => null,
47             'STRICT'                => null,
48             'CASELESS'              => null,
49             'UNKNOWNS'              => null,
50             'TIME_PARSE'            => null,
51             'ENABLE_PHPINCLUDE'     => null,
52             'INCLUDE_PATHS'         => array(),
53             'CACHE_DIRECTORY'       => null,
54             'CACHE_LIFETIME'        => null,
55             'CACHE_EXTENSION'       => null
56         );
b5a2f8 57
7fe908 58         /** open and close tags used for escaping */
MC 59         private $ESCAPE_TAGS = array(
60             'html'      => array('open' => 'htmlspecialchars('    , 'close'=> ', ENT_QUOTES)'),
61             'url'       => array('open' => 'urlencode('           , 'close'=> ')'),
62             'rawurl'    => array('open' => 'rawurlencode('        , 'close'=> ')'),
63             'sq'        => array('open' => 'addcslashes('         , 'close'=> ", \"'\")"),
64             'dq'        => array('open' => 'addcslashes('         , 'close'=> ", '\"')"),
65             '1'         => array('open' => 'htmlspecialchars('    , 'close'=> ', ENT_QUOTES)'),
66             '0'         => array('open' => ''                     , 'close'=> ''),
67             'none'      => array('open' => ''                     , 'close'=> ''),
68             'hex'       => array('open' => '$this->_escape_hex('  , 'close'=> ', false)'),
69             'hexentity' => array('open' => '$this->_escape_hex('  , 'close'=> ', true)')
70         );
b5a2f8 71
T 72
d9bb62 73
7fe908 74         /** open and close tags used for formatting */
MC 75         private $FORMAT_TAGS = array(
76             'strtoupper' => array('open' => 'strtoupper(',          'close'=> ')'),
77             'uc'         => array('open' => 'strtoupper(',          'close'=> ')'),
78             'strtolower' => array('open' => 'strtolower(',          'close'=> ')'),
79             'lc'         => array('open' => 'strtolower(',          'close'=> ')'),
80             'ucfirst'    => array('open' => 'ucfirst(',             'close'=> ')'),
81             'lcucfirst'  => array('open' => 'ucfirst(strtolower(',  'close'=> '))'),
82             'ucwords'    => array('open' => 'ucwords(',             'close'=> ')'),
83             'lcucwords'  => array('open' => 'ucwords(strtolower(',  'close'=> '))')
84         );
85
86         /** operators allowed when using extended TMPL_IF syntax */
87         private $allowed_if_ops = array('==', '!=', '<>', '<', '>', '<=', '>=');
88
89
90
91         /** dbs allowed by vlibTemplate::setDbLoop(). */
92         private $allowed_loop_dbs = array('MYSQL', 'POSTGRESQL', 'INFORMIX', 'INTERBASE', 'INGRES',
93             'MSSQL', 'MSQL', 'OCI8', 'ORACLE', 'OVRIMOS', 'SYBASE');
94
95
96
97         /** root directory of vlibTemplate automagically filled in */
98         private $VLIBTEMPLATE_ROOT = null;
99
100
101
102         /** contains current directory used when doing recursive include */
103         private $_currentincludedir = array();
104
105
106
107         /** current depth of includes */
108         private $_includedepth = 0;
109
110
111
112         /** full path to tmpl file */
113         private $_tmplfilename = null;
114
115
116
117         /** file data before it's parsed */
118         private $_tmplfile = null;
119
120
121
122         /** parsed version of file, ready for eval()ing */
123         private $_tmplfilep = null;
124
125
126
127         /** eval()ed version ready for printing or whatever */
128         private $_tmploutput = null;
129
130
131
132         /** array for variables to be kept */
133         private $_vars = array();
134
135
136
137         /** array where loop variables are kept */
138         private $_arrvars = array();
139
140         /** array which holds the current namespace during parse */
141         private $_namespace = array();
142
143
144
145         /** variable is set to true once the template is parsed, to save re-parsing everything */
146         private $_parsed = false;
147
148
149
150         /** array holds all unknowns vars */
151         private $_unknowns = array();
152
153
154
155         /** microtime when template parsing began */
156         private $_firstparsetime = null;
157
158
159
160         /** total time taken to parse template */
161         private $_totalparsetime = null;
162
163
164
165         /** name of current loop being passed in */
166         private $_currloopname = null;
167
168
169
170         /** rows with the above loop */
171         private $_currloop = array();
172
173
174
175         /** define vars to avoid warnings */
176         private $_debug = null;
177         private $_cache = null;
178
179
180
181         /** array which holds the dynamic Includes */
182         private $_dyninclude = array();
183
184         /*-----------------------------------------------------------------------------\
d9bb62 185         |                           public functions                                   |
P 186         \-----------------------------------------------------------------------------*/
b5a2f8 187
T 188
189
7fe908 190
MC 191
192         /**
193          * Usually called by the class constructor.
194          * Stores the filename in $this->_tmplfilename.
195          * Raises an error if the template file is not found.
196          * @param string $tmplfile full path to template file
197          * @return boolean true
198          * @access public
199          */
200         public function newTemplate($tmplfile)
201         {
202             if (!$tfile = $this->_fileSearch($tmplfile)){
203                 vlibTemplateError::raiseError('VT_ERROR_NOFILE', KILL, $tmplfile);
204             }
205
206             //* make sure that any parsing vars are cleared for the new template
207             $this->_tmplfile = null;
208             $this->_tmplfilep = null;
209             $this->_tmploutput = null;
210             $this->_parsed = false;
211             $this->_unknowns = array();
212             $this->_firstparsetime = null;
213             $this->_totalparsetime = null;
214
215             //* reset debug module
216             if ($this->_debug){
217                 $this->_debugReset();
218             }
219             $this->_tmplfilename = $tfile;
220             return true;
221         }
222
223         /**
224          * Sets variables to be used by the template
225          * If $k is an array, then it will treat it as an associative array
226          * using the keys as variable names and the values as variable values.
227          * @param mixed $k key to define variable name
228          * @param mixed $v variable to assign to $k
229          * @return boolean true/false
230          * @access public
231          */
232         public function setVar($k, $v = null)
233         {
234             if (is_array($k)) {
235                 foreach($k as $key => $value){
236                     $key = ($this->OPTIONS['CASELESS']) ? strtolower(trim($key)) : trim($key);
eca44a 237                     if (preg_match('/^[A-Za-z_]+[A-Za-z0-9_]*$/', $key) && $value !== null ) {
7fe908 238                         $this->_vars[$key] = $value;
MC 239                     }
240                 }
241             } else {
eca44a 242                 if (preg_match('/^[A-Za-z_]+[A-Za-z0-9_]*$/', $k) && $v !== null) {
7fe908 243                     if ($this->OPTIONS['CASELESS']) $k = strtolower($k);
MC 244                     $this->_vars[trim($k)] = $v;
245                 } else {
246                     return false;
247                 }
248             }
249             return true;
250         }
251
252
253
254         /**
255          * Sets dynamic includes to be used by the template
256          * If $k is an array, then it will treat it as an associative array
257          * using the keys as variable names and the values as variable values.
258          * @param mixed $k key to define variable name
259          * @param mixed $v variable to assign to $k
260          * @return boolean true/false
261          * @access public
262          */
263         public function setInclude($k, $v = null)
264         {
265             if(is_array($k)) {
b5a2f8 266                 foreach($k as $key => $val) {
T 267                     $this->_dyninclude[$key] = $val;
268                 }
269             } else {
270                 $this->_dyninclude[$k] = $v;
271             }
272             return true;
273         }
274
7fe908 275         /**
MC 276          * Unsets a variable which has already been set
277          * Parse in all vars wanted for deletion in seperate parametres
278          * @param string var name to remove use: vlibTemplate::unsetVar(var[, var..])
279          * @return boolean true/false returns true unless called with 0 params
280          * @access public
281          */
282         public function unsetVar()
283         {
284             $num_args = func_num_args();
285             if ($num_args < 1)  return false;
b5a2f8 286
7fe908 287             for ($i = 0; $i < $num_args; $i++) {
MC 288                 $var = func_get_arg($i);
289                 if ($this->OPTIONS['CASELESS']) $var = strtolower($var);
eca44a 290                 if (!preg_match('/^[A-Za-z_]+[A-Za-z0-9_]*$/', $var)) continue;
7fe908 291                 unset($this->_vars[$var]);
MC 292             }
293             return true;
294         }
b5a2f8 295
7fe908 296         /**
MC 297          * Gets all vars currently set in global namespace.
298          * @return array
299          * @access public
300          */
301         public function getVars()
302         {
303             return empty($this->_vars) ? false : $this->_vars;
304         }
b5a2f8 305
7fe908 306         /**
MC 307          * Gets a single var from the global namespace
308          * @return var
309          * @access public
310          */
311         public function getVar($var)
312         {
313             if ($this->OPTIONS['CASELESS']) $var = strtolower($var);
314             return (empty($var) || !isset($this->_vars[$var])) ? false : $this->_vars[$var];
315         }
b5a2f8 316
7fe908 317         /**
MC 318          * sets the GLOBAL_CONTEXT_VARS
319          * @return true
320          * @access public
321          */
322         public function setContextVars()
323         {
324             $_phpself = @$GLOBALS['HTTP_SERVER_VARS']['PHP_SELF'];
325             $_pathinfo = @$GLOBALS['HTTP_SERVER_VARS']['PATH_INFO'];
326             $_request_uri = @$GLOBALS['HTTP_SERVER_VARS']['REQUEST_URI'];
327             $_qs   = @$GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING'];
b5a2f8 328
7fe908 329             //* the following fixes bug of $PHP_SELF on Win32 CGI and IIS.
MC 330             $_self = (!empty($_pathinfo)) ? $_pathinfo : $_phpself;
331             $_uri  = (!empty($_request_uri)) ? $_request_uri : $_self.'?'.$_qs;
b5a2f8 332
7fe908 333             $this->setvar('__SELF__', $_self);
MC 334             $this->setvar('__REQUEST_URI__', $_uri);
335             return true;
336         }
b5a2f8 337
7fe908 338         /**
MC 339          * Builds the loop construct for use with <TMPL_LOOP>.
340          * @param string $k string to define loop name
341          * @param array $v array to assign to $k
342          * @return boolean true/false
343          * @access public
344          */
345         public function setLoop($k, $v)
346         {
eca44a 347             if (is_array($v) && preg_match('/^[A-Za-z_]+[A-Za-z0-9_]*$/', $k)) {
7fe908 348                 $k = ($this->OPTIONS['CASELESS']) ? strtolower(trim($k)) : trim($k);
MC 349                 $this->_arrvars[$k] = array();
350                 if ($this->OPTIONS['SET_LOOP_VAR'] && !empty($v)) $this->setvar($k, 1);
351                 if (($this->_arrvars[$k] = $this->_arrayBuild($v)) == false) {
352                     vlibTemplateError::raiseError('VT_WARNING_INVALID_ARR', WARNING, $k);
353                 } else {
354                     $this->vars['_'.$k.'_num'] = count($v);
355                 }
356             }
357             return true;
358         }
b5a2f8 359
7fe908 360         /**
MC 361          * [** EXPERIMENTAL **]
362          * Function to create a loop from a Db result resource link.
363          * @param string $loopname to commit loop. If not set, will use last loopname set using newLoop()
364          * @param string $result link to a Db result resource
365          * @param string $db_type, type of db that the result resource belongs to.
366          * @return boolean true/false
367          * @access public
368          */
369         public function setDbLoop($loopname, $result, $db_type = 'MYSQL')
370         {
371             /*
b7bf0c 372             $db_type = strtoupper($db_type);
b5a2f8 373             if (!in_array($db_type, $this->allowed_loop_dbs)) {
1d751b 374                 vlibTemplateError::raiseError('VT_WARNING_INVALID_LOOP_DB', WARNING, $db_type);
b5a2f8 375                 return false;
T 376             }
377
378             $loop_arr = array();
1d751b 379             // TODO: Are all these necessary as were onyl using mysql and possible postgres ? - pedro
b5a2f8 380             switch ($db_type) {
T 381
382                 case 'MYSQL':
383                     if (get_resource_type($result) != 'mysql result') {
1d751b 384                         vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type);
b5a2f8 385                         return false;
T 386                     }
387                     while($r = mysql_fetch_assoc($result)) {
388                         $loop_arr[] = $r;
389                     }
d9bb62 390                     break;
b5a2f8 391
T 392                 case 'POSTGRESQL':
393                     if (get_resource_type($result) != 'pgsql result') {
1d751b 394                         vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type);
b5a2f8 395                         return false;
T 396                     }
397
398                     $nr = (function_exists('pg_num_rows')) ? pg_num_rows($result) : pg_numrows($result);
399
400                     for ($i=0; $i < $nr; $i++) {
401                         $loop_arr[] = pg_fetch_array($result, $i, PGSQL_ASSOC);
402                     }
d9bb62 403                     break;
b5a2f8 404
T 405                 case 'INFORMIX':
406                     if (!$result) {
1d751b 407                         vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type);
b5a2f8 408                         return false;
T 409                     }
410                     while($r = ifx_fetch_row($result, 'NEXT')) {
411                         $loop_arr[] = $r;
412                     }
d9bb62 413                     break;
b5a2f8 414
T 415                 case 'INTERBASE':
416                     if (get_resource_type($result) != 'interbase result') {
1d751b 417                         vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type);
b5a2f8 418                         return false;
T 419                     }
420                     while($r = ibase_fetch_row($result)) {
421                         $loop_arr[] = $r;
422                     }
d9bb62 423                     break;
b5a2f8 424
T 425                 case 'INGRES':
426                     if (!$result) {
1d751b 427                         vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type);
b5a2f8 428                         return false;
T 429                     }
430                     while($r = ingres_fetch_array(INGRES_ASSOC, $result)) {
431                         $loop_arr[] = $r;
432                     }
d9bb62 433                     break;
b5a2f8 434
T 435                 case 'MSSQL':
436                     if (get_resource_type($result) != 'mssql result') {
1d751b 437                         vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type);
b5a2f8 438                         return false;
T 439                     }
440                     while($r = mssql_fetch_array($result)) {
441                         $loop_arr[] = $r;
442                     }
d9bb62 443                     break;
b5a2f8 444
T 445                 case 'MSQL':
446                     if (get_resource_type($result) != 'msql result') {
1d751b 447                         vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type);
b5a2f8 448                         return false;
T 449                     }
450                     while($r = msql_fetch_array($result, MSQL_ASSOC)) {
451                         $loop_arr[] = $r;
452                     }
d9bb62 453                     break;
b5a2f8 454
T 455                 case 'OCI8':
456                     if (get_resource_type($result) != 'oci8 statement') {
1d751b 457                         vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type);
b5a2f8 458                         return false;
T 459                     }
460                     while(OCIFetchInto($result, &$r, OCI_ASSOC+OCI_RETURN_LOBS)) {
461                         $loop_arr[] = $r;
462                     }
d9bb62 463                     break;
b5a2f8 464
T 465                 case 'ORACLE':
466                     if (get_resource_type($result) != 'oracle Cursor') {
1d751b 467                         vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type);
b5a2f8 468                         return false;
T 469                     }
470                     while(ora_fetch_into($result, &$r, ORA_FETCHINTO_ASSOC)) {
471                         $loop_arr[] = $r;
472                     }
d9bb62 473                     break;
b5a2f8 474
T 475                 case 'OVRIMOS':
476                     if (!$result) {
1d751b 477                         vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type);
b5a2f8 478                         return false;
T 479                     }
480                     while(ovrimos_fetch_into($result, &$r, 'NEXT')) {
481                         $loop_arr[] = $r;
482                     }
d9bb62 483                     break;
b5a2f8 484
T 485                 case 'SYBASE':
486                     if (get_resource_type($result) != 'sybase-db result') {
1d751b 487                         vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type);
b5a2f8 488                         return false;
T 489                     }
490
491                     while($r = sybase_fetch_array($result)) {
492                         $loop_arr[] = $r;
493                     }
d9bb62 494                     break;
b5a2f8 495             }
T 496             $this->setLoop($loopname, $loop_arr);
497             return true;
b7bf0c 498             */
7fe908 499         }
b5a2f8 500
7fe908 501         /**
MC 502          * Sets the name for the curent loop in the 3 step loop process.
503          * @param string $name string to define loop name
504          * @return boolean true/false
505          * @access public
506          */
507         public function newLoop($loopname)
508         {
509             if (preg_match('/^[a-z_]+[a-z0-9_]*$/i', $loopname)) {
510                 $this->_currloopname[$loopname] = $loopname;
511                 $this->_currloop[$loopname] = array();
512                 return true;
513             } else {
514                 return false;
515             }
516         }
b5a2f8 517
7fe908 518         /**
MC 519          * Adds a row to the current loop in the 3 step loop process.
520          * @param array $row loop row to add to current loop
521          * @param string $loopname loop to which you want to add row, if not set will use last loop set using newLoop().
522          * @return boolean true/false
523          * @access public
524          */
525         public function addRow($row, $loopname = null)
526         {
527             if (!$loopname) $loopname = $this->_currloopname[(count($this->_currloopname)-1)];
b5a2f8 528
7fe908 529             if (!isset($this->_currloop[$loopname]) || empty($this->_currloopname)) {
MC 530                 vlibTemplateError::raiseError('VT_WARNING_LOOP_NOT_SET', WARNING);
531                 return false;
532             }
533             if (is_array($row)) {
534                 $this->_currloop[$loopname][] = $row;
535                 return true;
536             } else {
537                 return false;
538             }
539         }
b5a2f8 540
7fe908 541         /**
MC 542          * Completes the 3 step loop process. This assigns the rows and resets
543          * the variables used.
544          * @param string $loopname to commit loop. If not set, will use last loopname set using newLoop()
545          * @return boolean true/false
546          * @access public
547          */
548         public function addLoop($loopname = null)
549         {
550             if ($loopname == null) { // add last loop used
551                 if (!empty($this->_currloop)) {
552                     foreach ($this->_currloop as $k => $v) {
553                         $this->setLoop($k, $v);
554                         unset($this->_currloop[$k]);
555                     }
556                     $this->_currloopname = array();
557                     return true;
558                 } else {
559                     return false;
560                 }
561             } elseif (!isset($this->_currloop[$loopname]) || empty($this->_currloopname)) { // newLoop not yet envoked
562                 vlibTemplateError::raiseError('VT_WARNING_LOOP_NOT_SET', WARNING);
563                 return false;
564             } else { // add a specific loop
565                 $this->setLoop($loopname, $this->_currloop[$loopname]);
566                 unset($this->_currloopname[$loopname], $this->_currloop[$loopname]);
567             }
568             return true;
569         }
b5a2f8 570
7fe908 571         /**
MC 572          * Unsets a loop which has already been set.
573          * Can only unset top level loops.
574          * @param string loop to remove use: vlibTemplate::unsetLoop(loop[, loop..])
575          * @return boolean true/false returns true unless called with 0 params
576          * @access public
577          */
578         public function unsetLoop()
579         {
580             $num_args = func_num_args();
581             if ($num_args < 1) return false;
b5a2f8 582
7fe908 583             for ($i = 0; $i < $num_args; $i++) {
MC 584                 $var = func_get_arg($i);
585                 if ($this->OPTIONS['CASELESS']) $var = strtolower($var);
586                 if (!preg_match('/^[A-Za-z_]+[A-Za-z0-9_]*$/', $var)) continue;
587                 unset($this->_arrvars[$var]);
588             }
589             return true;
590         }
b5a2f8 591
7fe908 592         /**
MC 593          * Resets the vlibTemplate object. After using vlibTemplate::reset() you must
594          * use vlibTemplate::newTemplate(tmpl) to reuse, not passing in the options array.
595          * @return boolean true
596          * @access public
597          */
598         public function reset()
599         {
600             $this->clearVars();
601             $this->clearLoops();
602             $this->_tmplfilename = null;
603             $this->_tmplfile = null;
604             $this->_tmplfilep = null;
605             $this->_tmploutput = null;
606             $this->_parsed = false;
607             $this->_unknowns = array();
608             $this->_firstparsetime = null;
609             $this->_totalparsetime = null;
610             $this->_currloopname = null;
611             $this->_currloop = array();
612             return true;
613         }
b5a2f8 614
7fe908 615         /**
MC 616          * Unsets all variables in the template
617          * @return boolean true
618          * @access public
619          */
620         public function clearVars()
621         {
622             $this->_vars = array();
623             return true;
624         }
b5a2f8 625
7fe908 626         /**
MC 627          * Unsets all loops in the template
628          * @return boolean true
629          * @access public
630          */
631         public function clearLoops()
632         {
633             $this->_arrvars = array();
634             $this->_currloopname = null;
635             $this->_currloop = array();
636             return true;
637         }
b5a2f8 638
7fe908 639         /**
MC 640          * Unsets all variables and loops set using setVar/Loop()
641          * @return boolean true
642          * @access public
643          */
644         public function clearAll()
645         {
646             $this->clearVars();
647             $this->clearLoops();
648             return true;
649         }
b5a2f8 650
7fe908 651         /**
MC 652          * Returns true if unknowns were found after parsing.
653          * Function MUST be called AFTER one of the parsing functions to have any relevance.
654          * @return boolean true/false
655          * @access public
656          */
657         public function unknownsExist()
658         {
659             return !empty($this->_unknowns);
660         }
b5a2f8 661
7fe908 662         /**
MC 663          * Alias for unknownsExist.
664          * @access public
665          */
666         public function unknowns()
667         {
668             return $this->unknownsExist();
669         }
b5a2f8 670
7fe908 671         /**
MC 672          * Returns an array of all unknown vars found when parsing.
673          * This function is only relevant after parsing a document.
674          * @return array
675          * @access public
676          */
677         public function getUnknowns()
678         {
679             return $this->_unknowns;
680         }
b5a2f8 681
7fe908 682         /**
MC 683          * Sets how you want to handle variables that were found in the
684          * template but not set in vlibTemplate using vlibTemplate::setVar().
685          * @param  string $arg ignore, remove, print, leave or comment
686          * @return boolean
687          * @access public
688          */
689         public function setUnknowns($arg)
690         {
691             $arg = strtolower(trim($arg));
692             if (preg_match('/^ignore|remove|print|leave|comment$/', $arg)) {
693                 $this->OPTIONS['UNKNOWNS'] = $arg;
694                 return true;
695             }
696             return false;
697         }
b5a2f8 698
7fe908 699         /**
MC 700          * function sets the paths to use when including files.
701          * Use of this function: vlibTemplate::setPath(string path [, string path, ..]);
702          * i.e. if $tmpl is your template object do: $tmpl->setPath('/web/htdocs/templates','/web/htdocs/www');
703          * with as many paths as you like.
704          * if this function is called without any arguments, it will just delete any previously set paths.
705          *
706          * @param string path (mulitple)
707          * @return bool success
708          * @access public
709          */
710         public function setPath()
711         {
712             $num_args = func_num_args();
713             if ($num_args < 1) {
714                 $this->OPTIONS['INCLUDE_PATHS'] = array();
715                 return true;
716             }
717             for ($i = 0; $i < $num_args; $i++) {
718                 $thispath = func_get_arg($i);
719                 array_push($this->OPTIONS['INCLUDE_PATHS'], realpath($thispath));
720             }
721             return true;
722         }
b5a2f8 723
7fe908 724         /**
MC 725          * After using one of the parse functions, this will allow you
726          * access the time taken to parse the template.
727          * see OPTION 'TIME_PARSE'.
728          *
729          * @return float time taken to parse template
730          * @access public
731          */
732         public function getParseTime()
733         {
734             if ($this->OPTIONS['TIME_PARSE'] && $this->_parsed) {
735                 return $this->_totalparsetime;
736             }
737             return false;
738         }
b5a2f8 739
T 740
7fe908 741         /**
MC 742          * Identical to pparse() except that it uses output buffering w/ gz compression thus
743          * printing the output directly and compressed if poss.
744          * Will possibly if parsing a huge template.
745          *
746          * @access public
747          * @return boolean true/false
748          */
749         public function fastPrint()
750         {
751             $ret = $this->_parse('ob_gzhandler');
752             print($this->_tmploutput);
753             return $ret;
754         }
b5a2f8 755
T 756
7fe908 757         /**
MC 758          * Calls parse, and then prints out $this->_tmploutput
759          * @access public
760          * @return boolean true/false
761          */
762         public function pparse()
763         {
764             if (!$this->_parsed) $this->_parse();
765             print($this->_tmploutput);
766             return true;
767         }
b5a2f8 768
7fe908 769         /**
MC 770          * Alias for pparse()
771          * @access public
772          */
773         public function pprint()
774         {
775             return $this->pparse();
776         }
b5a2f8 777
T 778
7fe908 779         /**
MC 780          * Returns the parsed output, ready for printing, passing to mail() ...etc.
781          * Invokes $this->_parse() if template has not yet been parsed.
782          *
783          * @access public
784          * @return boolean true/false
785          */
786         public function grab()
787         {
788             if (!$this->_parsed) $this->_parse();
789             return $this->_tmploutput;
790         }
b5a2f8 791
7fe908 792         /*-----------------------------------------------------------------------------\
d9bb62 793         |                           private functions                                  |
P 794         \-----------------------------------------------------------------------------*/
b5a2f8 795
7fe908 796         /**
MC 797          * vlibTemplate constructor.
798          * if $tmplfile has been passed to it, it will send to $this->newTemplate()
799          * @param string $tmplfile full path to template file
800          * @param array $options see above
801          * @return boolean true/false
802          * @access private
803          */
804         public function __construct($tmplfile = null, $options = null)
805         {
806             if (is_array($tmplfile) && $options == null) {
807                 $options = $tmplfile;
808                 unset($tmplfile);
809             }
b5a2f8 810
7fe908 811             $this->VLIBTEMPLATE_ROOT = dirname(realpath(__FILE__));
b5a2f8 812
7fe908 813             if (is_array(vlibIni::vlibTemplate())) {
MC 814                 foreach (vlibIni::vlibTemplate() as $name => $val) {
815                     $this->OPTIONS[$name] = $val;
816                 }
817             }
b5a2f8 818
7fe908 819             if (is_array($options)) {
MC 820                 foreach($options as $key => $val) {
821                     $key = strtoupper($key);
822                     if ($key == 'PATH') {
823                         $this->setPath($val);
824                     } else {
825                         $this->_setOption($key, strtolower($val));
826                     }
827                 }
828             }
829             if($tmplfile) $this->newTemplate($tmplfile);
830             if ($this->OPTIONS['GLOBAL_CONTEXT_VARS']) $this->setContextVars();
831             return true;
832         }
b5a2f8 833
7fe908 834         /**
MC 835          * function returns the text from the file, or if we're using cache, the text
836          * from the cache file. MUST RETURN DATA.
837          * @param string tmplfile contains path to template file
838          * @param do_eval used for included files. If set then this function must do the eval()'ing.
839          * @access private
840          * @return mixed data/string or boolean
841          */
1b9d2f 842         private function _getData ($tmplfile, $do_eval=false, $tmpl_from_string = false)
7fe908 843         {
MC 844             //* check the current file depth
845             if ($this->_includedepth > $this->OPTIONS['MAX_INCLUDES'] || $tmplfile == false) {
846                 return;
847             } else {
848                 if ($this->_debug){
1b9d2f 849                     if($tmpl_from_string) array_push($this->_debugIncludedfiles, 'String: ' . substr($tmplfile, 0, 25) . '...');
MB 850                     else array_push($this->_debugIncludedfiles, $tmplfile);
7fe908 851                 }
MC 852                 if ($do_eval) {
1b9d2f 853                     if($tmpl_from_string == true) array_push($this->_currentincludedir, end($this->_currentincludedir));
MB 854                     else array_push($this->_currentincludedir, dirname($tmplfile));
7fe908 855                     $this->_includedepth++;
MC 856                 }
857             }
b5a2f8 858
T 859
1b9d2f 860             if($this->_cache && $this->_checkCache($tmplfile, $tmpl_from_string)) { //* cache exists so lets use it
67d99a 861                 $data = file_get_contents($this->_cachefile);
7fe908 862             } else { //* no cache lets parse the file
1b9d2f 863                 if($tmpl_from_string == true) {
MB 864                     $data = $tmplfile;
865                 } else {
67d99a 866                     $data = file_get_contents($tmplfile);
1b9d2f 867                 }
b5a2f8 868
7fe908 869                 $regex = '/(<|<\/|{|{\/|<!--|<!--\/){1}\s*';
MC 870                 $regex.= 'tmpl_([\w]+)\s*';
eca44a 871                 $regex.= '((?:(?:';
7fe908 872                 $regex.=    '(?:';
MC 873                 $regex.=        '(name|format|escape|op|value|file)';
874                 $regex.=        '\s*=\s*';
875                 $regex.=    ')?';
876                 $regex.=    '(?:[\"\'])?';
877                 $regex.=    '((?<=[\"\'])';
878                 $regex.=    '[^\"\']*|[a-z0-9_\.]*)';
879                 $regex.=    '[\"\']?';
eca44a 880                 $regex.= ')?\s*)*?)';
7fe908 881                 $regex.= '(?:>|\/>|}|-->){1}';
eca44a 882                 $regex.= '/i';
MC 883                 $data = preg_replace_callback($regex, array($this, '_parseTag'), $data);
b5a2f8 884
7fe908 885                 if ($this->_cache) { // add cache if need be
MC 886                     $this->_createCache($data);
887                 }
888             }
b5a2f8 889
7fe908 890             //* now we must parse the $data and check for any <tmpl_include>'s
1b9d2f 891             if ($this->_debug && $tmpl_from_string == false) $this->doDebugWarnings(file($tmplfile), $tmplfile);
b5a2f8 892
7fe908 893             if ($do_eval) {
MC 894                 $success = @eval('?>'.$data.'<?php return 1;');
895                 $this->_includedepth--;
896                 array_pop($this->_currentincludedir);
897                 return $success;
898             } else {
899                 return $data;
900             }
901         }
b5a2f8 902
7fe908 903         /**
MC 904          * Searches for all possible instances of file { $file }
905          * @param string $file path of file we're looking for
906          * @access private
907          * @return mixed fullpath to file or boolean false
908          */
909         private function _fileSearch($file)
910         {
911
1199a7 912             $filename = basename($file);
7fe908 913             $filepath = dirname($file);
MC 914
1199a7 915             if(isset($_SESSION['s']['module']['name']) && isset($_SESSION['s']['theme'])) {
f0b3e5 916                 if(is_file(ISPC_THEMES_PATH.'/'.$_SESSION['s']['theme'].'/templates/'.$_SESSION['s']['module']['name'].'/'.$filename)) {
C 917                     return ISPC_THEMES_PATH.'/'.$_SESSION['s']['theme'].'/templates/'.$_SESSION['s']['module']['name'].'/'.$filename;
1199a7 918                 }
T 919             }
b5a2f8 920
7fe908 921             //* check fullpath first..
MC 922             $fullpath = $filepath.'/'.$filename;
923             if (is_file($fullpath)) return $fullpath;
b5a2f8 924
7fe908 925             //* ..then check for relative path for current directory..
MC 926             if (!empty($this->_currentincludedir)) {
927                 $currdir = $this->_currentincludedir[(count($this->_currentincludedir) -1)];
928                 $relativepath = realpath($currdir.'/'.$filepath.'/'.$filename);
929                 if (is_file($relativepath)) {
930                     array_push($this->_currentincludedir, dirname($relativepath));
931                     return $relativepath;
932                 }
933             }
b5a2f8 934
7fe908 935             //* ..then check for relative path for all additional given paths..
MC 936             if (!empty($this->OPTIONS['INCLUDE_PATHS'])) {
937                 foreach ($this->OPTIONS['INCLUDE_PATHS'] as $currdir) {
938                     $relativepath = realpath($currdir.'/'.$filepath.'/'.$filename);
939                     if (is_file($relativepath)) {
940                         return $relativepath;
941                     }
942                 }
943             }
b5a2f8 944
7fe908 945             //* ..then check path from TEMPLATE_DIR..
MC 946             if (!empty($this->OPTIONS['TEMPLATE_DIR'])) {
947                 $fullpath = realpath($this->OPTIONS['TEMPLATE_DIR'].'/'.$filepath.'/'.$filename);
948                 if (is_file($fullpath)) return $fullpath;
949             }
b5a2f8 950
7fe908 951             //* ..then check relative path from executing php script..
MC 952             $fullpath = realpath($filepath.'/'.$filename);
953             if (is_file($fullpath)) return $fullpath;
b5a2f8 954
7fe908 955             //* ..then check path from template file.
MC 956             if (!empty($this->VLIBTEMPLATE_ROOT)) {
957                 $fullpath = realpath($this->VLIBTEMPLATE_ROOT.'/'.$filepath.'/'.$filename);
958                 if (is_file($fullpath)) return $fullpath;
959             }
b5a2f8 960
7fe908 961             return false; // uh oh, file not found
MC 962         }
b5a2f8 963
7fe908 964         /**
MC 965          * Modifies the array $arr to add Template variables, __FIRST__, __LAST__ ..etc
966          * if $this->OPTIONS['LOOP_CONTEXT_VARS'] is true.
967          * Used by $this->setloop().
968          * @param array $arr
969          * @return array new look array
970          * @access private
971          */
972         private function _arrayBuild($arr)
973         {
974             if (is_array($arr) && !empty($arr)) {
975                 $arr = array_values($arr); // to prevent problems w/ non sequential arrays
976                 for ($i = 0; $i < count($arr); $i++) {
977                     if(!is_array($arr[$i]))  return false;
978                     foreach ($arr[$i] as $k => $v) {
979                         unset($arr[$i][$k]);
980                         if ($this->OPTIONS['CASELESS']) $k = strtolower($k);
981                         if (preg_match('/^[0-9]+$/', $k)) $k = '_'.$k;
b5a2f8 982
7fe908 983                         if (is_array($v)) {
MC 984                             if (($arr[$i][$k] = $this->_arrayBuild($v)) == false) return false;
985                         } else { // reinsert the var
986                             $arr[$i][$k] = $v;
987                         }
988                     }
989                     if ($this->OPTIONS['LOOP_CONTEXT_VARS']) {
990                         if ($i == 0) $arr[$i]['__FIRST__'] = true;
991                         if (($i + 1) == count($arr)) $arr[$i]['__LAST__'] = true;
992                         if ($i != 0 && (($i + 1) < count($arr))) $arr[$i]['__INNER__'] = true;
993                         if (is_int(($i+1) / 2))  $arr[$i]['__EVEN__'] = true;
994                         if (!is_int(($i+1) / 2))  $arr[$i]['__ODD__'] = true;
995                         $arr[$i]['__ROWNUM__'] = ($i + 1);
996                     }
997                 }
998                 return $arr;
999             } elseif (empty($arr)) {
1000                 return true;
1001             }
1002         }
b5a2f8 1003
7fe908 1004         /**
MC 1005          * returns a string used for parsing in tmpl_if statements.
1006          * @param string $varname
1007          * @param string $value
1008          * @param string $op
1009          * @param string $namespace current namespace
1010          * @access private
1011          * @return string used for eval'ing
1012          */
eca44a 1013         private function _parseIf($varname, $value = null, $op = null, $namespace = null, $format = null)
7fe908 1014         {
MC 1015             if (isset($namespace)) $namespace = substr($namespace, 0, -1);
1016             $comp_str = ''; // used for extended if statements
b5a2f8 1017
7fe908 1018             // work out what to put on the end id value="whatever" is used
MC 1019             if (isset($value)) {
b5a2f8 1020
7fe908 1021                 // add the correct operator depending on whether it's been specified or not
MC 1022                 if (!empty($op)) {
1023                     if (in_array($op, $this->allowed_if_ops)) {
1024                         $comp_str .= $op;
1025                     } else {
1026                         vlibTemplateError::raiseError('VT_WARNING_INVALID_IF_OP', WARNING, $op);
1027                     }
1028                 } else {
1029                     $comp_str .= '==';
1030                 }
b5a2f8 1031
7fe908 1032                 // now we add the value, if it's numeric, then we leave the quotes off
MC 1033                 if (is_numeric($value)) {
1034                     $comp_str .= $value;
1035                 } else {
1036                     $comp_str .= '\''.$value.'\'';
1037                 }
1038             }
b5a2f8 1039
7fe908 1040             if (count($this->_namespace) == 0 || $namespace == 'global') return '$this->_vars[\''.$varname.'\']'.$comp_str;
MC 1041             $retstr = '$this->_arrvars';
1042             $numnamespaces = count($this->_namespace);
1043             for ($i=0; $i < $numnamespaces; $i++) {
1044                 if ($this->_namespace[$i] == $namespace || (($i + 1) == $numnamespaces && !empty($namespace))) {
1045                     $retstr .= "['".$namespace."'][\$_".$i."]";
1046                     break 1;
1047                 } else {
1048                     $retstr .= "['".$this->_namespace[$i]."'][\$_".$i."]";
1049                 }
1050             }
1051             if ($this->OPTIONS['GLOBAL_VARS'] && empty($namespace)) {
eca44a 1052                 $retstr = '(('.$retstr.'[\''.$varname.'\'] !== null) ? '.$retstr.'[\''.$varname.'\'] : $this->_vars[\''.$varname.'\'])';
MC 1053                 if(isset($format) && isset($value) && $format == 'version') {
1054                     return 'version_compare(' . $retstr . ', \'' . $value . '\', \'' . (!empty($op) ? $op : '==') . '\')';
1055                 } else {
1056                     return $retstr.$comp_str;
1057                 }
1058             }
1059             else {
1060                 if(isset($format) && isset($value) && $format == 'version') {
1061                     return 'version_compare(' . $retstr."['".$varname."']" . ', \'' . $value . '\', \'' . (!empty($op) ? $op : '==') . '\')';
1062                 } else {
1063                     return $retstr."['".$varname."']".$comp_str;
1064                 }
7fe908 1065             }
MC 1066         }
b5a2f8 1067
1b9d2f 1068         /**
MB 1069          * returns a string containing hook data
1070          * @param string $type
1071          * @param string $name
1072          * @return string hook data
1073          */
216ea1 1074         private function _parseHook ($name)
1b9d2f 1075         {
MB 1076             global $app;
1077             
216ea1 1078             if(!$name) return false;
1b9d2f 1079             
216ea1 1080             $module = isset($_SESSION['s']['module']['name']) ? $_SESSION['s']['module']['name'] : '';
MB 1081             $form = isset($app->tform->formDef['name']) ? $app->tform->formDef['name'] : '';
1082             
1083             $events = array();
1084             if($module) {
1085                 $events[] = $module . ':' . ($form ? $form : '') . ':' . $name;
1086                 $events[] = $module . ':' . ($form ? $form : '') . ':on_template_content';
1087             } else {
1088                 $events[] = $name;
1089                 $events[] = 'on_template_content';
1090             }
1091             
1092             $events = array_unique($events);
1093             
1094             for($e = 0; $e < count($events); $e++) {
1095                 $tmpresult = $app->plugin->raiseEvent($events[$e], array(
1096                     'name' => $name,
1097                     'module' => $module,
1098                     'form' => $form
1099                 ), true);
1100                 if(!$tmpresult) $tmpresult = '';
1101                 else $tmpresult = $this->_getData($tmpresult, false, true);
1102                 
1103                 $result .= $tmpresult;
1104             }
1b9d2f 1105             
MB 1106             return $result;
1107         }
b5a2f8 1108
7fe908 1109         /**
MC 1110          * returns a string used for parsing in tmpl_loop statements.
1111          * @param string $varname
1112          * @access private
1113          * @return string used for eval'ing
1114          */
1115         private function _parseLoop ($varname)
1116         {
1117             array_push($this->_namespace, $varname);
1118             $tempvar = count($this->_namespace) - 1;
1119             $retstr = "for (\$_".$tempvar."=0 ; \$_".$tempvar." < count(\$this->_arrvars";
1120             for ($i=0; $i < count($this->_namespace); $i++) {
1121                 $retstr .= "['".$this->_namespace[$i]."']";
1122                 if ($this->_namespace[$i] != $varname) $retstr .= "[\$_".$i."]";
1123             }
1124             return $retstr."); \$_".$tempvar."++) {";
1125         }
b5a2f8 1126
7fe908 1127         /**
MC 1128          * returns a string used for parsing in tmpl_var statements.
1129          * @param string $wholetag
1130          * @param string $tag
1131          * @param string $varname
1132          * @param string $escape
1133          * @param string $format
1134          * @param string $namespace
1135          * @access private
1136          * @return string used for eval'ing
1137          */
1138         private function _parseVar ($wholetag, $tag, $varname, $escape, $format, $namespace)
1139         {
1140             if (!empty($namespace)) $namespace = substr($namespace, 0, -1);
1141             $wholetag = stripslashes($wholetag);
b5a2f8 1142
7fe908 1143             if (count($this->_namespace) == 0 || $namespace == 'global') {
MC 1144                 $var1 = '$this->_vars[\''.$varname.'\']';
1145             } else {
1146                 $var1build = "\$this->_arrvars";
1147                 $numnamespaces = count($this->_namespace);
1148                 for ($i=0; $i < $numnamespaces; $i++) {
1149                     if ($this->_namespace[$i] == $namespace || (($i + 1) == $numnamespaces && !empty($namespace))) {
1150                         $var1build .= "['".$namespace."'][\$_".$i."]";
1151                         break 1;
1152                     } else {
1153                         $var1build .= "['".$this->_namespace[$i]."'][\$_".$i."]";
1154                     }
1155                 }
1156                 $var1 = $var1build . "['$varname']";
1157                 if ($this->OPTIONS['GLOBAL_VARS'] && empty($namespace)) {
1158                     $var2 = '$this->_vars[\''.$varname.'\']';
1159                 }
1160             }
b5a2f8 1161
7fe908 1162             $beforevar = '';
MC 1163             $aftervar  = '';
1164             if (!empty($escape)&& isset($this->ESCAPE_TAGS[$escape])) {
1165                 $beforevar .= $this->ESCAPE_TAGS[$escape]['open'];
1166                 $aftervar   = $this->ESCAPE_TAGS[$escape]['close'] . $aftervar;
1167             }
b5a2f8 1168
7fe908 1169             if (!empty($format)&& isset($this->FORMAT_TAGS[$format])) {
MC 1170                 $beforevar .= $this->FORMAT_TAGS[$format]['open'];
1171                 $aftervar   = $this->FORMAT_TAGS[$format]['close'] . $aftervar;
1172             }
b5a2f8 1173
7fe908 1174             //* build return values
MC 1175             $retstr  = 'if ('.$var1.' !== null) { ';
1176             $retstr .= 'print('.$beforevar.$var1.$aftervar.'); ';
1177             $retstr .= '}';
b5a2f8 1178
7fe908 1179             if (@$var2) {
MC 1180                 $retstr .= ' elseif ('.$var2.' !== null) { ';
1181                 $retstr .= 'print('.$beforevar.$var2.$aftervar.'); ';
1182                 $retstr .= '}';
1183             }
b5a2f8 1184
7fe908 1185             switch (strtolower($this->OPTIONS['UNKNOWNS'])) {
MC 1186             case 'comment':
1187                 $comment = addcslashes('<!-- unknown variable '.preg_replace('/<!--|-->/', '', $wholetag).'//-->', '"');
1188                 $retstr .= ' else { print("'.$comment.'"); $this->_setUnknown("'.$varname.'"); }';
1189                 return $retstr;
d9bb62 1190
7fe908 1191             case 'leave':
MC 1192                 $retstr .= ' else { print("'.addcslashes($wholetag, '"').'"); $this->_setUnknown("'.$varname.'"); }';
1193                 return $retstr;
d9bb62 1194
7fe908 1195             case 'print':
MC 1196                 $retstr .= ' else { print("'.htmlspecialchars($wholetag, ENT_QUOTES).'"); $this->_setUnknown("'.$varname.'"); }';
1197                 return $retstr;
b5a2f8 1198
7fe908 1199             case 'ignore':
MC 1200                 return $retstr;
d9bb62 1201
7fe908 1202             case 'remove':
MC 1203             default:
1204                 $retstr .= ' else { $this->_setUnknown("'.$varname.'"); }';
1205                 return $retstr;
d9bb62 1206
7fe908 1207             }
MC 1208         }
b5a2f8 1209
7fe908 1210         /**
MC 1211          * takes values from preg_replace in $this->_intparse() and determines
1212          * the replace string.
1213          *
1214          * @param array $args array of all matches found by preg_replace
1215          * @access private
1216          * @return string replace values
1217          */
1218         private function _parseTag ($args)
1219         {
1220             $wholetag = $args[0];
1221             $openclose = $args[1];
1222             $tag = strtolower($args[2]);
eca44a 1223             
MC 1224             if ($tag == 'else') return '<?php } else { ?>';
7fe908 1225             if ($tag == 'tmpl_include') return $wholetag; // ignore tmpl_include tags
b5a2f8 1226
7fe908 1227             if (preg_match("/^<\/|{\/|<!--\/$/s", $openclose) || preg_match("/^end[if|loop|unless|comment]$/", $tag)) {
MC 1228                 if ($tag == 'loop' || $tag == 'endloop') array_pop($this->_namespace);
1229                 if ($tag == 'comment' || $tag == 'endcomment') {
eca44a 1230                     return '<?php */ ?>';
7fe908 1231                 } else {
eca44a 1232                     return '<?php } ?>';
7fe908 1233                 }
MC 1234             }
b5a2f8 1235
eca44a 1236             // arrange attributes
MC 1237             $tmp_atts = $args[3];
1238             $atts = preg_split('/\s+/', $tmp_atts);
1239             foreach($atts as $att) {
1240                 $regex =    '/(?:';
1241                 $regex.=        '(name|format|escape|op|value|file)';
1242                 $regex.=        '\s*=\s*';
1243                 $regex.=    ')?';
1244                 $regex.=    '(?:[\"\'])?';
1245                 $regex.=    '((?<=[\"\'])';
1246                 $regex.=    '[^\"\']*|[a-z0-9_\.]*)';
1247                 $regex.=    '[\"\']?/';
1248                 if(preg_match($regex, $att, $match)) {
1249                     $key = (empty($match[1])) ? 'name' : strtolower($match[1]);
1250                     if ($key == 'name' && preg_match('/^(php)?include$/', $tag)) $key = 'file';
1251                     $$key = $match[2];
1252                 }
7fe908 1253             }
b5a2f8 1254
7fe908 1255             $var = ($this->OPTIONS['CASELESS']) ? strtolower($name) : $name;
b5a2f8 1256
7fe908 1257             if ($this->_debug && !empty($var)) {
MC 1258                 if (preg_match("/^global\.([A-Za-z_]+[_A-Za-z0-9]*)$/", $var, $matches)) $var2 = $matches[1];
1259                 if (empty($this->_debugTemplatevars[$tag])) $this->_debugTemplatevars[$tag] = array();
1260                 if (!isset($var2)) $var2 = $var;
1261                 if (!in_array($var2, $this->_debugTemplatevars[$tag])) array_push($this->_debugTemplatevars[$tag], $var2);
1262             }
b5a2f8 1263
7fe908 1264             if (preg_match("/^([A-Za-z_]+[_A-Za-z0-9]*(\.)+)?([A-Za-z_]+[_A-Za-z0-9]*)$/", $var, $matches)) {
MC 1265                 $var = $matches[3];
1266                 $namespace = $matches[1];
1267             }
b5a2f8 1268
T 1269
7fe908 1270             //* return correct string (tag dependent)
MC 1271             switch ($tag) {
1272             case 'var':
1273                 if (empty($escape) && (!empty($this->OPTIONS['DEFAULT_ESCAPE']) && strtolower($this->OPTIONS['DEFAULT_ESCAPE']) != 'none')) {
1274                     $escape = strtolower($this->OPTIONS['DEFAULT_ESCAPE']);
1275                 }
eca44a 1276                 return '<?php '.$this->_parseVar ($wholetag, $tag, $var, @$escape, @$format, @$namespace)." ?>\n";
b5a2f8 1277
7fe908 1278             case 'if':
eca44a 1279                 return '<?php if ('. $this->_parseIf($var, @$value, @$op, @$namespace, @$format) .') { ?>';
b5a2f8 1280
7fe908 1281             case 'unless':
eca44a 1282                 return '<?php if (!'. $this->_parseIf($var, @$value, @$op, @$namespace, @$format) .') { ?>';
b5a2f8 1283
7fe908 1284             case 'elseif':
eca44a 1285                 return '<?php } elseif ('. $this->_parseIf($var, @$value, @$op, @$namespace, @$format) .') { ?>';
b5a2f8 1286
7fe908 1287             case 'loop':
eca44a 1288                 return '<?php '. $this->_parseLoop($var) .'?>';
b5a2f8 1289
7fe908 1290             case 'comment':
MC 1291                 if (empty($var)) { // full open/close style comment
eca44a 1292                     return '<?php /* ?>';
7fe908 1293                 } else { // just ignore tag if it was a one line comment
MC 1294                     return;
1295                 }
b5a2f8 1296
7fe908 1297             case 'phpinclude':
MC 1298                 if ($this->OPTIONS['ENABLE_PHPINCLUDE']) {
eca44a 1299                     return '<?php include(\''.$file.'\'); ?>';
7fe908 1300                 }
1b9d2f 1301             
MB 1302             case 'hook':
216ea1 1303                 return $this->_parseHook(@$var);
1b9d2f 1304             
7fe908 1305             case 'include':
MC 1306                 return '<?php $this->_getData($this->_fileSearch(\''.$file.'\'), 1); ?>';
b5a2f8 1307
7fe908 1308             case 'dyninclude':
MC 1309                 return '<?php $this->_getData($this->_fileSearch($this->_dyninclude[\''.$name.'\']), 1); ?>';
b5a2f8 1310
7fe908 1311             default:
MC 1312                 if ($this->OPTIONS['STRICT']) vlibTemplateError::raiseError('VT_ERROR_INVALID_TAG', KILL, htmlspecialchars($wholetag, ENT_QUOTES));
1313                 break;
1314             }
b5a2f8 1315
7fe908 1316         }
b5a2f8 1317
7fe908 1318         /**
MC 1319          * Parses $this->_tmplfile into correct format for eval() to work
1320          * Called by $this->_parse(), or $this->fastPrint, this replaces all <tmpl_*> references
1321          * with their correct php representation, i.e. <tmpl_var title> becomes $this->vars['title']
1322          * Sets final parsed file to $this->_tmplfilep.
1323          *
1324          * @access private
1325          * @return boolean true/false
1326          */
1327         private function _intParse ()
1328         {
1329             //$mqrt = get_magic_quotes_runtime();
1330             //set_magic_quotes_runtime(0);
1331             $this->_tmplfilep = '?>'.$this->_getData($this->_tmplfilename).'<?php return true;';
1332             //set_magic_quotes_runtime($mqrt);
1333             return true;
1334         }
b5a2f8 1335
7fe908 1336         /**
MC 1337          * Calls _intParse, and eval()s $this->tmplfilep
1338          * and outputs the results to $this->tmploutput
1339          *
1340          * @param bool compress whether to compress contents
1341          * @access private
1342          * @return boolean true/false
1343          */
1344         private function _parse ($compress = '')
1345         {
1346             if (!$this->_parsed) {
1347                 if ($this->OPTIONS['TIME_PARSE']) $this->_firstparsetime = $this->_getMicroTime();
b5a2f8 1348
7fe908 1349                 $this->_intParse();
MC 1350                 $this->_parsed = true;
1351
1352                 if ($this->OPTIONS['TIME_PARSE']) $this->_totalparsetime = ($this->_getMicroTime() - $this->_firstparsetime);
1353                 if ($this->OPTIONS['TIME_PARSE'] && $this->OPTIONS['GLOBAL_CONTEXT_VARS']) $this->setVar('__PARSE_TIME__', $this->getParseTime());
1354             }
1355
b5a2f8 1356             // ob_start($compress);
7fe908 1357             ob_start();
b5a2f8 1358
7fe908 1359             array_push($this->_currentincludedir, dirname($this->_tmplfilename));
MC 1360             $this->_includedepth++;
1361             $success = @eval($this->_tmplfilep);
1362             $this->_includedepth--;
1363             array_pop($this->_currentincludedir);
b5a2f8 1364
7fe908 1365             if ($this->_debug) $this->doDebug();
MC 1366             if (!$success) vlibTemplateError::raiseError('VT_ERROR_PARSE', FATAL);
1367             $this->_tmploutput .= ob_get_contents();
1368             ob_end_clean();
1369             return true;
1370         }
b5a2f8 1371
7fe908 1372         /**
MC 1373          * Sets one or more of the boolean options 1/0, that control certain actions in the template.
1374          * Use of this function:
1375          * either: vlibTemplate::_setOptions(string option_name, bool option_val [, string option_name, bool option_val ..]);
1376          * or      vlibTemplate::_setOptions(array);
1377          *          with an associative array where the key is the option_name
1378          *          and the value is the option_value.
1379          *
1380          * @param mixed (mulitple)
1381          * @return bool true/false
1382          * @access private
1383          */
1384         private function _setOption()
1385         {
1386             $numargs = func_num_args();
1387             if ($numargs < 1) {
1388                 vlibTemplateError::raiseError('VT_ERROR_WRONG_NO_PARAMS', null, '_setOption()');
1389                 return false;
1390             }
b5a2f8 1391
7fe908 1392             if ($numargs == 1) {
MC 1393                 $options = func_get_arg(1);
1394                 if (is_array($options)) {
1395                     foreach ($options as $k => $v) {
1396                         if ($v != null) {
1397                             if(in_array($k, array_keys($this->OPTIONS))) $this->OPTIONS[$k] = $v;
1398                         } else {
1399                             continue;
1400                         }
1401                     }
1402                 } else {
1403                     vlibTemplateError::raiseError('VT_ERROR_WRONG_NO_PARAMS', null, '_setOption()');
1404                     return false;
1405                 }
1406             }elseif (is_int($numargs / 2)) {
1407                 for ($i = 0; $i < $numargs; $i=($i+2)) {
1408                     $k  = func_get_arg($i);
1409                     $v = func_get_arg(($i+1));
1410                     if ($v != null) {
1411                         if(in_array($k, array_keys($this->OPTIONS))) $this->OPTIONS[$k] = $v;
1412                     }
1413                 }
1414             } else {
1415                 vlibTemplateError::raiseError('VT_ERROR_WRONG_NO_PARAMS', null, '_setOption()');
1416                 return false;
1417             }
1418             return true;
1419         }
b5a2f8 1420
7fe908 1421         /**
MC 1422          * Used during parsing, this function sets an unknown var checking to see if it
1423          * has been previously set.
1424          * @param string var
1425          * @access private
1426          */
1427         private function _setUnknown($var)
1428         {
1429             if (!in_array($var, $this->_unknowns)) array_push($this->_unknowns, $var);
1430         }
b5a2f8 1431
7fe908 1432         /**
MC 1433          * Returns microtime as a float number
1434          * @return float microtime
1435          * @access private
1436          */
1437         private function _getMicrotime()
1438         {
1439             list($msec, $sec) = explode(' ', microtime());
1440             return (float)$msec + (float)$sec;
1441         }
b5a2f8 1442
7fe908 1443         /**
MC 1444          * Returns str encoded to hex code.
1445          * @param string str to be encoded
1446          * @param bool true/false specify whether to use hex_entity
1447          * @return string encoded in hex
1448          * @access private
1449          */
1450         private  function _escape_hex($str = '', $entity = false) {
1451             $prestr = $entity ? '&#x' : '%';
1452             $poststr= $entity ? ';' : '';
1453             for ($i=0; $i < strlen($str); $i++) {
1454                 $return .= $prestr.bin2hex($str[$i]).$poststr;
1455             }
1456             return $return;
1457         }
b5a2f8 1458
7fe908 1459         /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
b5a2f8 1460     The following functions have no use and are included just so that if the user
T 1461     is making use of vlibTemplateCache functions, this doesn't crash when changed to
1462     vlibTemplate if the user is quickly bypassing the vlibTemplateCache class.
1463     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
7fe908 1464         function clearCache()        {vlibTemplateError::raiseError('VT_WARNING_NOT_CACHE_OBJ', WARNING, 'clearCache()');}
b5a2f8 1465
7fe908 1466         function recache()           {vlibTemplateError::raiseError('VT_WARNING_NOT_CACHE_OBJ', WARNING, 'recache()');}
MC 1467
1468         function setCacheLifeTime()  {vlibTemplateError::raiseError('VT_WARNING_NOT_CACHE_OBJ', WARNING, 'setCacheLifeTime()');}
1469
1470         function setCacheExtension() {vlibTemplateError::raiseError('VT_WARNING_NOT_CACHE_OBJ', WARNING, 'setCacheExtension()');}
1471
1472     } // << end class Def
1473
1474     //include_once (ISPC_CLASS_PATH.'/vlibTemplate/debug.php');
1475     include_once ISPC_CLASS_PATH.'/tpl_cache.inc.php';
b5a2f8 1476
T 1477 } // << end if(!defined())..
7fe908 1478 ?>