source: trunk/www.guidonia.net/wp/wp-content/plugins/tubepress/classes/net/php/pear/HTML/Template/IT.class.php@ 44

Last change on this file since 44 was 44, checked in by luciano, 14 years ago
File size: 31.3 KB
Line 
1<?php
2//
3// +----------------------------------------------------------------------+
4// | Copyright (c) 1997-2005 Ulf Wendel, Pierre-Alain Joye |
5// +----------------------------------------------------------------------+
6// | This source file is subject to the New BSD license, That is bundled |
7// | with this package in the file LICENSE, and is available through |
8// | the world-wide-web at |
9// | http://www.opensource.org/licenses/bsd-license.php |
10// | If you did not receive a copy of the new BSDlicense and are unable |
11// | to obtain it through the world-wide-web, please send a note to |
12// | pajoye@php.net so we can mail you a copy immediately. |
13// +----------------------------------------------------------------------+
14// | Author: Ulf Wendel <ulf.wendel@phpdoc.de> |
15// | Pierre-Alain Joye <pajoye@php.net> |
16// +----------------------------------------------------------------------+
17//
18// $Id: IT.php,v 1.20 2006/08/17 15:47:22 dsp Exp $
19//
20
21function_exists('tubepress_load_classes')
22 || require(dirname(__FILE__) . '/../../../../../tubepress_classloader.php');
23tubepress_load_classes(array('net_php_pear_PEAR'));
24
25define('IT_OK', 1);
26define('IT_ERROR', -1);
27define('IT_TPL_NOT_FOUND', -2);
28define('IT_BLOCK_NOT_FOUND', -3);
29define('IT_BLOCK_DUPLICATE', -4);
30define('IT_UNKNOWN_OPTION', -6);
31/**
32 * Integrated Template - IT
33 *
34 * Well there's not much to say about it. I needed a template class that
35 * supports a single template file with multiple (nested) blocks inside and
36 * a simple block API.
37 *
38 * The Isotemplate API is somewhat tricky for a beginner although it is the best
39 * one you can build. template::parse() [phplib template = Isotemplate] requests
40 * you to name a source and a target where the current block gets parsed into.
41 * Source and target can be block names or even handler names. This API gives you
42 * a maximum of fexibility but you always have to know what you do which is
43 * quite unusual for php skripter like me.
44 *
45 * I noticed that I do not any control on which block gets parsed into which one.
46 * If all blocks are within one file, the script knows how they are nested and in
47 * which way you have to parse them. IT knows that inner1 is a child of block2, there's
48 * no need to tell him about this.
49 *
50 * <table border>
51 * <tr>
52 * <td colspan=2>
53 * __global__
54 * <p>
55 * (hidden and automatically added)
56 * </td>
57 * </tr>
58 * <tr>
59 * <td>block1</td>
60 * <td>
61 * <table border>
62 * <tr>
63 * <td colspan=2>block2</td>
64 * </tr>
65 * <tr>
66 * <td>inner1</td>
67 * <td>inner2</td>
68 * </tr>
69 * </table>
70 * </td>
71 * </tr>
72 * </table>
73 *
74 * To add content to block1 you simply type:
75 * <code>$tpl->setCurrentBlock("block1");</code>
76 * and repeat this as often as needed:
77 * <code>
78 * $tpl->setVariable(...);
79 * $tpl->parseCurrentBlock();
80 * </code>
81 *
82 * To add content to block2 you would type something like:
83 * <code>
84 * $tpl->setCurrentBlock("inner1");
85 * $tpl->setVariable(...);
86 * $tpl->parseCurrentBlock();
87 *
88 * $tpl->setVariable(...);
89 * $tpl->parseCurrentBlock();
90 *
91 * $tpl->parse("block1");
92 * </code>
93 *
94 * This will result in one repition of block1 which contains two repitions
95 * of inner1. inner2 will be removed if $removeEmptyBlock is set to true which is the default.
96 *
97 * Usage:
98 * <code>
99 * $tpl = new HTML_Template_IT( [string filerootdir] );
100 *
101 * // load a template or set it with setTemplate()
102 * $tpl->loadTemplatefile( string filename [, boolean removeUnknownVariables, boolean removeEmptyBlocks] )
103 *
104 * // set "global" Variables meaning variables not beeing within a (inner) block
105 * $tpl->setVariable( string variablename, mixed value );
106 *
107 * // like with the Isotemplates there's a second way to use setVariable()
108 * $tpl->setVariable( array ( string varname => mixed value ) );
109 *
110 * // Let's use any block, even a deeply nested one
111 * $tpl->setCurrentBlock( string blockname );
112 *
113 * // repeat this as often as you need it.
114 * $tpl->setVariable( array ( string varname => mixed value ) );
115 * $tpl->parseCurrentBlock();
116 *
117 * // get the parsed template or print it: $tpl->show()
118 * $tpl->get();
119 * </code>
120 *
121 * @author Ulf Wendel <uw@netuse.de>
122 * @version $Id: IT.php,v 1.20 2006/08/17 15:47:22 dsp Exp $
123 * @access public
124 * @package HTML_Template_IT
125 */
126class net_php_pear_HTML_Template_IT
127{
128 /**
129 * Contains the error objects
130 * @var array
131 * @access public
132 * @see halt(), $printError, $haltOnError
133 */
134 var $err = array();
135
136 /**
137 * Clear cache on get()?
138 * @var boolean
139 */
140 var $clearCache = false;
141
142 /**
143 * First character of a variable placeholder ( _{_VARIABLE} ).
144 * @var string
145 * @access public
146 * @see $closingDelimiter, $blocknameRegExp, $variablenameRegExp
147 */
148 var $openingDelimiter = '{';
149
150 /**
151 * Last character of a variable placeholder ( {VARIABLE_}_ ).
152 * @var string
153 * @access public
154 * @see $openingDelimiter, $blocknameRegExp, $variablenameRegExp
155 */
156 var $closingDelimiter = '}';
157
158 /**
159 * RegExp matching a block in the template.
160 * Per default "sm" is used as the regexp modifier, "i" is missing.
161 * That means a case sensitive search is done.
162 * @var string
163 * @access public
164 * @see $variablenameRegExp, $openingDelimiter, $closingDelimiter
165 */
166 var $blocknameRegExp = '[\.0-9A-Za-z_-]+';
167
168 /**
169 * RegExp matching a variable placeholder in the template.
170 * Per default "sm" is used as the regexp modifier, "i" is missing.
171 * That means a case sensitive search is done.
172 * @var string
173 * @access public
174 * @see $blocknameRegExp, $openingDelimiter, $closingDelimiter
175 */
176 var $variablenameRegExp = '[\.0-9A-Za-z_-]+';
177
178 /**
179 * RegExp used to find variable placeholder, filled by the constructor.
180 * @var string Looks somewhat like @(delimiter varname delimiter)@
181 * @access public
182 * @see IntegratedTemplate()
183 */
184 var $variablesRegExp = '';
185
186 /**
187 * RegExp used to strip unused variable placeholder.
188 * @brother $variablesRegExp
189 */
190 var $removeVariablesRegExp = '';
191
192 /**
193 * Controls the handling of unknown variables, default is remove.
194 * @var boolean
195 * @access public
196 */
197 var $removeUnknownVariables = true;
198
199 /**
200 * Controls the handling of empty blocks, default is remove.
201 * @var boolean
202 * @access public
203 */
204 var $removeEmptyBlocks = true;
205
206 /**
207 * RegExp used to find blocks an their content, filled by the constructor.
208 * @var string
209 * @see IntegratedTemplate()
210 */
211 var $blockRegExp = '';
212
213 /**
214 * Name of the current block.
215 * @var string
216 */
217 var $currentBlock = '__global__';
218
219 /**
220 * Content of the template.
221 * @var string
222 */
223 var $template = '';
224
225 /**
226 * Array of all blocks and their content.
227 *
228 * @var array
229 * @see findBlocks()
230 */
231 var $blocklist = array();
232
233 /**
234 * Array with the parsed content of a block.
235 *
236 * @var array
237 */
238 var $blockdata = array();
239
240 /**
241 * Array of variables in a block.
242 * @var array
243 */
244 var $blockvariables = array();
245
246 /**
247 * Array of inner blocks of a block.
248 * @var array
249 */
250 var $blockinner = array();
251
252 /**
253 * List of blocks to preverse even if they are "empty".
254 *
255 * This is something special. Sometimes you have blocks that
256 * should be preserved although they are empty (no placeholder replaced).
257 * Think of a shopping basket. If it's empty you have to drop a message to
258 * the user. If it's filled you have to show the contents of
259 * the shopping baseket. Now where do you place the message that the basket
260 * is empty? It's no good idea to place it in you applications as customers
261 * tend to like unecessary minor text changes. Having another template file
262 * for an empty basket means that it's very likely that one fine day
263 * the filled and empty basket templates have different layout. I decided
264 * to introduce blocks that to not contain any placeholder but only
265 * text such as the message "Your shopping basked is empty".
266 *
267 * Now if there is no replacement done in such a block the block will
268 * be recognized as "empty" and by default ($removeEmptyBlocks = true) be
269 * stripped off. To avoid thisyou can now call touchBlock() to avoid this.
270 *
271 * The array $touchedBlocks stores a list of touched block which must not
272 * be removed even if they are empty.
273 *
274 * @var array $touchedBlocks
275 * @see touchBlock(), $removeEmptyBlocks
276 */
277 var $touchedBlocks = array();
278
279 /**
280 * List of blocks which should not be shown even if not "empty"
281 * @var array $_hiddenBlocks
282 * @see hideBlock(), $removeEmptyBlocks
283 */
284 var $_hiddenBlocks = array();
285
286 /**
287 * Variable cache.
288 *
289 * Variables get cached before any replacement is done.
290 * Advantage: empty blocks can be removed automatically.
291 * Disadvantage: might take some more memory
292 *
293 * @var array
294 * @see setVariable(), $clearCacheOnParse
295 */
296 var $variableCache = array();
297
298 /**
299 * Clear the variable cache on parse?
300 *
301 * If you're not an expert just leave the default false.
302 * True reduces memory consumption somewhat if you tend to
303 * add lots of values for unknown placeholder.
304 *
305 * @var boolean
306 */
307 var $clearCacheOnParse = false;
308
309 /**
310 * Root directory for all file operations.
311 * The string gets prefixed to all filenames given.
312 * @var string
313 * @see HTML_Template_IT(), setRoot()
314 */
315 var $fileRoot = '';
316
317 /**
318 * Internal flag indicating that a blockname was used multiple times.
319 * @var boolean
320 */
321 var $flagBlocktrouble = false;
322
323 /**
324 * Flag indicating that the global block was parsed.
325 * @var boolean
326 */
327 var $flagGlobalParsed = false;
328
329 /**
330 * EXPERIMENTAL! FIXME!
331 * Flag indication that a template gets cached.
332 *
333 * Complex templates require some times to be preparsed
334 * before the replacement can take place. Often I use
335 * one template file over and over again but I don't know
336 * before that I will use the same template file again.
337 * Now IT could notice this and skip the preparse.
338 *
339 * @var boolean
340 */
341 var $flagCacheTemplatefile = true;
342
343 /**
344 * EXPERIMENTAL! FIXME!
345 */
346 var $lastTemplatefile = '';
347
348 /**
349 * $_options['preserve_data'] Whether to substitute variables and remove
350 * empty placeholders in data passed through setVariable
351 * (see also bugs #20199, #21951).
352 * $_options['use_preg'] Whether to use preg_replace instead of
353 * str_replace in parse()
354 * (this is a backwards compatibility feature, see also bugs #21951, #20392)
355 */
356 var $_options = array(
357 'preserve_data' => false,
358 'use_preg' => true
359 );
360
361 /**
362 * Builds some complex regular expressions and optinally sets the
363 * file root directory.
364 *
365 * Make sure that you call this constructor if you derive your template
366 * class from this one.
367 *
368 * @param string File root directory, prefix for all filenames
369 * given to the object.
370 * @see setRoot()
371 */
372 function net_php_pear_HTML_Template_IT($root = '', $options = null)
373 {
374 if (!is_null($options)) {
375 $this->setOptions($options);
376 }
377 $this->variablesRegExp = '@' . $this->openingDelimiter .
378 '(' . $this->variablenameRegExp . ')' .
379 $this->closingDelimiter . '@sm';
380 $this->removeVariablesRegExp = '@' . $this->openingDelimiter .
381 "\s*(" . $this->variablenameRegExp .
382 ")\s*" . $this->closingDelimiter .'@sm';
383
384 $this->blockRegExp = '@<!--\s+BEGIN\s+(' . $this->blocknameRegExp .
385 ')\s+-->(.*)<!--\s+END\s+\1\s+-->@sm';
386
387 $this->setRoot($root);
388 } // end constructor
389
390
391 /**
392 * Sets the option for the template class
393 *
394 * @access public
395 * @param string option name
396 * @param mixed option value
397 * @return mixed IT_OK on success, error object on failure
398 */
399 function setOption($option, $value)
400 {
401 if (array_key_exists($option, $this->_options)) {
402 $this->_options[$option] = $value;
403 return IT_OK;
404 }
405
406 throw new Exception(
407 $this->errorMessage(IT_UNKNOWN_OPTION) . ": '{$option}'",
408 IT_UNKNOWN_OPTION
409 );
410 }
411
412 /**
413 * Sets the options for the template class
414 *
415 * @access public
416 * @param string options array of options
417 * default value:
418 * 'preserve_data' => false,
419 * 'use_preg' => true
420 * @param mixed option value
421 * @return mixed IT_OK on success, error object on failure
422 * @see $options
423 */
424 function setOptions($options)
425 {
426 if (is_array($options)) {
427 foreach ($options as $option => $value) {
428 $error = $this->setOption($option, $value);
429 if (net_php_pear_PEAR::isError($error)) {
430 return $error;
431 }
432 }
433 }
434
435 return IT_OK;
436 }
437
438 /**
439 * Print a certain block with all replacements done.
440 * @brother get()
441 */
442 function show($block = '__global__')
443 {
444 print $this->get($block);
445 } // end func show
446
447 /**
448 * Returns a block with all replacements done.
449 *
450 * @param string name of the block
451 * @return string
452 * @throws PEAR_Error
453 * @access public
454 * @see show()
455 */
456 function get($block = '__global__')
457 {
458 if ($block == '__global__' && !$this->flagGlobalParsed) {
459 $this->parse('__global__');
460 }
461
462 if (!isset($this->blocklist[$block])) {
463 $this->err[] = net_php_pear_PEAR::raiseError(
464 $this->errorMessage(IT_BLOCK_NOT_FOUND) .
465 '"' . $block . "'",
466 IT_BLOCK_NOT_FOUND
467 );
468 return '';
469 }
470
471 if (isset($this->blockdata[$block])) {
472 $ret = $this->blockdata[$block];
473 if ($this->clearCache) {
474 unset($this->blockdata[$block]);
475 }
476 if ($this->_options['preserve_data']) {
477 $ret = str_replace(
478 $this->openingDelimiter .
479 '%preserved%' . $this->closingDelimiter,
480 $this->openingDelimiter,
481 $ret
482 );
483 }
484 return $ret;
485 }
486
487 return '';
488 } // end func get()
489
490 /**
491 * Parses the given block.
492 *
493 * @param string name of the block to be parsed
494 * @access public
495 * @see parseCurrentBlock()
496 * @throws PEAR_Error
497 */
498 function parse($block = '__global__', $flag_recursion = false)
499 {
500 static $regs, $values;
501
502 if (!isset($this->blocklist[$block])) {
503 throw new Exception(
504 $this->errorMessage( IT_BLOCK_NOT_FOUND ) . '"' . $block . "'",
505 IT_BLOCK_NOT_FOUND
506 );
507 }
508
509 if ($block == '__global__') {
510 $this->flagGlobalParsed = true;
511 }
512
513 if (!$flag_recursion) {
514 $regs = array();
515 $values = array();
516 }
517 $outer = $this->blocklist[$block];
518 $empty = true;
519
520 if ($this->clearCacheOnParse) {
521 foreach ($this->variableCache as $name => $value) {
522 $regs[] = $this->openingDelimiter .
523 $name . $this->closingDelimiter;
524 $values[] = $value;
525 $empty = false;
526 }
527 $this->variableCache = array();
528 } else {
529 foreach ($this->blockvariables[$block] as $allowedvar => $v) {
530
531 if (isset($this->variableCache[$allowedvar])) {
532 $regs[] = $this->openingDelimiter .
533 $allowedvar . $this->closingDelimiter;
534 $values[] = $this->variableCache[$allowedvar];
535 unset($this->variableCache[$allowedvar]);
536 $empty = false;
537 }
538 }
539 }
540
541 if (isset($this->blockinner[$block])) {
542 foreach ($this->blockinner[$block] as $k => $innerblock) {
543
544 $this->parse($innerblock, true);
545 if ($this->blockdata[$innerblock] != '') {
546 $empty = false;
547 }
548
549 $placeholder = $this->openingDelimiter . "__" .
550 $innerblock . "__" . $this->closingDelimiter;
551 $outer = str_replace(
552 $placeholder,
553 $this->blockdata[$innerblock], $outer
554 );
555 $this->blockdata[$innerblock] = "";
556 }
557
558 }
559
560 if (!$flag_recursion && 0 != count($values)) {
561 if ($this->_options['use_preg']) {
562 $regs = array_map(array(
563 &$this, '_addPregDelimiters'),
564 $regs
565 );
566 $funcReplace = 'preg_replace';
567 } else {
568 $funcReplace = 'str_replace';
569 }
570
571 if ($this->_options['preserve_data']) {
572 $values = array_map(
573 array(&$this, '_preserveOpeningDelimiter'), $values
574 );
575 }
576
577 $outer = $funcReplace($regs, $values, $outer);
578
579 if ($this->removeUnknownVariables) {
580 $outer = preg_replace($this->removeVariablesRegExp, "", $outer);
581 }
582 }
583
584 if ($empty) {
585 if (!$this->removeEmptyBlocks) {
586 $this->blockdata[$block ].= $outer;
587 } else {
588 if (isset($this->touchedBlocks[$block])) {
589 $this->blockdata[$block] .= $outer;
590 unset($this->touchedBlocks[$block]);
591 }
592 }
593 } else {
594 if (empty($this->blockdata[$block])) {
595 $this->blockdata[$block] = $outer;
596 } else {
597 $this->blockdata[$block] .= $outer;
598 }
599 }
600
601 return $empty;
602 } // end func parse
603
604 /**
605 * Parses the current block
606 * @see parse(), setCurrentBlock(), $currentBlock
607 * @access public
608 */
609 function parseCurrentBlock()
610 {
611 return $this->parse($this->currentBlock);
612 } // end func parseCurrentBlock
613
614 /**
615 * Sets a variable value.
616 *
617 * The function can be used eighter like setVariable( "varname", "value")
618 * or with one array $variables["varname"] = "value"
619 * given setVariable($variables) quite like phplib templates set_var().
620 *
621 * @param mixed string with the variable name or an array
622 * %variables["varname"] = "value"
623 * @param string value of the variable or empty if $variable
624 * is an array.
625 * @param string prefix for variable names
626 * @access public
627 */
628 function setVariable($variable, $value = '')
629 {
630 if (is_array($variable)) {
631 $this->variableCache = array_merge(
632 $this->variableCache, $variable
633 );
634 } else {
635 $this->variableCache[$variable] = $value;
636 }
637 } // end func setVariable
638
639 /**
640 * Sets the name of the current block that is the block where variables
641 * are added.
642 *
643 * @param string name of the block
644 * @return boolean false on failure, otherwise true
645 * @throws PEAR_Error
646 * @access public
647 */
648 function setCurrentBlock($block = '__global__')
649 {
650
651 if (!isset($this->blocklist[$block])) {
652 throw new Exception(
653 $this->errorMessage( IT_BLOCK_NOT_FOUND ) .
654 '"' . $block . "'", IT_BLOCK_NOT_FOUND
655 );
656 }
657
658 $this->currentBlock = $block;
659
660 return true;
661 } // end func setCurrentBlock
662
663 /**
664 * Preserves an empty block even if removeEmptyBlocks is true.
665 *
666 * @param string name of the block
667 * @return boolean false on false, otherwise true
668 * @throws PEAR_Error
669 * @access public
670 * @see $removeEmptyBlocks
671 */
672 function touchBlock($block)
673 {
674 if (!isset($this->blocklist[$block])) {
675 throw new Exception(
676 $this->errorMessage(IT_BLOCK_NOT_FOUND) .
677 '"' . $block . "'", IT_BLOCK_NOT_FOUND);
678 }
679
680 $this->touchedBlocks[$block] = true;
681
682 return true;
683 } // end func touchBlock
684
685 /**
686 * Clears all datafields of the object and rebuild the internal blocklist
687 *
688 * LoadTemplatefile() and setTemplate() automatically call this function
689 * when a new template is given. Don't use this function
690 * unless you know what you're doing.
691 *
692 * @access public
693 * @see free()
694 */
695 function init()
696 {
697 $this->free();
698 $this->findBlocks($this->template);
699 // we don't need it any more
700 $this->template = '';
701 $this->buildBlockvariablelist();
702 } // end func init
703
704 /**
705 * Clears all datafields of the object.
706 *
707 * Don't use this function unless you know what you're doing.
708 *
709 * @access public
710 * @see init()
711 */
712 function free()
713 {
714 $this->err = array();
715
716 $this->currentBlock = '__global__';
717
718 $this->variableCache = array();
719 $this->blocklist = array();
720 $this->touchedBlocks = array();
721
722 $this->flagBlocktrouble = false;
723 $this->flagGlobalParsed = false;
724 } // end func free
725
726 /**
727 * Sets the template.
728 *
729 * You can eighter load a template file from disk with
730 * LoadTemplatefile() or set the template manually using this function.
731 *
732 * @param string template content
733 * @param boolean remove unknown/unused variables?
734 * @param boolean remove empty blocks?
735 * @see LoadTemplatefile(), $template
736 * @access public
737 * @return boolean
738 */
739 function setTemplate( $template, $removeUnknownVariables = true,
740 $removeEmptyBlocks = true)
741 {
742 $this->removeUnknownVariables = $removeUnknownVariables;
743 $this->removeEmptyBlocks = $removeEmptyBlocks;
744
745 if ($template == '' && $this->flagCacheTemplatefile) {
746 $this->variableCache = array();
747 $this->blockdata = array();
748 $this->touchedBlocks = array();
749 $this->currentBlock = '__global__';
750 } else {
751 $this->template = '<!-- BEGIN __global__ -->' . $template .
752 '<!-- END __global__ -->';
753 $this->init();
754 }
755
756 if ($this->flagBlocktrouble) {
757 return false;
758 }
759
760 return true;
761 } // end func setTemplate
762
763 /**
764 * Reads a template file from the disk.
765 *
766 * @param string name of the template file
767 * @param bool how to handle unknown variables.
768 * @param bool how to handle empty blocks.
769 * @access public
770 * @return boolean false on failure, otherwise true
771 * @see $template, setTemplate(), $removeUnknownVariables,
772 * $removeEmptyBlocks
773 */
774 function loadTemplatefile( $filename,
775 $removeUnknownVariables = true,
776 $removeEmptyBlocks = true )
777 {
778 $template = '';
779 if (!$this->flagCacheTemplatefile ||
780 $this->lastTemplatefile != $filename
781 ) {
782 $template = $this->getFile($filename);
783 }
784 $this->lastTemplatefile = $filename;
785
786 return $template != '' ?
787 $this->setTemplate(
788 $template,$removeUnknownVariables, $removeEmptyBlocks
789 ) : false;
790 } // end func LoadTemplatefile
791
792 /**
793 * Sets the file root. The file root gets prefixed to all filenames passed
794 * to the object.
795 *
796 * Make sure that you override this function when using the class
797 * on windows.
798 *
799 * @param string
800 * @see HTML_Template_IT()
801 * @access public
802 */
803 function setRoot($root)
804 {
805 if ($root != '' && substr($root, -1) != '/') {
806 $root .= '/';
807 }
808
809 $this->fileRoot = $root;
810 } // end func setRoot
811
812 /**
813 * Build a list of all variables within of a block
814 */
815 function buildBlockvariablelist()
816 {
817 foreach ($this->blocklist as $name => $content) {
818 preg_match_all($this->variablesRegExp, $content, $regs);
819
820 if (count($regs[1]) != 0) {
821 foreach ($regs[1] as $k => $var) {
822 $this->blockvariables[$name][$var] = true;
823 }
824 } else {
825 $this->blockvariables[$name] = array();
826 }
827 }
828 } // end func buildBlockvariablelist
829
830 /**
831 * Returns a list of all global variables
832 */
833 function getGlobalvariables()
834 {
835 $regs = array();
836 $values = array();
837
838 foreach ($this->blockvariables['__global__'] as $allowedvar => $v) {
839 if (isset($this->variableCache[$allowedvar])) {
840 $regs[] = '@' . $this->openingDelimiter .
841 $allowedvar . $this->closingDelimiter . '@';
842 $values[] = $this->variableCache[$allowedvar];
843 unset($this->variableCache[$allowedvar]);
844 }
845 }
846
847 return array($regs, $values);
848 } // end func getGlobalvariables
849
850 /**
851 * Recusively builds a list of all blocks within the template.
852 *
853 * @param string string that gets scanned
854 * @see $blocklist
855 */
856 function findBlocks($string)
857 {
858 $blocklist = array();
859
860 if (preg_match_all($this->blockRegExp, $string, $regs, PREG_SET_ORDER)) {
861 foreach ($regs as $k => $match) {
862 $blockname = $match[1];
863 $blockcontent = $match[2];
864
865 if (isset($this->blocklist[$blockname])) {
866 $this->err[] = net_php_pear_PEAR::raiseError(
867 $this->errorMessage(
868 IT_BLOCK_DUPLICATE, $blockname),
869 IT_BLOCK_DUPLICATE
870 );
871 $this->flagBlocktrouble = true;
872 }
873
874 $this->blocklist[$blockname] = $blockcontent;
875 $this->blockdata[$blockname] = "";
876
877 $blocklist[] = $blockname;
878
879 $inner = $this->findBlocks($blockcontent);
880 foreach ($inner as $k => $name) {
881 $pattern = sprintf(
882 '@<!--\s+BEGIN\s+%s\s+-->(.*)<!--\s+END\s+%s\s+-->@sm',
883 $name,
884 $name
885 );
886
887 $this->blocklist[$blockname] = preg_replace(
888 $pattern,
889 $this->openingDelimiter .
890 '__' . $name . '__' .
891 $this->closingDelimiter,
892 $this->blocklist[$blockname]
893 );
894 $this->blockinner[$blockname][] = $name;
895 $this->blockparents[$name] = $blockname;
896 }
897 }
898 }
899
900 return $blocklist;
901 } // end func findBlocks
902
903 /**
904 * Reads a file from disk and returns its content.
905 * @param string Filename
906 * @return string Filecontent
907 */
908 function getFile($filename)
909 {
910 if ($filename{0} == '/' && substr($this->fileRoot, -1) == '/') {
911 $filename = substr($filename, 1);
912 }
913
914 $filename = $this->fileRoot . $filename;
915
916 if (!($fh = @fopen($filename, 'r'))) {
917 $this->err[] = net_php_pear_PEAR::raiseError(
918 $this->errorMessage(IT_TPL_NOT_FOUND) .
919 ': "' .$filename .'"',
920 IT_TPL_NOT_FOUND
921 );
922 return "";
923 }
924
925 $fsize = filesize($filename);
926 if ($fsize < 1) {
927 fclose($fh);
928 return '';
929 }
930
931 $content = fread($fh, $fsize);
932 fclose($fh);
933
934 return preg_replace(
935 "#<!-- INCLUDE (.*) -->#ime", "\$this->getFile('\\1')", $content
936 );
937 } // end func getFile
938
939 /**
940 * Adds delimiters to a string, so it can be used as a pattern
941 * in preg_* functions
942 *
943 * @param string
944 * @return string
945 */
946 function _addPregDelimiters($str)
947 {
948 return '@' . $str . '@';
949 }
950
951 /**
952 * Replaces an opening delimiter by a special string
953 *
954 * @param string
955 * @return string
956 */
957 function _preserveOpeningDelimiter($str)
958 {
959 return (false === strpos($str, $this->openingDelimiter))?
960 $str:
961 str_replace(
962 $this->openingDelimiter,
963 $this->openingDelimiter .
964 '%preserved%' . $this->closingDelimiter,
965 $str
966 );
967 }
968
969 /**
970 * Return a textual error message for a IT error code
971 *
972 * @param integer $value error code
973 *
974 * @return string error message, or false if the error code was
975 * not recognized
976 */
977 function errorMessage($value, $blockname = '')
978 {
979 static $errorMessages;
980 if (!isset($errorMessages)) {
981 $errorMessages = array(
982 IT_OK => '',
983 IT_ERROR => 'unknown error',
984 IT_TPL_NOT_FOUND => 'Cannot read the template file',
985 IT_BLOCK_NOT_FOUND => 'Cannot find this block',
986 IT_BLOCK_DUPLICATE => 'The name of a block must be'.
987 ' uniquewithin a template.'.
988 ' Found "' . $blockname . '" twice.'.
989 'Unpredictable results '.
990 'may appear.',
991 IT_UNKNOWN_OPTION => 'Unknown option'
992 );
993 }
994
995 if (net_php_pear_PEAR::isError($value)) {
996 $value = $value->getCode();
997 }
998
999 return isset($errorMessages[$value]) ?
1000 $errorMessages[$value] : $errorMessages[IT_ERROR];
1001 }
1002} // end class IntegratedTemplate
1003?>
Note: See TracBrowser for help on using the repository browser.