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