Automated build for v0.01
This commit is contained in:
		
						commit
						791b998489
					
				
					 2771 changed files with 222096 additions and 0 deletions
				
			
		
							
								
								
									
										922
									
								
								lib/MiniTemplator.class.php
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										922
									
								
								lib/MiniTemplator.class.php
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,922 @@ | |||
| <?php | ||||
| /** | ||||
| * File MiniTemplator.class.php | ||||
| * @package MiniTemplator | ||||
| */ | ||||
| 
 | ||||
| /** | ||||
| * A compact template engine for HTML files. | ||||
| * | ||||
| * Requires PHP 4.0.4 or newer. | ||||
| * | ||||
| * <pre> | ||||
| * Template syntax: | ||||
| * | ||||
| *   Variables: | ||||
| *     ${VariableName} | ||||
| * | ||||
| *   Blocks: | ||||
| *     <!-- $BeginBlock BlockName --> | ||||
| *     ... block content ... | ||||
| *     <!-- $EndBlock BlockName --> | ||||
| * | ||||
| *   Include a subtemplate: | ||||
| *     <!-- $Include RelativeFileName --> | ||||
| * </pre> | ||||
| * | ||||
| * <pre> | ||||
| * General remarks: | ||||
| *  - Variable names and block names are case-insensitive. | ||||
| *  - The same variable may be used multiple times within a template. | ||||
| *  - Blocks can be nested. | ||||
| *  - Multiple blocks with the same name may occur within a template. | ||||
| * </pre> | ||||
| * | ||||
| * <pre> | ||||
| * Public methods: | ||||
| *   readTemplateFromFile   - Reads the template from a file. | ||||
| *   setTemplateString      - Assigns a new template string. | ||||
| *   setVariable            - Sets a template variable. | ||||
| *   setVariableEsc         - Sets a template variable to an escaped string value. | ||||
| *   variableExists         - Checks whether a template variable exists. | ||||
| *   addBlock               - Adds an instance of a template block. | ||||
| *   blockExists            - Checks whether a block exists. | ||||
| *   reset                  - Clears all variables and blocks. | ||||
| *   generateOutput         - Generates the HTML page and writes it to the PHP output stream. | ||||
| *   generateOutputToFile   - Generates the HTML page and writes it to a file. | ||||
| *   generateOutputToString - Generates the HTML page and writes it to a string. | ||||
| * </pre> | ||||
| * | ||||
| * Home page: {@link http://www.source-code.biz/MiniTemplator}<br> | ||||
| * License: This module is released under the GNU/LGPL license ({@link http://www.gnu.org/licenses/lgpl.html}).<br> | ||||
| * Copyright 2003: Christian d'Heureuse, Inventec Informatik AG, Switzerland. All rights reserved.<br> | ||||
| * This product is provided "as is" without warranty of any kind.<br> | ||||
| * | ||||
| * Version history:<br> | ||||
| * 2001-10-24 Christian d'Heureuse (chdh): VBasic version created.<br> | ||||
| * 2002-01-26 Markus Angst: ported to PHP4.<br> | ||||
| * 2003-04-07 chdh: changes to adjust to Java version.<br> | ||||
| * 2003-07-08 chdh: Method variableExists added. | ||||
| *   Method setVariable changed to trigger an error when the variable does not exist.<br> | ||||
| * 2004-04-07 chdh: Parameter isOptional added to method setVariable. | ||||
| *   Licensing changed from GPL to LGPL.<br> | ||||
| * 2004-04-18 chdh: Method blockExists added.<br> | ||||
| * 2004-10-28 chdh:<br> | ||||
| *   Method setVariableEsc added.<br> | ||||
| *   Multiple blocks with the same name may now occur within a template.<br> | ||||
| *   No error ("unknown command") is generated any more, if a HTML comment starts with "${".<br> | ||||
| * 2004-11-06 chdh:<br> | ||||
| *   "$Include" command implemented.<br> | ||||
| * 2004-11-20 chdh:<br> | ||||
| *   "$Include" command changed so that the command text is not copied to the output file.<br> | ||||
| */ | ||||
| 
 | ||||
| class MiniTemplator { | ||||
| 
 | ||||
| //--- public member variables ---------------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| /** | ||||
| * Base path for relative file names of subtemplates (for the $Include command). | ||||
| * This path is prepended to the subtemplate file names. It must be set before | ||||
| * readTemplateFromFile or setTemplateString. | ||||
| * @access public | ||||
| */ | ||||
| var $subtemplateBasePath; | ||||
| 
 | ||||
| //--- private member variables --------------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| /**#@+
 | ||||
| * @access private | ||||
| */ | ||||
| 
 | ||||
| var $maxNestingLevel = 50;            // maximum number of block nestings
 | ||||
| var $maxInclTemplateSize = 1000000;   // maximum length of template string when including subtemplates
 | ||||
| var $template;                        // Template file data
 | ||||
| var $varTab;                          // variables table, array index is variable no
 | ||||
|     // Fields:
 | ||||
|     //  varName                       // variable name
 | ||||
|     //  varValue                      // variable value
 | ||||
| var $varTabCnt;                       // no of entries used in VarTab
 | ||||
| var $varNameToNoMap;                  // maps variable names to variable numbers
 | ||||
| var $varRefTab;                       // variable references table
 | ||||
|     // Contains an entry for each variable reference in the template. Ordered by TemplatePos.
 | ||||
|     // Fields:
 | ||||
|     //  varNo                         // variable no
 | ||||
|     //  tPosBegin                     // template position of begin of variable reference
 | ||||
|     //  tPosEnd                       // template position of end of variable reference
 | ||||
|     //  blockNo                       // block no of the (innermost) block that contains this variable reference
 | ||||
|     //  blockVarNo                    // block variable no. Index into BlockInstTab.BlockVarTab
 | ||||
| var $varRefTabCnt;                    // no of entries used in VarRefTab
 | ||||
| var $blockTab;                        // Blocks table, array index is block no
 | ||||
|     // Contains an entry for each block in the template. Ordered by TPosBegin.
 | ||||
|     // Fields:
 | ||||
|     //  blockName                     // block name
 | ||||
|     //  nextWithSameName;             // block no of next block with same name or -1 (blocks are backward linked in relation to template position)
 | ||||
|     //  tPosBegin                     // template position of begin of block
 | ||||
|     //  tPosContentsBegin             // template pos of begin of block contents
 | ||||
|     //  tPosContentsEnd               // template pos of end of block contents
 | ||||
|     //  tPosEnd                       // template position of end of block
 | ||||
|     //  nestingLevel                  // block nesting level
 | ||||
|     //  parentBlockNo                 // block no of parent block
 | ||||
|     //  definitionIsOpen              // true while $BeginBlock processed but no $EndBlock
 | ||||
|     //  instances                     // number of instances of this block
 | ||||
|     //  firstBlockInstNo              // block instance no of first instance of this block or -1
 | ||||
|     //  lastBlockInstNo               // block instance no of last instance of this block or -1
 | ||||
|     //  currBlockInstNo               // current block instance no, used during generation of output file
 | ||||
|     //  blockVarCnt                   // no of variables in block
 | ||||
|     //  blockVarNoToVarNoMap          // maps block variable numbers to variable numbers
 | ||||
|     //  firstVarRefNo                 // variable reference no of first variable of this block or -1
 | ||||
| var $blockTabCnt;                     // no of entries used in BlockTab
 | ||||
| var $blockNameToNoMap;                // maps block names to block numbers
 | ||||
| var $openBlocksTab; | ||||
|     // During parsing, this table contains the block numbers of the open parent blocks (nested outer blocks).
 | ||||
|     // Indexed by the block nesting level.
 | ||||
| var $blockInstTab;                    // block instances table
 | ||||
|     // This table contains an entry for each block instance that has been added.
 | ||||
|     // Indexed by BlockInstNo.
 | ||||
|     // Fields:
 | ||||
|     //  blockNo                       // block number
 | ||||
|     //  instanceLevel                 // instance level of this block
 | ||||
|     //     InstanceLevel is an instance counter per block.
 | ||||
|     //     (In contrast to blockInstNo, which is an instance counter over the instances of all blocks)
 | ||||
|     //  parentInstLevel               // instance level of parent block
 | ||||
|     //  nextBlockInstNo               // pointer to next instance of this block or -1
 | ||||
|     //     Forward chain for instances of same block.
 | ||||
|     //  blockVarTab                   // block instance variables
 | ||||
| var $blockInstTabCnt;                 // no of entries used in BlockInstTab
 | ||||
| 
 | ||||
| var $currentNestingLevel;             // Current block nesting level during parsing.
 | ||||
| var $templateValid;                   // true if a valid template is prepared
 | ||||
| var $outputMode;                      // 0 = to PHP output stream, 1 = to file, 2 = to string
 | ||||
| var $outputFileHandle;                // file handle during writing of output file
 | ||||
| var $outputError;                     // true when an output error occurred
 | ||||
| var $outputString;                    // string buffer for the generated HTML page
 | ||||
| 
 | ||||
| /**#@-*/ | ||||
| 
 | ||||
| //--- constructor ---------------------------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| /** | ||||
| * Constructs a MiniTemplator object. | ||||
| * @access public | ||||
| */ | ||||
| function __construct() { | ||||
|    $this->templateValid = false; } | ||||
| 
 | ||||
| //--- template string handling --------------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| /** | ||||
| * Reads the template from a file. | ||||
| * @param  string   $fileName  name of the file that contains the template. | ||||
| * @return boolean  true on success, false on error. | ||||
| * @access public | ||||
| */ | ||||
| function readTemplateFromFile ($fileName) { | ||||
|    if (!$this->readFileIntoString($fileName,$s)) { | ||||
|       $this->triggerError ("Error while reading template file " . $fileName . "."); | ||||
|       return false; } | ||||
|    if (!$this->setTemplateString($s)) return false; | ||||
|    return true; } | ||||
| 
 | ||||
| /** | ||||
| * Assigns a new template string. | ||||
| * @param  string   $templateString  contents of the template file. | ||||
| * @return boolean  true on success, false on error. | ||||
| * @access public | ||||
| */ | ||||
| function setTemplateString ($templateString) { | ||||
|    $this->templateValid = false; | ||||
|    $this->template = $templateString; | ||||
|    if (!$this->parseTemplate()) return false; | ||||
|    $this->reset(); | ||||
|    $this->templateValid = true; | ||||
|    return true; } | ||||
| 
 | ||||
| /** | ||||
| * Loads the template string for a subtemplate (used for the $Include command). | ||||
| * @return boolean  true on success, false on error. | ||||
| * @access private | ||||
| */ | ||||
| function loadSubtemplate ($subtemplateName, &$s) { | ||||
|    $subtemplateFileName = $this->combineFileSystemPath($this->subtemplateBasePath,$subtemplateName); | ||||
|    if (!$this->readFileIntoString($subtemplateFileName,$s)) { | ||||
|       $this->triggerError ("Error while reading subtemplate file " . $subtemplateFileName . "."); | ||||
|       return false; } | ||||
|    return true; } | ||||
| 
 | ||||
| //--- template parsing ----------------------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| /** | ||||
| * Parses the template. | ||||
| * @return boolean  true on success, false on error. | ||||
| * @access private | ||||
| */ | ||||
| function parseTemplate() { | ||||
|    $this->initParsing(); | ||||
|    $this->beginMainBlock(); | ||||
|    if (!$this->parseTemplateCommands()) return false; | ||||
|    $this->endMainBlock(); | ||||
|    if (!$this->checkBlockDefinitionsComplete()) return false; | ||||
|    if (!$this->parseTemplateVariables()) return false; | ||||
|    $this->associateVariablesWithBlocks(); | ||||
|    return true; } | ||||
| 
 | ||||
| /** | ||||
| * @access private | ||||
| */ | ||||
| function initParsing() { | ||||
|    $this->varTab = array(); | ||||
|    $this->varTabCnt = 0; | ||||
|    $this->varNameToNoMap = array(); | ||||
|    $this->varRefTab = array(); | ||||
|    $this->varRefTabCnt = 0; | ||||
|    $this->blockTab = array(); | ||||
|    $this->blockTabCnt = 0; | ||||
|    $this->blockNameToNoMap = array(); | ||||
|    $this->openBlocksTab = array(); } | ||||
| 
 | ||||
| /** | ||||
| * Registers the main block. | ||||
| * The main block is an implicitly defined block that covers the whole template. | ||||
| * @access private | ||||
| */ | ||||
| function beginMainBlock() { | ||||
|    $blockNo = 0; | ||||
|    $this->registerBlock('@@InternalMainBlock@@', $blockNo); | ||||
|    $bte =& $this->blockTab[$blockNo]; | ||||
|    $bte['tPosBegin'] = 0; | ||||
|    $bte['tPosContentsBegin'] = 0; | ||||
|    $bte['nestingLevel'] = 0; | ||||
|    $bte['parentBlockNo'] = -1; | ||||
|    $bte['definitionIsOpen'] = true; | ||||
|    $this->openBlocksTab[0] = $blockNo; | ||||
|    $this->currentNestingLevel = 1; } | ||||
| 
 | ||||
| /** | ||||
| * Completes the main block registration. | ||||
| * @access private | ||||
| */ | ||||
| function endMainBlock() { | ||||
|    $bte =& $this->blockTab[0]; | ||||
|    $bte['tPosContentsEnd'] = strlen($this->template); | ||||
|    $bte['tPosEnd'] = strlen($this->template); | ||||
|    $bte['definitionIsOpen'] = false; | ||||
|    $this->currentNestingLevel -= 1; } | ||||
| 
 | ||||
| /** | ||||
| * Parses commands within the template in the format "<!-- $command parameters -->". | ||||
| * @return boolean  true on success, false on error. | ||||
| * @access private | ||||
| */ | ||||
| function parseTemplateCommands() { | ||||
|    $p = 0; | ||||
|    while (true) { | ||||
|       $p0 = strpos($this->template,'<!--',$p); | ||||
|       if ($p0 === false) break; | ||||
|       $p = strpos($this->template,'-->',$p0); | ||||
|       if ($p === false) { | ||||
|          $this->triggerError ("Invalid HTML comment in template at offset $p0."); | ||||
|          return false; } | ||||
|       $p += 3; | ||||
|       $cmdL = substr($this->template,$p0+4,$p-$p0-7); | ||||
|       if (!$this->processTemplateCommand($cmdL,$p0,$p,$resumeFromStart)) | ||||
|          return false; | ||||
|       if ($resumeFromStart) $p = $p0; } | ||||
|    return true; } | ||||
| 
 | ||||
| /** | ||||
| * @return boolean  true on success, false on error. | ||||
| * @access private | ||||
| */ | ||||
| function processTemplateCommand ($cmdL, $cmdTPosBegin, $cmdTPosEnd, &$resumeFromStart) { | ||||
|    $resumeFromStart = false; | ||||
|    $p = 0; | ||||
|    $cmd = ''; | ||||
|    if (!$this->parseWord($cmdL,$p,$cmd)) return true; | ||||
|    $parms = substr($cmdL,$p); | ||||
|    switch (strtoupper($cmd)) { | ||||
|       case '$BEGINBLOCK': | ||||
|          if (!$this->processBeginBlockCmd($parms,$cmdTPosBegin,$cmdTPosEnd)) | ||||
|             return false; | ||||
|          break; | ||||
|       case '$ENDBLOCK': | ||||
|          if (!$this->processEndBlockCmd($parms,$cmdTPosBegin,$cmdTPosEnd)) | ||||
|             return false; | ||||
|          break; | ||||
|       case '$INCLUDE': | ||||
|          if (!$this->processincludeCmd($parms,$cmdTPosBegin,$cmdTPosEnd)) | ||||
|             return false; | ||||
|          $resumeFromStart = true; | ||||
|          break; | ||||
|       default: | ||||
|          if ($cmd{0} == '$' && !(strlen($cmd) >= 2 && $cmd{1} == '{')) { | ||||
|             $this->triggerError ("Unknown command \"$cmd\" in template at offset $cmdTPosBegin.");
 | ||||
|             return false; }} | ||||
|     return true; } | ||||
| 
 | ||||
| /** | ||||
| * Processes the $BeginBlock command. | ||||
| * @return boolean  true on success, false on error. | ||||
| * @access private | ||||
| */ | ||||
| function processBeginBlockCmd ($parms, $cmdTPosBegin, $cmdTPosEnd) { | ||||
|    $p = 0; | ||||
|    if (!$this->parseWord($parms,$p,$blockName)) { | ||||
|       $this->triggerError ("Missing block name in \$BeginBlock command in template at offset $cmdTPosBegin."); | ||||
|       return false; } | ||||
|    if (trim(substr($parms,$p)) != '') { | ||||
|       $this->triggerError ("Extra parameter in \$BeginBlock command in template at offset $cmdTPosBegin."); | ||||
|       return false; } | ||||
|    $this->registerBlock ($blockName, $blockNo); | ||||
|    $btr =& $this->blockTab[$blockNo]; | ||||
|    $btr['tPosBegin'] = $cmdTPosBegin; | ||||
|    $btr['tPosContentsBegin'] = $cmdTPosEnd; | ||||
|    $btr['nestingLevel'] = $this->currentNestingLevel; | ||||
|    $btr['parentBlockNo'] = $this->openBlocksTab[$this->currentNestingLevel-1]; | ||||
|    $this->openBlocksTab[$this->currentNestingLevel] = $blockNo; | ||||
|    $this->currentNestingLevel += 1; | ||||
|    if ($this->currentNestingLevel > $this->maxNestingLevel) { | ||||
|       $this->triggerError ("Block nesting overflow in template at offset $cmdTPosBegin."); | ||||
|       return false; } | ||||
|    return true; } | ||||
| 
 | ||||
| /** | ||||
| * Processes the $EndBlock command. | ||||
| * @return boolean  true on success, false on error. | ||||
| * @access private | ||||
| */ | ||||
| function processEndBlockCmd ($parms, $cmdTPosBegin, $cmdTPosEnd) { | ||||
|    $p = 0; | ||||
|    if (!$this->parseWord($parms,$p,$blockName)) { | ||||
|       $this->triggerError ("Missing block name in \$EndBlock command in template at offset $cmdTPosBegin."); | ||||
|       return false; } | ||||
|    if (trim(substr($parms,$p)) != '') { | ||||
|       $this->triggerError ("Extra parameter in \$EndBlock command in template at offset $cmdTPosBegin."); | ||||
|       return false; } | ||||
|    if (!$this->lookupBlockName($blockName,$blockNo)) { | ||||
|       $this->triggerError ("Undefined block name \"$blockName\" in \$EndBlock command in template at offset $cmdTPosBegin.");
 | ||||
|       return false; } | ||||
|    $this->currentNestingLevel -= 1; | ||||
|    $btr =& $this->blockTab[$blockNo]; | ||||
|    if (!$btr['definitionIsOpen']) { | ||||
|       $this->triggerError ("Multiple \$EndBlock command for block \"$blockName\" in template at offset $cmdTPosBegin.");
 | ||||
|       return false; } | ||||
|    if ($btr['nestingLevel'] != $this->currentNestingLevel) { | ||||
|       $this->triggerError ("Block nesting level mismatch at \$EndBlock command for block \"$blockName\" in template at offset $cmdTPosBegin.");
 | ||||
|       return false; } | ||||
|    $btr['tPosContentsEnd'] = $cmdTPosBegin; | ||||
|    $btr['tPosEnd'] = $cmdTPosEnd; | ||||
|    $btr['definitionIsOpen'] = false; | ||||
|    return true; } | ||||
| 
 | ||||
| /** | ||||
| * @access private | ||||
| */ | ||||
| function registerBlock($blockName, &$blockNo) { | ||||
|    $blockNo = $this->blockTabCnt++; | ||||
|    $btr =& $this->blockTab[$blockNo]; | ||||
|    $btr = array(); | ||||
|    $btr['blockName'] = $blockName; | ||||
|    if (!$this->lookupBlockName($blockName,$btr['nextWithSameName'])) | ||||
|       $btr['nextWithSameName'] = -1; | ||||
|    $btr['definitionIsOpen'] = true; | ||||
|    $btr['instances'] = 0; | ||||
|    $btr['firstBlockInstNo'] = -1; | ||||
|    $btr['lastBlockInstNo'] = -1; | ||||
|    $btr['blockVarCnt'] = 0; | ||||
|    $btr['firstVarRefNo'] = -1; | ||||
|    $btr['blockVarNoToVarNoMap'] = array(); | ||||
|    $this->blockNameToNoMap[strtoupper($blockName)] = $blockNo; } | ||||
| 
 | ||||
| /** | ||||
| * Checks that all block definitions are closed. | ||||
| * @return boolean  true on success, false on error. | ||||
| * @access private | ||||
| */ | ||||
| function checkBlockDefinitionsComplete() { | ||||
|    for ($blockNo=0; $blockNo < $this->blockTabCnt; $blockNo++) { | ||||
|       $btr =& $this->blockTab[$blockNo]; | ||||
|       if ($btr['definitionIsOpen']) { | ||||
|          $this->triggerError ("Missing \$EndBlock command in template for block " . $btr['blockName'] . "."); | ||||
|          return false; }} | ||||
|    if ($this->currentNestingLevel != 0) { | ||||
|       $this->triggerError ("Block nesting level error at end of template."); | ||||
|       return false; } | ||||
|    return true; } | ||||
| 
 | ||||
| /** | ||||
| * Processes the $Include command. | ||||
| * @return boolean  true on success, false on error. | ||||
| * @access private | ||||
| */ | ||||
| function processIncludeCmd ($parms, $cmdTPosBegin, $cmdTPosEnd) { | ||||
|    $p = 0; | ||||
|    if (!$this->parseWordOrQuotedString($parms,$p,$subtemplateName)) { | ||||
|       $this->triggerError ("Missing or invalid subtemplate name in \$Include command in template at offset $cmdTPosBegin."); | ||||
|       return false; } | ||||
|    if (trim(substr($parms,$p)) != '') { | ||||
|       $this->triggerError ("Extra parameter in \$include command in template at offset $cmdTPosBegin."); | ||||
|       return false; } | ||||
|    return $this->insertSubtemplate($subtemplateName,$cmdTPosBegin,$cmdTPosEnd); } | ||||
| 
 | ||||
| /** | ||||
| * Processes the $Include command. | ||||
| * @return boolean  true on success, false on error. | ||||
| * @access private | ||||
| */ | ||||
| function insertSubtemplate ($subtemplateName, $tPos1, $tPos2) { | ||||
|    if (strlen($this->template) > $this->maxInclTemplateSize) { | ||||
|       $this->triggerError ("Subtemplate include aborted because the internal template string is longer than $this->maxInclTemplateSize characters."); | ||||
|       return false; } | ||||
|    if (!$this->loadSubtemplate($subtemplateName,$subtemplate)) return false; | ||||
|    // (Copying the template to insert a subtemplate is a bit slow. In a future implementation of MiniTemplator,
 | ||||
|    // a table could be used that contains references to the string fragments.)
 | ||||
|    $this->template = substr($this->template,0,$tPos1) . $subtemplate . substr($this->template,$tPos2); | ||||
|    return true; } | ||||
| 
 | ||||
| /** | ||||
| * Parses variable references within the template in the format "${VarName}". | ||||
| * @return boolean  true on success, false on error. | ||||
| * @access private | ||||
| */ | ||||
| function parseTemplateVariables() { | ||||
|    $p = 0; | ||||
|    while (true) { | ||||
|       $p = strpos($this->template, '${', $p); | ||||
|       if ($p === false) break; | ||||
|       $p0 = $p; | ||||
|       $p = strpos($this->template, '}', $p); | ||||
|       if ($p === false) { | ||||
|          $this->triggerError ("Invalid variable reference in template at offset $p0."); | ||||
|          return false; } | ||||
|       $p += 1; | ||||
|       $varName = trim(substr($this->template, $p0+2, $p-$p0-3)); | ||||
|       if (strlen($varName) == 0) { | ||||
|          $this->triggerError ("Empty variable name in template at offset $p0."); | ||||
|          return false; } | ||||
|       $this->registerVariableReference ($varName, $p0, $p); } | ||||
|    return true; } | ||||
| 
 | ||||
| /** | ||||
| * @access private | ||||
| */ | ||||
| function registerVariableReference ($varName, $tPosBegin, $tPosEnd) { | ||||
|    if (!$this->lookupVariableName($varName,$varNo)) | ||||
|       $this->registerVariable($varName,$varNo); | ||||
|    $varRefNo = $this->varRefTabCnt++; | ||||
|    $vrtr =& $this->varRefTab[$varRefNo]; | ||||
|    $vrtr = array(); | ||||
|    $vrtr['tPosBegin'] = $tPosBegin; | ||||
|    $vrtr['tPosEnd'] = $tPosEnd; | ||||
|    $vrtr['varNo'] = $varNo; } | ||||
| 
 | ||||
| /** | ||||
| * @access private | ||||
| */ | ||||
| function registerVariable ($varName, &$varNo) { | ||||
|    $varNo = $this->varTabCnt++; | ||||
|    $vtr =& $this->varTab[$varNo]; | ||||
|    $vtr = array(); | ||||
|    $vtr['varName'] = $varName; | ||||
|    $vtr['varValue'] = ''; | ||||
|    $this->varNameToNoMap[strtoupper($varName)] = $varNo; } | ||||
| 
 | ||||
| /** | ||||
| * Associates variable references with blocks. | ||||
| * @access private | ||||
| */ | ||||
| function associateVariablesWithBlocks() { | ||||
|    $varRefNo = 0; | ||||
|    $activeBlockNo = 0; | ||||
|    $nextBlockNo = 1; | ||||
|    while ($varRefNo < $this->varRefTabCnt) { | ||||
|       $vrtr =& $this->varRefTab[$varRefNo]; | ||||
|       $varRefTPos = $vrtr['tPosBegin']; | ||||
|       $varNo = $vrtr['varNo']; | ||||
|       if ($varRefTPos >= $this->blockTab[$activeBlockNo]['tPosEnd']) { | ||||
|          $activeBlockNo = $this->blockTab[$activeBlockNo]['parentBlockNo']; | ||||
|          continue; } | ||||
|       if ($nextBlockNo < $this->blockTabCnt) { | ||||
|          if ($varRefTPos >= $this->blockTab[$nextBlockNo]['tPosBegin']) { | ||||
|             $activeBlockNo = $nextBlockNo; | ||||
|             $nextBlockNo += 1; | ||||
|             continue; }} | ||||
|       $btr =& $this->blockTab[$activeBlockNo]; | ||||
|       if ($varRefTPos < $btr['tPosBegin']) | ||||
|          $this->programLogicError(1); | ||||
|       $blockVarNo = $btr['blockVarCnt']++; | ||||
|       $btr['blockVarNoToVarNoMap'][$blockVarNo] = $varNo; | ||||
|       if ($btr['firstVarRefNo'] == -1) | ||||
|          $btr['firstVarRefNo'] = $varRefNo; | ||||
|       $vrtr['blockNo'] = $activeBlockNo; | ||||
|       $vrtr['blockVarNo'] = $blockVarNo; | ||||
|       $varRefNo += 1; }} | ||||
| 
 | ||||
| //--- build up (template variables and blocks) ----------------------------------------------------------------------
 | ||||
| 
 | ||||
| /** | ||||
| * Clears all variables and blocks. | ||||
| * This method can be used to produce another HTML page with the same | ||||
| * template. It is faster than creating another MiniTemplator object, | ||||
| * because the template does not have to be parsed again. | ||||
| * All variable values are cleared and all added block instances are deleted. | ||||
| * @access public | ||||
| */ | ||||
| function reset() { | ||||
|    for ($varNo=0; $varNo<$this->varTabCnt; $varNo++) | ||||
|       $this->varTab[$varNo]['varValue'] = ''; | ||||
|    for ($blockNo=0; $blockNo<$this->blockTabCnt; $blockNo++) { | ||||
|       $btr =& $this->blockTab[$blockNo]; | ||||
|       $btr['instances'] = 0; | ||||
|       $btr['firstBlockInstNo'] = -1; | ||||
|       $btr['lastBlockInstNo'] = -1; } | ||||
|    $this->blockInstTab = array(); | ||||
|    $this->blockInstTabCnt = 0; } | ||||
| 
 | ||||
| /** | ||||
| * Sets a template variable. | ||||
| * For variables that are used in blocks, the variable value | ||||
| * must be set before {@link addBlock} is called. | ||||
| * @param  string  $variableName   the name of the variable to be set. | ||||
| * @param  string  $variableValue  the new value of the variable. | ||||
| * @param  boolean $isOptional     Specifies whether an error should be | ||||
| *    generated when the variable does not exist in the template. If | ||||
| *    $isOptional is false and the variable does not exist, an error is | ||||
| *    generated. | ||||
| * @return boolean true on success, or false on error (e.g. when no | ||||
| *    variable with the specified name exists in the template and | ||||
| *    $isOptional is false). | ||||
| * @access public | ||||
| */ | ||||
| function setVariable ($variableName, $variableValue, $isOptional=false) { | ||||
|    if (!$this->templateValid) {$this->triggerError ("Template not valid."); return false; } | ||||
|    if (!$this->lookupVariableName($variableName,$varNo)) { | ||||
|       if ($isOptional) return true; | ||||
|       $this->triggerError ("Variable \"$variableName\" not defined in template.");
 | ||||
|       return false; } | ||||
|    $this->varTab[$varNo]['varValue'] = $variableValue; | ||||
|    return true; } | ||||
| 
 | ||||
| /** | ||||
| * Sets a template variable to an escaped string. | ||||
| * This method is identical to (@link setVariable), except that | ||||
| * the characters <, >, &, ' and " of variableValue are
 | ||||
| * replaced by their corresponding HTML/XML character entity codes. | ||||
| * For variables that are used in blocks, the variable value | ||||
| * must be set before {@link addBlock} is called. | ||||
| * @param  string  $variableName   the name of the variable to be set. | ||||
| * @param  string  $variableValue  the new value of the variable. Special HTML/XML characters are escaped. | ||||
| * @param  boolean $isOptional     Specifies whether an error should be | ||||
| *    generated when the variable does not exist in the template. If | ||||
| *    $isOptional is false and the variable does not exist, an error is | ||||
| *    generated. | ||||
| * @return boolean true on success, or false on error (e.g. when no | ||||
| *    variable with the specified name exists in the template and | ||||
| *    $isOptional is false). | ||||
| * @access public | ||||
| */ | ||||
| function setVariableEsc ($variableName, $variableValue, $isOptional=false) { | ||||
|    return $this->setVariable($variableName,htmlspecialchars($variableValue,ENT_QUOTES),$isOptional); } | ||||
| 
 | ||||
| /** | ||||
| * Checks whether a variable with the specified name exists within the template. | ||||
| * @param  string  $variableName   the name of the variable. | ||||
| * @return boolean true if the variable exists, or false when no | ||||
| *    variable with the specified name exists in the template. | ||||
| * @access public | ||||
| */ | ||||
| function variableExists ($variableName) { | ||||
|    if (!$this->templateValid) {$this->triggerError ("Template not valid."); return false; } | ||||
|    return $this->lookupVariableName($variableName,$varNo); } | ||||
| 
 | ||||
| /** | ||||
| * Adds an instance of a template block. | ||||
| * If the block contains variables, these variables must be set | ||||
| * before the block is added. | ||||
| * If the block contains subblocks (nested blocks), the subblocks | ||||
| * must be added before this block is added. | ||||
| * If multiple blocks exist with the specified name, an instance | ||||
| * is added for each block occurence. | ||||
| * @param  string   blockName the name of the block to be added. | ||||
| * @return boolean  true on success, false on error (e.g. when no | ||||
| *    block with the specified name exists in the template). | ||||
| * @access public | ||||
| */ | ||||
| function addBlock($blockName) { | ||||
|    if (!$this->templateValid) {$this->triggerError ("Template not valid."); return false; } | ||||
|    if (!$this->lookupBlockName($blockName,$blockNo)) { | ||||
|       $this->triggerError ("Block \"$blockName\" not defined in template.");
 | ||||
|       return false; } | ||||
|    while ($blockNo != -1) { | ||||
|       $this->addBlockByNo($blockNo); | ||||
|       $blockNo = $this->blockTab[$blockNo]['nextWithSameName']; } | ||||
|    return true; } | ||||
| 
 | ||||
| /** | ||||
| * @access private | ||||
| */ | ||||
| function addBlockByNo ($blockNo) { | ||||
|    $btr =& $this->blockTab[$blockNo]; | ||||
|    $this->registerBlockInstance ($blockInstNo); | ||||
|    $bitr =& $this->blockInstTab[$blockInstNo]; | ||||
|    if ($btr['firstBlockInstNo'] == -1) | ||||
|       $btr['firstBlockInstNo'] = $blockInstNo; | ||||
|    if ($btr['lastBlockInstNo'] != -1) | ||||
|       $this->blockInstTab[$btr['lastBlockInstNo']]['nextBlockInstNo'] = $blockInstNo; | ||||
|          // set forward pointer of chain
 | ||||
|    $btr['lastBlockInstNo'] = $blockInstNo; | ||||
|    $parentBlockNo = $btr['parentBlockNo']; | ||||
|    $blockVarCnt = $btr['blockVarCnt']; | ||||
|    $bitr['blockNo'] = $blockNo; | ||||
|    $bitr['instanceLevel'] = $btr['instances']++; | ||||
|    if ($parentBlockNo == -1) | ||||
|       $bitr['parentInstLevel'] = -1; | ||||
|     else | ||||
|       $bitr['parentInstLevel'] = $this->blockTab[$parentBlockNo]['instances']; | ||||
|    $bitr['nextBlockInstNo'] = -1; | ||||
|    $bitr['blockVarTab'] = array(); | ||||
|    // copy instance variables for this block
 | ||||
|    for ($blockVarNo=0; $blockVarNo<$blockVarCnt; $blockVarNo++) { | ||||
|       $varNo = $btr['blockVarNoToVarNoMap'][$blockVarNo]; | ||||
|       $bitr['blockVarTab'][$blockVarNo] = $this->varTab[$varNo]['varValue']; }} | ||||
| 
 | ||||
| /** | ||||
| * @access private | ||||
| */ | ||||
| function registerBlockInstance (&$blockInstNo) { | ||||
|    $blockInstNo = $this->blockInstTabCnt++; } | ||||
| 
 | ||||
| /** | ||||
| * Checks whether a block with the specified name exists within the template. | ||||
| * @param  string  $blockName   the name of the block. | ||||
| * @return boolean true if the block exists, or false when no | ||||
| *    block with the specified name exists in the template. | ||||
| * @access public | ||||
| */ | ||||
| function blockExists ($blockName) { | ||||
|    if (!$this->templateValid) {$this->triggerError ("Template not valid."); return false; } | ||||
|    return $this->lookupBlockName($blockName,$blockNo); } | ||||
| 
 | ||||
| //--- output generation ---------------------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| /** | ||||
| * Generates the HTML page and writes it to the PHP output stream. | ||||
| * @return boolean  true on success, false on error. | ||||
| * @access public | ||||
| */ | ||||
| function generateOutput () { | ||||
|    $this->outputMode = 0; | ||||
|    if (!$this->generateOutputPage()) return false; | ||||
|    return true; } | ||||
| 
 | ||||
| /** | ||||
| * Generates the HTML page and writes it to a file. | ||||
| * @param  string   $fileName  name of the output file. | ||||
| * @return boolean  true on success, false on error. | ||||
| * @access public | ||||
| */ | ||||
| function generateOutputToFile ($fileName) { | ||||
|    $fh = fopen($fileName,"wb"); | ||||
|    if ($fh === false) return false; | ||||
|    $this->outputMode = 1; | ||||
|    $this->outputFileHandle = $fh; | ||||
|    $ok = $this->generateOutputPage(); | ||||
|    fclose ($fh); | ||||
|    return $ok; } | ||||
| 
 | ||||
| /** | ||||
| * Generates the HTML page and writes it to a string. | ||||
| * @param  string   $outputString  variable that receives | ||||
| *                  the contents of the generated HTML page. | ||||
| * @return boolean  true on success, false on error. | ||||
| * @access public | ||||
| */ | ||||
| function generateOutputToString (&$outputString) { | ||||
|    $outputString = "Error"; | ||||
|    $this->outputMode = 2; | ||||
|    $this->outputString = ""; | ||||
|    if (!$this->generateOutputPage()) return false; | ||||
|    $outputString = $this->outputString; | ||||
|    return true; } | ||||
| 
 | ||||
| /** | ||||
| * @access private | ||||
| * @return boolean  true on success, false on error. | ||||
| */ | ||||
| function generateOutputPage() { | ||||
|    if (!$this->templateValid) {$this->triggerError ("Template not valid."); return false; } | ||||
|    if ($this->blockTab[0]['instances'] == 0) | ||||
|       $this->addBlockByNo (0);        // add main block
 | ||||
|    for ($blockNo=0; $blockNo < $this->blockTabCnt; $blockNo++) { | ||||
|        $btr =& $this->blockTab[$blockNo]; | ||||
|        $btr['currBlockInstNo'] = $btr['firstBlockInstNo']; } | ||||
|    $this->outputError = false; | ||||
|    $this->writeBlockInstances (0, -1); | ||||
|    if ($this->outputError) return false; | ||||
|    return true; } | ||||
| 
 | ||||
| /** | ||||
| * Writes all instances of a block that are contained within a specific | ||||
| * parent block instance. | ||||
| * Called recursively. | ||||
| * @access private | ||||
| */ | ||||
| function writeBlockInstances ($blockNo, $parentInstLevel) { | ||||
|    $btr =& $this->blockTab[$blockNo]; | ||||
|    while (!$this->outputError) { | ||||
|       $blockInstNo = $btr['currBlockInstNo']; | ||||
|       if ($blockInstNo == -1) break; | ||||
|       $bitr =& $this->blockInstTab[$blockInstNo]; | ||||
|       if ($bitr['parentInstLevel'] < $parentInstLevel) | ||||
|          $this->programLogicError (2); | ||||
|       if ($bitr['parentInstLevel'] > $parentInstLevel) break; | ||||
|       $this->writeBlockInstance ($blockInstNo); | ||||
|       $btr['currBlockInstNo'] = $bitr['nextBlockInstNo']; }} | ||||
| 
 | ||||
| /** | ||||
| * @access private | ||||
| */ | ||||
| function writeBlockInstance($blockInstNo) { | ||||
|    $bitr =& $this->blockInstTab[$blockInstNo]; | ||||
|    $blockNo = $bitr['blockNo']; | ||||
|    $btr =& $this->blockTab[$blockNo]; | ||||
|    $tPos = $btr['tPosContentsBegin']; | ||||
|    $subBlockNo = $blockNo + 1; | ||||
|    $varRefNo = $btr['firstVarRefNo']; | ||||
|    while (!$this->outputError) { | ||||
|       $tPos2 = $btr['tPosContentsEnd']; | ||||
|       $kind = 0;                                // assume end-of-block
 | ||||
|       if ($varRefNo != -1 && $varRefNo < $this->varRefTabCnt) {  // check for variable reference
 | ||||
|          $vrtr =& $this->varRefTab[$varRefNo]; | ||||
|          if ($vrtr['tPosBegin'] < $tPos) { | ||||
|             $varRefNo += 1; | ||||
|             continue; } | ||||
|          if ($vrtr['tPosBegin'] < $tPos2) { | ||||
|             $tPos2 = $vrtr['tPosBegin']; | ||||
|             $kind = 1; }} | ||||
|       if ($subBlockNo < $this->blockTabCnt) {   // check for subblock
 | ||||
|          $subBtr =& $this->blockTab[$subBlockNo]; | ||||
|          if ($subBtr['tPosBegin'] < $tPos) { | ||||
|             $subBlockNo += 1; | ||||
|             continue; } | ||||
|          if ($subBtr['tPosBegin'] < $tPos2) { | ||||
|             $tPos2 = $subBtr['tPosBegin']; | ||||
|             $kind = 2; }} | ||||
|       if ($tPos2 > $tPos) | ||||
|          $this->writeString (substr($this->template,$tPos,$tPos2-$tPos)); | ||||
|       switch ($kind) { | ||||
|          case 0:         // end of block
 | ||||
|             return; | ||||
|          case 1:         // variable
 | ||||
|             $vrtr =& $this->varRefTab[$varRefNo]; | ||||
|             if ($vrtr['blockNo'] != $blockNo) | ||||
|                $this->programLogicError (4); | ||||
|             $variableValue = $bitr['blockVarTab'][$vrtr['blockVarNo']]; | ||||
|             $this->writeString ($variableValue); | ||||
|             $tPos = $vrtr['tPosEnd']; | ||||
|             $varRefNo += 1; | ||||
|             break; | ||||
|          case 2:         // sub block
 | ||||
|             $subBtr =& $this->blockTab[$subBlockNo]; | ||||
|             if ($subBtr['parentBlockNo'] != $blockNo) | ||||
|                $this->programLogicError (3); | ||||
|             $this->writeBlockInstances ($subBlockNo, $bitr['instanceLevel']);  // recursive call
 | ||||
|             $tPos = $subBtr['tPosEnd']; | ||||
|             $subBlockNo += 1; | ||||
|             break; }}} | ||||
| 
 | ||||
| /** | ||||
| * @access private | ||||
| */ | ||||
| function writeString ($s) { | ||||
|    if ($this->outputError) return; | ||||
|    switch ($this->outputMode) { | ||||
|       case 0:            // output to PHP output stream
 | ||||
|          if (!print($s)) | ||||
|             $this->outputError = true; | ||||
|          break; | ||||
|       case 1:            // output to file
 | ||||
|          $rc = fwrite($this->outputFileHandle, $s); | ||||
|          if ($rc === false) $this->outputError = true; | ||||
|          break; | ||||
|       case 2:            // output to string
 | ||||
|          $this->outputString .= $s; | ||||
|          break; }} | ||||
| 
 | ||||
| //--- name lookup routines ------------------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| /** | ||||
| * Maps variable name to variable number. | ||||
| * @return boolean  true on success, false if the variable is not found. | ||||
| * @access private | ||||
| */ | ||||
| function lookupVariableName ($varName, &$varNo) { | ||||
|    $x =& $this->varNameToNoMap[strtoupper($varName)]; | ||||
|    if (!isset($x)) return false; | ||||
|    $varNo = $x; | ||||
|    return true; } | ||||
| 
 | ||||
| /** | ||||
| * Maps block name to block number. | ||||
| * If there are multiple blocks with the same name, the block number of the last | ||||
| * registered block with that name is returned. | ||||
| * @return boolean  true on success, false when the block is not found. | ||||
| * @access private | ||||
| */ | ||||
| function lookupBlockName ($blockName, &$blockNo) { | ||||
|    $x =& $this->blockNameToNoMap[strtoupper($blockName)]; | ||||
|    if (!isset($x)) return false; | ||||
|    $blockNo = $x; | ||||
|    return true; } | ||||
| 
 | ||||
| //--- general utility routines -----------------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| /** | ||||
| * Reads a file into a string. | ||||
| * @return boolean  true on success, false on error. | ||||
| * @access private | ||||
| */ | ||||
| function readFileIntoString ($fileName, &$s) { | ||||
|    if (function_exists('version_compare') && version_compare(phpversion(),"4.3.0",">=")) { | ||||
|       $s = file_get_contents($fileName); | ||||
|       if ($s === false) return false; | ||||
|       return true; } | ||||
|    $fh = fopen($fileName,"rb"); | ||||
|    if ($fh === false) return false; | ||||
|    $fileSize = filesize($fileName); | ||||
|    if ($fileSize === false) {fclose ($fh); return false; } | ||||
|    $s = fread($fh,$fileSize); | ||||
|    fclose ($fh); | ||||
|    if (strlen($s) != $fileSize) return false; | ||||
|    return true; } | ||||
| 
 | ||||
| /** | ||||
| * @access private | ||||
| * @return boolean  true on success, false when the end of the string is reached. | ||||
| */ | ||||
| function parseWord ($s, &$p, &$w) { | ||||
|    $sLen = strlen($s); | ||||
|    while ($p < $sLen && ord($s{$p}) <= 32) $p++; | ||||
|    if ($p >= $sLen) return false; | ||||
|    $p0 = $p; | ||||
|    while ($p < $sLen && ord($s{$p}) > 32) $p++; | ||||
|    $w = substr($s, $p0, $p - $p0); | ||||
|    return true; } | ||||
| 
 | ||||
| /** | ||||
| * @access private | ||||
| * @return boolean  true on success, false on error. | ||||
| */ | ||||
| function parseQuotedString ($s, &$p, &$w) { | ||||
|    $sLen = strlen($s); | ||||
|    while ($p < $sLen && ord($s{$p}) <= 32) $p++; | ||||
|    if ($p >= $sLen) return false; | ||||
|    if (substr($s,$p,1) != '"') return false; | ||||
|    $p++; $p0 = $p; | ||||
|    while ($p < $sLen && $s{$p} != '"') $p++; | ||||
|    if ($p >= $sLen) return false; | ||||
|    $w = substr($s, $p0, $p - $p0); | ||||
|    $p++; | ||||
|    return true; } | ||||
| 
 | ||||
| /** | ||||
| * @access private | ||||
| * @return boolean  true on success, false on error. | ||||
| */ | ||||
| function parseWordOrQuotedString ($s, &$p, &$w) { | ||||
|    $sLen = strlen($s); | ||||
|    while ($p < $sLen && ord($s{$p}) <= 32) $p++; | ||||
|    if ($p >= $sLen) return false; | ||||
|    if (substr($s,$p,1) == '"') | ||||
|       return $this->parseQuotedString($s,$p,$w); | ||||
|     else | ||||
|       return $this->parseWord($s,$p,$w); } | ||||
| 
 | ||||
| /** | ||||
| * Combine two file system paths. | ||||
| * @access private | ||||
| */ | ||||
| function combineFileSystemPath ($path1, $path2) { | ||||
|    if ($path1 == '' || $path2 == '') return $path2; | ||||
|    $s = $path1; | ||||
|    if (substr($s,-1) != '\\' && substr($s,-1) != '/') $s = $s . "/"; | ||||
|    if (substr($path2,0,1) == '\\' || substr($path2,0,1) == '/') | ||||
|       $s = $s . substr($path2,1); | ||||
|     else | ||||
|       $s = $s . $path2; | ||||
|    return $s; } | ||||
| 
 | ||||
| /** | ||||
| * @access private | ||||
| */ | ||||
| function triggerError ($msg) { | ||||
|    trigger_error ("MiniTemplator error: $msg", E_USER_ERROR); } | ||||
| 
 | ||||
| /** | ||||
| * @access private | ||||
| */ | ||||
| function programLogicError ($errorId) { | ||||
|    die ("MiniTemplator: Program logic error $errorId.\n"); } | ||||
| 
 | ||||
| } | ||||
| ?>
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Fmstrat
						Fmstrat