Location: PHPKode > projects > CMSmelborp > CMSmelborp/includes/templates.php
<?php
/*******************************************************************************
License:
	Copyright 2005 Ryan Morehart
	Licensed under the Apache License, Version 2.0 (the "License");
	you may not use this file except in compliance with the License.
	You may obtain a copy of the License at
	
	http://www.apache.org/licenses/LICENSE-2.0
	
	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.
	
Filename: /includes/templates.php

Purpose: Holds template processing functions for both display and creation/updating.

Processed parameters: (TYPE - NAME - DESCRIPTION - DEFAULT)
	None
*******************************************************************************/

function getTemplate(&$connection, $name, $getLinkedData = true)
{
	global $linked_data_page_name_prefix;
	global $__tags;
	global $__html;
	global $__page;
	global $__templateName;
	
	// Name may contain letters, numbers, underscores
	if(!isValidTemplateName($connection, $name, true))
	{
		return false;
	}
	
	$template = mysql_query("SELECT * FROM templates WHERE template_name='$name';", $connection);
	$template = mysql_fetch_array($template, MYSQL_ASSOC);
	
	// Ensure the template was retrieved
	if($template === false)
	{
		return false;
	}
	
	// Check if there is a "linked data page," meaing we are supposed to use the supplied page
	// to fill in this template
	if($template['linked_data_page'] == true && $getLinkedData)
	{
		// Get the page (and check to make sure we got it)
		$page = getPage($connection, $linked_data_page_name_prefix . $template['template_name']);
		if($page === false)
		{
			$template['error'] = 'Linked data page could not be opened';
			return $template;
		}
		
		// Save current template parsing data (if it exists)
		if(isset($__html))
		{
			$backupHtml = $__html;
			$backupPage = $__page;
			$backupTags = $__tags;
			$backupName = $__templateName;
		}
		
		// Parse template with the page data, leaving the tags which are empty (leave them
		// to be parsed later)
		$template['html'] = parseTemplate($connection, $template, $page, true);
		
		// Restore backed up data
		if(isset($backupHtml))
		{
			$__html = $backupHtml;
			$__page = $backupPage;
			$__tags = $backupTags;
			$__templateName = $backupName;
		}
	}
	
	// Return template
	return $template;
}

function parseTemplate(&$connection, $template, $page = false, $leaveEmptyTags = false)
{
	global $process_php_in_html;
	
	// Setup the global variable the results will be stored in temporarially
	global $__tags;
	global $__html;
	global $__page;
	$__tags = array();
	$__html = '';
	if($page !== false)
	{
		// If there's no content, just set the global __page to an empty array
		if(isset($page['content']))
		{
			$__page = $page['content'];
		}
		else
		{
			$__page = array();
		}
	}
	else
	{
		$__page = false;
	}
	
	// Use this to try to prevent the inclusion of a template in the same template
	global $__templateName;
	$__templateName = $template['template_name'];
	
	parseTemplateSection($connection, $template['html'], $leaveEmptyTags);
	
	// Destroy global variables
	$tags = $__tags;
	$html = $__html;
	unset($__tags);
	unset($__html);
	unset($__page);
	unset($__templateName);
	
	if($page === false)
	{
		return $tags;
	}
	else
	{
		// Process any embedded PHP
		if($process_php_in_html)
		{
			$html = preg_replace('/<\?(?:php|)\s*(.*?)\s*\?>/e',
				"eval('\1');", $html);
		}
		
		return $html;
	}
}

function parseTemplateSection(&$connection, $template, $leaveEmptyTags = false)
{
	global $debug_mode;
	
	global $__tags;
	global $__html;
	global $__page;
	global $__templateName;
	
	$beginTag = 0;
	$endTag = 0;
	
	// The variables below is used as a stack for keeping of track of which loop we are currently in
	$loopLevel = array();
	$loopInstance = array();
	$loopBegin = array();
	
	while(true)
	{
		// Find the beginning of the tag
		$beginTag = strpos($template, '{!', $endTag);

		// Copy from the end of the last tag to the beginning of this one
		// into the html which we are outputting
		if($beginTag !== false)
		{
			$__html .= substr($template, $endTag, $beginTag - $endTag);
		}
		else
		{
			$__html .= substr($template, $endTag);
			break;
		}
		
		// Find the end of this tag
		$endTag = strpos($template, '}', $beginTag);
		
		// Save entire tag (in case leaveEmptyTags is on)
		$entireTag = substr($template, $beginTag, $endTag - $beginTag + 1);
		
		// Get the parameters of this tag
		$tagParametersLength = $endTag - ($beginTag + 2);
		$tagParameters = substr($template, $beginTag + 2, $tagParametersLength);
		$tagParameters = explode(',', $tagParameters);
		
		// Process each parameter for beauty
		for($i = 0; $i < count($tagParameters); $i++)
		{
			// Save for easy use
			$current = $tagParameters[$i];
			
			// Whitespace
			$current = trim($current);
			
			// Quoted? (Allows for a whitespace parameter)
			preg_match('/^([\'"]|)(.*)\1$/', $current, $matches);
			$current = $matches[2];
			
			// Put back in			
			$tagParameters[$i] = $current;
		}
		
		// Process accoding to it's type
		switch(strtolower($tagParameters[0]))
		{
		// Subsitution
		case 's':
			if($__page === false)
			{
				// Are we in a loop?
				if(empty($loopLevel))
					$__tags[$tagParameters[1]] = $tagParameters[0];
				else
					$__tags[$loopLevel[0]][$tagParameters[1]] = $tagParameters[0];
			}
			else
			{
				if($debug_mode === true)
					$__html .= "<!-- Begin substitution $tagParameters[1] -->";
				
				if(empty($loopLevel))
				{
					if(isset($__page[$tagParameters[1]]) && !empty($__page[$tagParameters[1]]))
					{
						$__html .= nl2br($__page[$tagParameters[1]]);
					}
					elseif($leaveEmptyTags)
					{
						$__html .= $entireTag;
					}
				}
				else
				{
					if(isset($__page[$loopLevel[0]][$loopInstance[0]][$tagParameters[1]])
                        && !empty($__page[$loopLevel[0]][$loopInstance[0]][$tagParameters[1]]))
					{
						$__html .= nl2br($__page[$loopLevel[0]][$loopInstance[0]][$tagParameters[1]]);
					}
					elseif($leaveEmptyTags)
					{
						$__html .= $entireTag;
					}
				}
				
				if($debug_mode === true)
					$__html .= "<!-- End substitution -->";
			}
			break;
		
		// File
		case 'f':
			if($__page === false)
			{
				// Are we in a loop?
				if(empty($loopLevel))
					$__tags[$tagParameters[1]] = $tagParameters[0];
				else
					$__tags[$loopLevel[0]][$tagParameters[1]] = $tagParameters[0];
			}
			else
			{
				if($debug_mode === true)
					$__html .= "<!-- Begin file $tagParameters[1] -->";
				
				if(empty($loopLevel))
				{
					if(isset($__page[$tagParameters[1]]) && !empty($__page[$tagParameters[1]]))
					{
						$__html .= "showfile.php?name=" . $__page[$tagParameters[1]];
					}
					elseif($leaveEmptyTags)
					{
						$__html .= $entireTag;
					}
				}
				else
				{
					if(isset($__page[$loopLevel[0]][$loopInstance[0]][$tagParameters[1]])
                        && !empty($__page[$loopLevel[0]][$loopInstance[0]][$tagParameters[1]]))
					{
						$__html .= "showfile.php?name=" . $__page[$loopLevel[0]][$loopInstance[0]][$tagParameters[1]];
					}
					elseif($leaveEmptyTags)
					{
						$__html .= $entireTag;
					}
				}
				
				if($debug_mode === true)
					$__html .= "<!-- End file -->";
			}
			break;
			
		// Loop
		case 'l':
			// Check if this tag is the beginning of a new loop or the end of the current one
			if(empty($loopLevel) || $loopLevel[0] != $tagParameters[1])
			{
				// New loop
				// Check if there is any data for this loop
				if($__page === false || isset($__page[$tagParameters[1]]))
				{
					array_unshift($loopLevel, $tagParameters[1]);
					array_unshift($loopInstance, 1);
					array_unshift($loopBegin, $endTag);
					
					if($debug_mode === true)
					{
						$__html .= "<!-- Begin loop $tagParameters[1] -->";
						$__html .= "<!-- Begin loop instance $loopInstance[0] -->";
					}
				}
				else
				{
					// Find the end of this loop
					$endLoop = strpos($template, $entireTag, $endTag);

					// Check if we are supposed to save the empty tags
					if($leaveEmptyTags)
					{
						// Output loop stuff, then skip past it
						// Beginning tag
						$__html .= $entireTag;
						
						// Template stuff between beginning and closing tag
						$__html .= substr($template, $endTag + 1, $endLoop - $endTag - 1);
						
						// Closing tag
						$__html .= $entireTag;
					}
					
					// Put current position past this loop
					$endTag = strpos($template, '}', $endLoop);
				}
			}
			else
			{
				// End current
				// Check if there are more instances of this loop
				if($__page !== false && isset($__page[$loopLevel[0]][$loopInstance[0] + 1]))
				{
					if($debug_mode === true)
						$__html .= "<!-- End loop instance $loopInstance[0] -->";

					// Move loop instance counter to next one and reset parsing to beginning of loop
					$loopInstance[0]++;
					$endTag = $loopBegin[0];
					
					if($debug_mode === true)
						$__html .= "<!-- Begin loop instance $loopInstance[0] -->";
				}
				else
				{
					if($debug_mode === true)
						$__html .= "<!-- End loop instance $loopInstance[0] -->";
					
					// Done with this loop
					array_shift($loopLevel);
					array_shift($loopInstance);
					array_shift($loopBegin);

					if($debug_mode === true)
						$__html .= "<!-- End loop -->";
				}
			}
			
			break;
		
		// Picture/image
		case 'p':
			if($__page === false)
			{
				if(empty($loopLevel))
					$__tags[$tagParameters[1]] = $tagParameters[0];
				else
					$__tags[$loopLevel[0]][$tagParameters[1]] = $tagParameters[0];
			}
			else
			{
				if($debug_mode === true)
					$__html .= "<!-- Begin image. Name: $tagParameters[1] -->";
					
				// Parameters images accept:
				// 1 - name, obviously
				// 2 - height
				// 3 - width
				// 4 - proportional mode
				// 5 - extra info for tag
				
				// Fill in empty parameters
				if(!isset($tagParameters[2]) || empty($tagParameters[2]))
				{
					$tagParameters[2] = false;
				}
				if(!isset($tagParameters[3]) || empty($tagParameters[3]))
				{
					$tagParameters[3] = $tagParameters[2];
				}
				if(!isset($tagParameters[4]) || empty($tagParameters[4]))
				{
					$tagParameters[4] = 'prop';
				}
				if(!isset($tagParameters[5]))
				{
					$tagParameters[5] = '';
				}
				
				if(empty($loopLevel))
				{
					if(isset($__page[$tagParameters[1]]) && !empty($__page[$tagParameters[1]]))
					{
						$__html .= getImageTag($connection, $__page[$tagParameters[1]], $tagParameters[2],
							$tagParameters[3], $tagParameters[4], $tagParameters[5]);
					}
					elseif($leaveEmptyTags)
					{
						$__html .= $entireTag;
					}
				}
				else
				{
					if(isset($__page[$loopLevel[0]][$loopInstance[0]][$tagParameters[1]])
                        && !empty($__page[$loopLevel[0]][$loopInstance[0]][$tagParameters[1]]))
					{
						$__html .= getImageTag($connection, $__page[$loopLevel[0]][$loopInstance[0]][$tagParameters[1]],
							$tagParameters[2], $tagParameters[3], $tagParameters[4], $tagParameters[5]);
					}
					elseif($leaveEmptyTags)
					{
						$__html .= $entireTag;
					}
				}
				
				if($debug_mode === true)
					$__html .= "<!-- End image -->";
			}
			break;
		
		// Include
		case 'i':
			// Get the template
			// If we are supposed to leave empty tags, then don't get the linked data
			$includedTemplate = getTemplate($connection, $tagParameters[1], !$leaveEmptyTags);
			
			// Parse it! Note that we don't go through the "main" parseTemplate function
			// If we did, the current stuff would be erased
			if($debug_mode === true)
				$__html .= "<!-- Begin include of $tagParameters[1] -->";
			
			if($__templateName != $includedTemplate['template_name'])
			{
				// Save and restore name to help catch self includes in included template
				$backupName = $__templateName;
				parseTemplateSection($connection, $includedTemplate['html'], $leaveEmptyTags);
				$__templateName = $backupName;
			}
			elseif($debug_mode == true)
			{
				$__html .= "<!-- Template included in self -->";
			}
			
			if($debug_mode === true)
				$__html .= "<!-- End include -->";
			break;
		
		// Count
		case 'c':
			// What type of count?
			if($tagParameters[1] == 'total')
			{
				// How many instances of the specfied loop exist on this page?
				if(isset($__page[$tagParameters[2]]) && is_array($__page[$tagParameters[2]]))
				{
					$__html .= count($__page[$tagParameters[2]]);
				}
			}
			elseif($tagParameters[1] == 'current')
			{
				// What instance of the specified loop are we currently on?
				if(($key = array_search($tagParameters[2], $loopLevel)) !== false)
				{
					$__html .= $loopInstance[$key];
				}
			}
			
			break;
			
		// Unrecognized
		default:
			$__html .= '<!-- Possible template tag type unrecognized. Outputting: -->';
			$__html .= substr($template, $beginTag, $tagParametersLength + 3);
			$__html .= '<!-- End unrecognized tag -->';
			
			$__tags[$tagParameters[1]] = $tagParameters[0];
			break;
		}
		
		// Move the tag end marker ahead 1 by default
		$endTag++;
	}
	
	return true;
}

function createTemplate(&$connection, $name, $description = '', $html = '', $isInclude = false, $linkedDataPage = false)
{
	global $linked_data_page_name_prefix;
	
	// Ensure we have a valid template and, if applicable, link data page name
	if(!isValidTemplateName($connection, $name, false) || templateExists($connection, $name)
		|| (!empty($linkedDataPage) && !isValidPageName($connection, $linkedDataPage)))
	{
		return false;
	}
	
	// Create linked data page if needed
	if($linkedDataPage)
	{
		if(createPage($connection, $linked_data_page_name_prefix . $name, $name,
			'Linked data page for template ' . $name, true) === false)
		{
			return false;
		}
	}
	
	// Attempt to template
	$success = mysql_query("INSERT INTO templates VALUES('$name', '"
		. addslashes($description) . "', '"
		. addslashes($html) . "', "
		. ($isInclude == true ? 'true' : 'false') . ", "
		. ($linkedDataPage ? 'true' : 'false') . ");", $connection);
	if($success === false)
	{
		return false;
	}
	
	return true;
}

function setTemplateInfo(&$connection, $oldName, $newName, $description, $isInclude = false, $linkedDataPage = false)
{
	global $linked_data_page_name_prefix;
	
	// Ensure we have valid template names
	if(!isValidTemplateName($connection, $oldName, true)
		|| !isValidTemplateName($connection, $newName)
		|| ($newName != $oldName && templateExists($connection, $newName))
		|| (!empty($linkedDataPage) && !isValidPageName($connection, $linkedDataPage)))
	{
		return false;
	}
	
	// Update linked data page name if the template name has changed
	if($oldName != $newName)
	{
		setPageInfo($connection, $linked_data_page_name_prefix . $oldName, $linked_data_page_name_prefix . $newName,
			$newName, 'Linked data page for template ' . $newName);
	}
	
	// Check if the linked data page setting has become active
	// Note how we don't check if it deactivates. This helps save poor souls who accidentally get
	// click happy. The LDP will be deleted when the template is anyways.
	if($linkedDataPage)
	{
		// Check if it already exists
		if(!pageExists($connection, $linked_data_page_name_prefix . $newName))
		{
			// Create
			createPage($connection, $linked_data_page_name_prefix . $newName, $newName,
				'Linked data page for template ' . $newName, true);
		}
	}
	
	$success = mysql_query("UPDATE templates SET "
		. "template_name='$newName', "
		. "description='" . addslashes($description) . "', "
		. "inclusion=" . ($isInclude == true ? 'true' : 'false') . ", "
		. "linked_data_page=" . ($linkedDataPage ? 'true' : 'false')
		. " WHERE template_name='$oldName';", $connection);
	if($success === false)
	{
		return false;
	}
	
	return true;
}

function setTemplateHTML(&$connection, $name, $newHTML)
{
	// Ensure we have a valid template name
	if(!isValidTemplateName($connection, $name, true))
	{
		return false;
	}
	
	// Put the new HTML in the template
	$success = mysql_query("UPDATE templates SET html='"
		. addslashes($newHTML)
		. "' WHERE template_name='$name';", $connection);
	if($success === false)
	{
		return false;
	}
	
	return true;
}

function getTemplateList(&$connection)
{
	// Get the list of templates from database
	$templates = mysql_query("SELECT * FROM templates ORDER BY template_name", $connection);
	if($templates === false)
	{
		return false;
	}
	
	// Put into an array
	$temp = fetchResults($templates);
	
	return $temp;
}

function deleteTemplate(&$connection, $name)
{
	global $linked_data_page_name_prefix;
	
	// Ensure we have a valid template name
	if(!isValidTemplateName($connection, $name, true))
	{
		return false;
	}

	// Remove it's linked data page (don't check if it does)
	// Ignore errors
	deletePage($connection, $linked_data_page_name_prefix . $name);
	
	// Remove template
	$success = mysql_query("DELETE FROM templates WHERE template_name='$name';", $connection);
	if($success === false)
	{
		return false;
	}
	
	return true;
}

function isValidTemplateName(&$connection, $name, $isExistent = false)
{
	// Ensure it conains only valid characters
	if(!ereg('^[_a-zA-Z0-9]+$', $name))
	{
		return false;
	}
	
	// Check if this name is already in the database (if we are supposed to)
	if($isExistent)
	{
		return templateExists($connection, $name);
	}
	else
	{
		return true;
	}
}

function templateExists(&$connection, $name)
{
	$exists = mysql_query("SELECT * FROM templates WHERE template_name='$name';");
	if(mysql_fetch_array($exists, MYSQL_ASSOC) === false)
	{
		return false;
	}
	else
	{
		return true;
	}
}
?>
Return current item: CMSmelborp