]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - XTemplate/xtpl.php
Release 6.4.0
[Github/sugarcrm.git] / XTemplate / xtpl.php
1 <?php
2
3 /*
4
5 Modification information for LGPL compliance
6 Stas 2010-12-20 Added 'VERSION_MARK' to templates
7
8 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
9
10 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
11
12 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
13
14 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system
15
16 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
17
18 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
19
20 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
21
22 r36874 - 2008-06-19 12:09:05 -0700 (Thu, 19 Jun 2008) - roger - bug 22568: use md5 of unique key and version for js key.
23
24 r32524 - 2008-03-06 15:51:02 -0800 (Thu, 06 Mar 2008) - dwong - Fix incorrect encoding on source code caused by IDE, e.g.
25 utils.php r3048
26 InboundEmail.php r17199
27 header.php r13729
28
29 r30876 - 2008-01-09 19:01:57 -0800 (Wed, 09 Jan 2008) - majed - initial check in for instances
30
31 r29571 - 2007-11-13 10:49:09 -0800 (Tue, 13 Nov 2007) - eddy - Bug 17113
32 Added check for array element prior to accessing it.
33 XTemplate/xtpl.php
34
35 r26822 - 2007-09-18 10:20:27 -0700 (Tue, 18 Sep 2007) - tswicegood - Refactor a bunch of the loops and such.
36 This code doesn't have a future in Sugar, but there are some legacy
37 areas that still rely on it.  Refactoring these few areas cuts its impact
38 on Sugar's main page by 40% (6.14% to 3.72%).
39
40 r26819 - 2007-09-18 10:07:01 -0700 (Tue, 18 Sep 2007) - tswicegood - Reduces this execution time relatively by 25%
41
42 r25238 - 2007-08-07 15:40:32 -0700 (Tue, 07 Aug 2007) - dwheeler - Bug 14129. Removed field from vardefs as it is no longer used, and should not be visible from mass update.
43
44 r18355 - 2006-12-05 17:00:55 -0800 (Tue, 05 Dec 2006) - jenny - Bug 10292 - checking to see if we actually have an array before setting the array values.
45
46 r13627 - 2006-05-31 11:01:53 -0700 (Wed, 31 May 2006) - majed - name change
47
48 r12024 - 2006-03-09 23:42:27 -0800 (Thu, 09 Mar 2006) - majed - fixes bugs 4449 5050 4063 4976 4770
49
50 r11291 - 2006-01-22 10:41:45 -0800 (Sun, 22 Jan 2006) - andrew - Removed the 'Log' CVS keyword.
51
52 r10797 - 2005-12-21 18:10:38 -0800 (Wed, 21 Dec 2005) - wayne - sugar_version and js_custom_version xtpl assignment now in xtpl.php
53
54 r9351 - 2005-11-15 15:39:37 -0800 (Tue, 15 Nov 2005) - andrew - Added another check for the $focus that needs to be in for PHP 5.0.3.
55
56 r9270 - 2005-11-11 15:08:19 -0800 (Fri, 11 Nov 2005) - majed - Adds support for emails email marketing and email templates
57
58 r8555 - 2005-10-19 12:26:13 -0700 (Wed, 19 Oct 2005) - majed - adds initial acl support
59
60 r8508 - 2005-10-17 17:23:04 -0700 (Mon, 17 Oct 2005) - majed - adds initial acl support
61
62 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
63
64 r4920 - 2005-04-29 00:38:19 -0700 (Fri, 29 Apr 2005) - jacob - Preventing conversion of array to string.
65
66 r4743 - 2005-04-27 00:57:27 -0700 (Wed, 27 Apr 2005) - jacob - Adding support for "parsing" sections that do not exist in HTML.  This provides backwards compatibility for old HTML files with new PHP files.
67
68 r2016 - 2004-12-28 15:19:29 -0800 (Tue, 28 Dec 2004) - majed - added a function to scan through a block checking for a given variable
69
70 r1228 - 2004-10-20 02:09:09 -0700 (Wed, 20 Oct 2004) - lam - update
71
72 r1211 - 2004-10-19 21:55:03 -0700 (Tue, 19 Oct 2004) - lam - update
73
74 r730 - 2004-09-09 20:14:02 -0700 (Thu, 09 Sep 2004) - sugarjacob - Cleaning up blanks
75
76 r462 - 2004-08-25 17:43:37 -0700 (Wed, 25 Aug 2004) - sugarmsi - added an exists method to check if a block exists in a template
77
78 r397 - 2004-08-08 02:28:36 -0700 (Sun, 08 Aug 2004) - sugarjacob - Fix: XTemplate changed to use <?php script declarations
79
80 r297 - 2004-07-31 15:13:23 -0700 (Sat, 31 Jul 2004) - sugarjacob - Removing default setting of template language arrays.
81
82 r295 - 2004-07-31 14:37:38 -0700 (Sat, 31 Jul 2004) - sugarjacob - Adding code to automatically assign the language strings to every template created.
83
84 r268 - 2004-07-16 01:21:57 -0700 (Fri, 16 Jul 2004) - sugarjacob - Changing the XTemplate replacement mechanism to allow for '$' in the text being substituted.
85
86 r80 - 2004-06-11 16:39:47 -0700 (Fri, 11 Jun 2004) - sugarjacob - Fixing issue with a variable not being an array in some cases.
87
88 r78 - 2004-06-11 16:34:17 -0700 (Fri, 11 Jun 2004) - sugarjacob - Removing errors or notices about invalid indexs.
89
90 r3 - 2004-05-26 22:30:56 -0700 (Wed, 26 May 2004) - sugarjacob - Moving project to SourceForge.
91
92
93 */
94
95
96
97 class XTemplate {
98
99 /*
100         xtemplate class 0.2.4-3
101         html generation with templates - fast & easy
102         copyright (c) 2000 barnabás debreceni [cranx@users.sourceforge.net]
103         code optimization by Ivar Smolin <okul@linux.ee> 14-march-2001
104         latest stable & CVS version always available @ http://sourceforge.net/projects/xtpl
105
106         tested with php 3.0.11 and 4.0.4pl1
107
108         This program is free software; you can redistribute it and/or
109         modify it under the terms of the GNU Lesser General Public License
110         version 2.1 as published by the Free Software Foundation.
111
112         This library is distributed in the hope that it will be useful,
113         but WITHOUT ANY WARRANTY; without even the implied warranty of
114         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
115         GNU Lesser General Public License for more details at
116         http://www.gnu.org/copyleft/lgpl.html
117
118         You should have received a copy of the GNU General Public License
119         along with this program; if not, write to the Free Software
120         Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
121
122
123 */
124
125 /***[ variables ]***********************************************************/
126
127 var $filecontents="";                                                           /* raw contents of template file */
128 var $blocks=array();                                                            /* unparsed blocks */
129 var $parsed_blocks=array();                                     /* parsed blocks */
130 var $block_parse_order=array();                 /* block parsing order for recursive parsing (sometimes reverse:) */
131 var $sub_blocks=array();                                                /* store sub-block names for fast resetting */
132 var $VARS=array();                                                                      /* variables array */
133 var $alternate_include_directory = "";
134
135 var $file_delim="/\{FILE\s*\"([^\"]+)\"\s*\}/m";  /* regexp for file includes */
136 var $block_start_delim="<!-- ";                 /* block start delimiter */
137 var $block_end_delim="-->";                                     /* block end delimiter */
138 var $block_start_word="BEGIN:";                 /* block start word */
139 var $block_end_word="END:";                                     /* block end word */
140
141 /* this makes the delimiters look like: <!-- BEGIN: block_name --> if you use my syntax. */
142
143 var $NULL_STRING=array(""=>"");                         /* null string for unassigned vars */
144 var $NULL_BLOCK=array(""=>"");  /* null string for unassigned blocks */
145 var $mainblock="";
146 var $ERROR="";
147 var $AUTORESET=1;                                                                               /* auto-reset sub blocks */
148
149 /***[ constructor ]*********************************************************/
150
151 function XTemplate ($file, $alt_include = "", $mainblock="main") {
152         $this->alternate_include_directory = $alt_include;
153         $this->mainblock=$mainblock;
154         $this->filecontents=$this->r_getfile($file);    /* read in template file */
155         //if(substr_count($file, 'backup') == 1)_ppd($this->filecontents);
156         $this->blocks=$this->maketree($this->filecontents,$mainblock);  /* preprocess some stuff */
157         //$this->scan_globals();
158 }
159
160
161 /***************************************************************************/
162 /***[ public stuff ]********************************************************/
163 /***************************************************************************/
164
165
166 /***[ assign ]**************************************************************/
167 /*
168         assign a variable
169 */
170
171 function assign ($name,$val="") {
172         if (is_array($name)) {
173                 foreach ($name as $k => $v) {
174                         $this->VARS[$k] = $v;
175                 }
176         } else {
177                 $this->VARS[$name]=$val;
178         }
179 }
180
181 function append ($varname, $name,$val="") {
182         if(!isset($this->VARS[$varname])){
183                 $this->VARS[$varname] = array();
184         }
185    if(is_array($this->VARS[$varname])){
186        $this->VARS[$varname][$name] = $val;
187     }
188 }
189
190 /***[ parse ]***************************************************************/
191 /*
192         parse a block
193 */
194
195 function parse ($bname) {
196         global $sugar_version, $sugar_config;
197
198         $this->assign('SUGAR_VERSION', $GLOBALS['js_version_key']);
199         $this->assign('JS_CUSTOM_VERSION', $sugar_config['js_custom_version']);
200     $this->assign('VERSION_MARK', getVersionedPath(''));
201
202         if(empty($this->blocks[$bname]))
203                 return;
204
205         $copy=$this->blocks[$bname];
206         if (!isset($this->blocks[$bname]))
207                 $this->set_error ("parse: blockname [$bname] does not exist");
208         preg_match_all("/\{([A-Za-z0-9\._]+?)}/",$this->blocks[$bname],$var_array);
209         $var_array=$var_array[1];
210         foreach ($var_array as $k => $v) {
211                 $sub=explode(".",$v);
212                 if ($sub[0]=="_BLOCK_") {
213                         unset($sub[0]);
214                         $bname2=implode(".",$sub);
215
216                         if(isset($this->parsed_blocks[$bname2]))
217                         {
218                                 $var=$this->parsed_blocks[$bname2];
219                         }
220                         else
221                         {
222                                 $var = null;
223                         }
224
225                         $nul=(!isset($this->NULL_BLOCK[$bname2])) ? $this->NULL_BLOCK[""] : $this->NULL_BLOCK[$bname2];
226                         $var=(empty($var))?$nul:trim($var);
227                         // Commented out due to regular expression issue with '$' in replacement string.
228                         //$copy=preg_replace("/\{".$v."\}/","$var",$copy);
229                         // This should be faster and work better for '$'
230                         $copy=str_replace("{".$v."}",$var,$copy);
231                 } else {
232                         $var=$this->VARS;
233
234                         foreach ($sub as $k1 => $v1)
235                         {
236                                 if(is_array($var) && isset($var[$v1]))
237                                 {
238                                         $var=$var[$v1];
239                                 }
240                                 else
241                                 {
242                                         $var = null;
243                                 }
244                         }
245
246                         $nul=(!isset($this->NULL_STRING[$v])) ? ($this->NULL_STRING[""]) : ($this->NULL_STRING[$v]);
247                         $var=(!isset($var))?$nul:$var;
248                         // Commented out due to regular expression issue with '$' in replacement string.
249                         //$copy=preg_replace("/\{$v\}/","$var",$copy);
250                         // This should be faster and work better for '$'
251
252                         // this was periodically returning an array to string conversion error....
253                         if(!is_array($var))
254                         {
255                                 $copy=str_replace("{".$v."}",$var,$copy);
256                         }
257                 }
258         }
259
260         if(isset($this->parsed_blocks[$bname]))
261         {
262                 $this->parsed_blocks[$bname].=$copy;
263         }
264         else
265         {
266                 $this->parsed_blocks[$bname]=$copy;
267         }
268
269         // reset sub-blocks
270         if ($this->AUTORESET && (!empty($this->sub_blocks[$bname]))) {
271                 reset($this->sub_blocks[$bname]);
272                 foreach ($this->sub_blocks[$bname] as $v)
273                         $this->reset($v);
274         }
275 }
276
277 /***[ exists ]**************************************************************/
278 /*
279         returns true if a block exists otherwise returns false.
280 */
281 function exists($bname){
282         return (!empty($this->parsed_blocks[$bname])) || (!empty($this->blocks[$bname]));
283 }
284
285
286 /***[ var_exists ]**************************************************************/
287 /*
288         returns true if a block exists otherwise returns false.
289 */
290 function var_exists($bname,$vname){
291         if(!empty($this->blocks[$bname])){
292                 return substr_count($this->blocks[$bname], '{'. $vname . '}') >0;
293         }
294         return false;
295 }
296
297
298 /***[ rparse ]**************************************************************/
299 /*
300         returns the parsed text for a block, including all sub-blocks.
301 */
302
303 function rparse($bname) {
304         if (!empty($this->sub_blocks[$bname])) {
305                 reset($this->sub_blocks[$bname]);
306                 while (list($k,$v)=each($this->sub_blocks[$bname]))
307                         if (!empty($v))
308                                 $this->rparse($v,$indent."\t");
309         }
310         $this->parse($bname);
311 }
312
313 /***[ insert_loop ]*********************************************************/
314 /*
315         inserts a loop ( call assign & parse )
316 */
317
318 function insert_loop($bname,$var,$value="") {
319         $this->assign($var,$value);
320         $this->parse($bname);
321 }
322
323 /***[ text ]****************************************************************/
324 /*
325         returns the parsed text for a block
326 */
327
328 function text($bname) {
329
330     if(!empty($this->parsed_blocks)){
331            return $this->parsed_blocks[isset($bname) ? $bname :$this->mainblock];
332     }else{
333         return '';
334     }
335 }
336
337 /***[ out ]*****************************************************************/
338 /*
339         prints the parsed text
340 */
341
342 function out ($bname) {
343         global $focus;
344
345         if(isset($focus)){
346                 global $action;
347
348                 if($focus && is_subclass_of($focus, 'SugarBean') && !$focus->ACLAccess($action)){
349
350                         ACLController::displayNoAccess(true);
351
352                         sugar_die('');
353                         return;
354         }}
355
356         echo $this->text($bname);
357 }
358
359 /***[ reset ]***************************************************************/
360 /*
361         resets the parsed text
362 */
363
364 function reset ($bname) {
365         $this->parsed_blocks[$bname]="";
366 }
367
368 /***[ parsed ]**************************************************************/
369 /*
370         returns true if block was parsed, false if not
371 */
372
373 function parsed ($bname) {
374         return (!empty($this->parsed_blocks[$bname]));
375 }
376
377 /***[ SetNullString ]*******************************************************/
378 /*
379         sets the string to replace in case the var was not assigned
380 */
381
382 function SetNullString($str,$varname="") {
383         $this->NULL_STRING[$varname]=$str;
384 }
385
386 /***[ SetNullBlock ]********************************************************/
387 /*
388         sets the string to replace in case the block was not parsed
389 */
390
391 function SetNullBlock($str,$bname="") {
392         $this->NULL_BLOCK[$bname]=$str;
393 }
394
395 /***[ set_autoreset ]*******************************************************/
396 /*
397         sets AUTORESET to 1. (default is 1)
398         if set to 1, parse() automatically resets the parsed blocks' sub blocks
399         (for multiple level blocks)
400 */
401
402 function set_autoreset() {
403         $this->AUTORESET=1;
404 }
405
406 /***[ clear_autoreset ]*****************************************************/
407 /*
408         sets AUTORESET to 0. (default is 1)
409         if set to 1, parse() automatically resets the parsed blocks' sub blocks
410         (for multiple level blocks)
411 */
412
413 function clear_autoreset() {
414         $this->AUTORESET=0;
415 }
416
417 /***[ scan_globals ]********************************************************/
418 /*
419         scans global variables
420 */
421
422 function scan_globals() {
423         reset($GLOBALS);
424         while (list($k,$v)=each($GLOBALS))
425                 $GLOB[$k]=$v;
426         $this->assign("PHP",$GLOB);     /* access global variables as {PHP.HTTP_HOST} in your template! */
427 }
428
429 /******
430
431                 WARNING
432                 PUBLIC FUNCTIONS BELOW THIS LINE DIDN'T GET TESTED
433
434 ******/
435
436
437 /***************************************************************************/
438 /***[ private stuff ]*******************************************************/
439 /***************************************************************************/
440
441 /***[ maketree ]************************************************************/
442 /*
443         generates the array containing to-be-parsed stuff:
444   $blocks["main"],$blocks["main.table"],$blocks["main.table.row"], etc.
445         also builds the reverse parse order.
446 */
447
448
449 function maketree($con,$block) {
450         $con2=explode($this->block_start_delim,$con);
451         $level=0;
452         $block_names=array();
453         $blocks=array();
454         reset($con2);
455         while(list($k,$v)=each($con2)) {
456                 $patt="($this->block_start_word|$this->block_end_word)\s*(\w+)\s*$this->block_end_delim(.*)";
457                 if (preg_match_all("/$patt/ims",$v,$res, PREG_SET_ORDER)) {
458                         // $res[0][1] = BEGIN or END
459                         // $res[0][2] = block name
460                         // $res[0][3] = kinda content
461                         if ($res[0][1]==$this->block_start_word) {
462                                 $parent_name=implode(".",$block_names);
463                                 $block_names[++$level]=$res[0][2];                                                      /* add one level - array("main","table","row")*/
464                                 $cur_block_name=implode(".",$block_names);      /* make block name (main.table.row) */
465                                 $this->block_parse_order[]=$cur_block_name;     /* build block parsing order (reverse) */
466
467                                 if(array_key_exists($cur_block_name, $blocks))
468                                 {
469                                         $blocks[$cur_block_name].=$res[0][3];                           /* add contents */
470                                 }
471                                 else
472                                 {
473                                         $blocks[$cur_block_name]=$res[0][3];                            /* add contents */
474                                 }
475
476                                 /* add {_BLOCK_.blockname} string to parent block */
477                                 if(array_key_exists($parent_name, $blocks))
478                                 {
479                                         $blocks[$parent_name].="{_BLOCK_.$cur_block_name}";
480                                 }
481                                 else
482                                 {
483                                         $blocks[$parent_name]="{_BLOCK_.$cur_block_name}";
484                                 }
485
486                                 $this->sub_blocks[$parent_name][]=$cur_block_name;              /* store sub block names for autoresetting and recursive parsing */
487                                 $this->sub_blocks[$cur_block_name][]="";                /* store sub block names for autoresetting */
488                         } else if ($res[0][1]==$this->block_end_word) {
489                                 unset($block_names[$level--]);
490                                 $parent_name=implode(".",$block_names);
491                                 $blocks[$parent_name].=$res[0][3];      /* add rest of block to parent block */
492                         }
493                 } else { /* no block delimiters found */
494                         $index = implode(".",$block_names);
495                         if(array_key_exists($index, $blocks))
496                         {
497                                 $blocks[].=$this->block_start_delim.$v;
498                         }
499                         else
500                         {
501                                 $blocks[]=$this->block_start_delim.$v;
502                         }
503                 }
504         }
505         return $blocks;
506 }
507
508
509
510 /***[ error stuff ]*********************************************************/
511 /*
512         sets and gets error
513 */
514
515 function get_error()    {
516         return ($this->ERROR=="")?0:$this->ERROR;
517 }
518
519
520 function set_error($str)        {
521         $this->ERROR=$str;
522 }
523
524 /***[ getfile ]*************************************************************/
525 /*
526         returns the contents of a file
527 */
528
529 function getfile($file) {
530         if (!isset($file)) {
531                 $this->set_error("!isset file name!");
532                 return "";
533         }
534
535         // Pick which folder we should include from
536         // Prefer the local directory, then try the theme directory.
537         if (!is_file($file))
538                 $file = $this->alternate_include_directory.$file;
539
540         if(is_file($file))
541         {
542                 $file_text=file_get_contents($file);
543
544         } else {
545                 $this->set_error("[$file] does not exist");
546                 $file_text="<b>__XTemplate fatal error: file [$file] does not exist__</b>";
547         }
548
549         return $file_text;
550 }
551
552 /***[ r_getfile ]***********************************************************/
553 /*
554         recursively gets the content of a file with {FILE "filename.tpl"} directives
555 */
556
557
558 function r_getfile($file) {
559         $text=$this->getfile($file);
560         while (preg_match($this->file_delim,$text,$res)) {
561                 $text2=$this->getfile($res[1]);
562                 $text=preg_replace("'".preg_quote($res[0])."'",$text2,$text);
563         }
564         return $text;
565 }
566
567 } /* end of XTemplate class. */
568
569 ?>