1
0

vlibTemplate.php 58 KB

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