Location: PHPKode > scripts > Booster Template > booster-template/Booster.class.php
<?php

/**
 * Booster Template
 *
 * a lightweight but powerful compiled template engine for PHP 4 or higher
 *
 * @package		Booster
 * @author		Chris Lam <hide@address.com>
 * @copyright	Copyright (c) 2008, Chris Lam
 * @license		http://www.opensource.org/licenses/bsd-license.html
 * @link		http://code.google.com/p/booster-template/
 * @since		Version 1.0
 * @filesource
 */
class Booster
{
	/**
	 * @var $ext extension of the template files
	 */
	var $ext = 'tpl';

	/**
	 * @var $lang_callback callback function for {lang} token
	 */
	var $lang_callback = 'booster_lang';

	/**
	 * @var $tpl_path path of the template folder
	 */
	var $tpl_path = 'templates';

	/**
	 * @var $com_path path of the compiled folder
	 */
	var $com_path = 'templates_c';

	/**
	 * @var $rewrite_short_tags Wheather to rewrite short open tag
	 */
	var $rewrite_short_tags = true;

	var $_ob_level;

	var $_folder;
	var $_tpl_file;
	var $_obj_file;

	var $_const_regexp	= "([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)";
	var $_var_regexp	= "((\\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(\[[a-zA-Z0-9_\-\.\"\'\[\]\$\x7f-\xff]+\])*((\->[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(\[[a-zA-Z0-9_\-\.\"\'\[\]\$\x7f-\xff]+\])*)*)";

	function __construct($folder = '')
	{
		$folder = trim($folder);
		$this->_folder = strlen($folder) > 0 ? $folder : null;
		$this->_ob_level = ob_get_level();
	}

	function Booster($folder = '')
	{
		$this->__construct($folder);
	}

	/**
	 * Add quotes
	 *
	 * @access	private
	 * @param	string
	 * @return	string
	 */
	function _add_quote($var)
	{
		return str_replace("\\\"", "\"", preg_replace("/\[([a-zA-Z0-9_\-\.\x7f-\xff]+)\]/s", "['\\1']", $var));
	}

	/**
	 * Read file
	 *
	 * @access	private
	 * @param	string
	 * @return	string
	 */
	function &_read_file($file)
	{
		if(!function_exists('file_get_contents'))
		{
			if(!$fp = @fopen($this->_tpl_file, 'r'))
				$this->_read_error($file);

			$content = fread($fp, filesize($this->_tpl_file));
			fclose($fp);
		}
		else
		{
			if( ($content = @file_get_contents($this->_tpl_file)) === false )
				$this->_read_error($file);
		}
		return $content;
	}

	/**
	 * Error trigger for _read_file
	 *
	 * @access	private
	 * @param	string
	 * @return	string
	 */
	function _read_error($file)
	{
		trigger_error("Unable to load view file: $file.tpl");
	}

	/**
	 * Compile View file
	 *
	 * @access	private
	 * @param	string $file
	 * @return	void
	 */
	function _compile($file)
	{
		$this->_write($file, $this->_parse($this->_read_file($file)));
	}

	/**
	 * Parse View file
	 *
	 * @access	public
	 * @param	string $file
	 * @return	string
	*/
	function &_parse(&$content)
	{
		$nest = 5;
		$nl = '[\n\r\t]*';

		//$content = preg_replace("/([\n\r]+)\t+/s", "\\1", $content);
		$content = preg_replace("/\<\!\-\-\{(.+?)\}\-\-\>/s", "{\\1}", $content);
		$content = str_replace("{LF}", "<?=\"\\n\"?>", $content);

		// variables
		$content = preg_replace("/\{(\\\$[a-zA-Z0-9_\[\]\'\"\$\.\->\x7f-\xff]+)\}/s", "<?=\\1?>", $content);
		$content = preg_replace("/$this->_var_regexp/es", "\$this->_add_quote('<?=\\1?>')", $content);
		$content = preg_replace("/\<\?\=\<\?\=$this->_var_regexp\?\>\?\>/es", "\$this->_add_quote('<?=\\1?>')", $content);

		// variable with modifiers
		$content = preg_replace('/\{\<\?\='.$this->_var_regexp.'\?\>\s*\|\s*(.+?)\}/es', "\$this->_parse_modifiers('\\1', '\\7')", $content);

		// Comment
		// {* ..}
		$content = preg_replace("/$nl\{\*\s*([^\}]+)\}$nl/is", '', $content);

		// include another template in a template
		// {template ..} && {include ..}
		$content = preg_replace("/$nl\{(?:template|include)\s+([^\}]+)\}$nl/is", "\n<?php include _fetch('\\1'); ?>\n", $content);

		// add CSS
		// {css .. ..} && {style .. ..}
		$content = preg_replace("/$nl\{(?:css|style)(?:\[([^\}]+)\])?\s+([^\}]+)\}$nl/ies", "\$this->_css('\\2', '\\1')", $content);

		// add JavaScript file
		// {js .. ..} && {javascript .. ..}
		$content = preg_replace("/$nl\{(?:js|javascript)\s+([^\}]+)\}$nl/ies", "\$this->_js('\\1')", $content);

		// dynamic language token
		// {lang ..}
		$content = preg_replace("/\{lang\s+(.+?)\}/ies", "\$this->_lang('\\1')", $content);

		// eval php code
		// {eval ..} && {php ..}
		$content = preg_replace("/$nl\{(?:eval|php)\s+(.+?)\}$nl/ies", "\$this->_strip_vtags('\n<?php \\1 ?>\n', '')", $content);

		// Output (echo))
		// {=..}
		$content = preg_replace("/$nl\{=\s*(.+?)\}$nl/ies", "\$this->_strip_vtags('<?=\\1; ?>\n', '')", $content);
		// {echo ..} && {print ..}
		$content = preg_replace("/$nl\{(?:echo|print)\s+(.+?)\}$nl/ies", "\$this->_strip_vtags('<?=\\1; ?>\n', '')", $content);

		// {elseif ..}
		$content = preg_replace("/$nl\{elseif\s+(.+?)\}$nl/ies", "\$this->_strip_vtags('\n<?php } elseif(\\1) { ?>\n', '')", $content);
		// {else}
		$content = preg_replace("/$nl\{else\}$nl/is", "\n<?php } else { ?>\n", $content);

		for($i = 0; $i < $nest; $i++)
		{
			// {eval} .. {/eval}
			$content = preg_replace("/$nl\{eval\}[\n\r]*(.+?)[\n\r]*\{\/eval\}$nl/ies", "\$this->_strip_vtags('','\n<?php\n\\1\n?>\n')", $content);

			// {loop ..} .. {/loop} && {innerloop ..} .. {/innerloop}
			$content = preg_replace("/$nl\{(?:loop|innerloop)\s+(\S+)\s+(\S+)\}[\n\r]*(.+?)[\n\r]*\{\/(?:loop|innerloop)\}$nl/ies", "\$this->_strip_vtags('\n<?php\nif(isset(\\1) && is_array(\\1) && (\$_cc = count(\\1)) > 0) {\n\tfor(\$_ii_{$i} = 0; \$_ii_{$i} < \$_cc; \$_ii_{$i}++) {\n\t\t\\2=\\1[\$_ii_{$i}];\n?>','\n\\3\n<?php\n\t}\n}\n?>\n')", $content);
			// {loop .. ..} .. {/loop} && {innerloop .. ..} .. {/innerloop}
			$content = preg_replace("/$nl\{(?:loop|innerloop)\s+(\S+)\s+(\S+)\s+(\S+)\}$nl(.+?)$nl\{\/(?:loop|innerloop)\}$nl/ies", "\$this->_strip_vtags('\n<?php\nif(isset(\\1) && is_array(\\1) && (\$_cc = count(\\1)) > 0) {\n\t\$_kk_{$i} = array_keys(\\1);\n\tfor(\$_ii_{$i}_{$i} = 0; \$_ii_{$i}_{$i} < \$_cc; \$_ii_{$i}_{$i}++) {\n\t\t\\2=\$_kk_{$i}[\$_ii_{$i}_{$i}];\n\t\t\\3=\\1[\$_kk_{$i}[\$_ii_{$i}_{$i}]];\n?>','\n\\4\n<?php\n\t}\n}\n?>\n')", $content);
			// {loopelse}
			$content = preg_replace("/$nl\{(?:loopelse|innerloopelse)\}$nl/is", "\n<?php\n\t}\n} else {\n\tif(true) {\n?>\n", $content);

			// {foreach ..} .. {/foreach}
			$content = preg_replace("/$nl\{foreach\s+(\S+)\s+(\S+)\}[\n\r]*(.+?)[\n\r]*\{\/foreach\}$nl/ies", "\$this->_strip_vtags('\n<?php\nif(isset(\\1) && is_array(\\1) && \\1) {\n\tforeach(\\1 as \\2) {\n?>','\n\\3\n<?php\n\t}\n}\n?>\n')", $content);
			// {foreach .. ..} .. {/foreach}
			$content = preg_replace("/$nl\{foreach\s+(\S+)\s+(\S+)\s+(\S+)\}$nl(.+?)$nl\{\/foreach\}$nl/ies", "\$this->_strip_vtags('\n<?php\nif(isset(\\1) && is_array(\\1) && \\1) {\n\tforeach(\\1 as \\2 => \\3) {\n?>','\n\\4\n<?php\n\t}\n}\n?>\n')", $content);
			// {foreachelse}
			$content = preg_replace("/$nl\{foreachelse\}$nl/is", "\n<?php\n\t}\n} else {\n\tif(true) {\n?>\n", $content);

			// {/if}
			$content = preg_replace("/$nl\{if\s+(.+?)\}[\n\r]*(.+?)[\n\r]*\{\/if\}$nl/ies", "\$this->_strip_vtags('\n<?php if(\\1) { ?>\n','\\2\n<?php } ?>\n')", $content);
		}

		$content = preg_replace("/\{$this->_const_regexp\}/s", "<?=\\1?>", $content);
		$content = preg_replace("/ \?\>[\n\r]*\<\? /s", " ", $content);

		$content = str_replace(
			array(
				'<?=MEMORY_USAGE?>',
				'<?=lb?>',
				'<?=rb?>'
			),
			array(
				round($this->memory_get_usage() / 1024 / 1024, 2) . 'MB',
				'{',
				'}'
			),
			$content
		);

		$content = preg_replace("/ \?\>[\n\r]*\<\? /s", " ", $content);
		$content = preg_replace("/\"(http)?[\w\.\/:]+\?[^\"]+?&[^\"]+?\"/e", "\$this->_escape_amp('\\0')", $content);

		if((bool) @ini_get('short_open_tag') === false && $this->rewrite_short_tags)
			$content = str_replace('<?=', '<?php echo ', $content);

		return $content;
	}

	/**
	 * Write out View file
	 *
	 * @access	public
	 * @param	string
	 * @return	void
	*/
	function _write($file, &$content)
	{
		if(!$fp = @fopen($this->_obj_file, 'w'))
		{
			trigger_error("Unable to compile view file: $file.tpl");
		}

		flock($fp, 2);
		fwrite($fp, $content);
		fclose($fp);
		@chmod($this->_obj_file, 0666);
	}

	/**
	 * Parse modifiers
	 *
	 * @access	private
	 * @param	string
	 * @param	string
	 * @return	string
	 */
	function _parse_modifiers($var = '', $modifier_str = '')
	{
		$output = '';
		$modifier_str = $this->_strip_vtags($modifier_str, '');
		$array = (explode('|', $modifier_str));
		foreach($array as $key => $modifiers)
		{
			if(!$modifiers)
				continue;

			$params = explode(':', $modifiers);
			$modifier = $params[0];
			unset($params[0]);

			if(!is_callable(array('Booster', $modifier)))
			{
				if($modifier == 'default')
				{
					$modifier = 'Booster::default_to';
					$var = "(isset($var) ? $var : '')";
				}
				else
				{
					if(is_callable(array('Text', $modifier)))
					{
						$modifier = 'Text::' . $modifier;
					}
					elseif(!function_exists($modifier))
					{
						write_log('error', "Unknown modifer in $this->_tpl_file: $modifier");
						continue;
					}
				}
			}
			else $modifier = 'Booster::' . $modifier;

			if($key == 0)
				$output .= $modifier . '(' . $var . (count($params) > 0 ? ', ' . implode(', ', $params) : '') . ')';
			else
				$output = $modifier . '(' . ($output !== '' ? $output : '') . (count($params) > 0 ? ', ' . implode(', ', $params) : '') . ')';
		}
		return '<?php echo '. $output . '?>';
	}

	/**
	 * Fecth language value
	 *
	 * @access	private
	 * @param	string
	 * @return	string
	 */
	function _lang($var)
	{
		$func = $this->lang_callback;
		return function_exists($func) ? $func($var) : $var;
	}

	/**
	 * Generate script tag
	 *
	 * @access	private
	 * @param	string
	 * @return	string
	 */
	function _js($src = '')
	{
		$files = array_unique(array_map('trim', explode(',', $src)));

		$html = "\n";

		foreach($files as $file)
		{
			$html .= '<script type="text/javascript" src="' . $src . '"></script>' . "\n";
		}
		return $html;
	}

	/**
	 * Generate link tag for stylesheet
	 *
	 * @access	private
	 * @param	string
	 * @return	string
	 */
	function _css($src = '', $media = 'screen')
	{
		$files = array_unique(array_map('trim', explode(',', $src)));

		$html = "\n";

		foreach($files as $file)
		{
			$html .= '<link media="' . $media . '" rel="stylesheet" type="text/css" href="' . $src . '" />' . "\n";
		}
		return $html;
	}

	/**
	 * Set template file and compile object
	 *
	 * @access	private
	 * @param	string
	 * @return	string
	 */
	function _set_files($file)
	{
		$this->_mkdir($file);

		$folder = !is_null($this->_folder) ? $this->_folder . '/' : '';

		$this->_tpl_file = $this->tpl_path . '/' . $folder . $file . '.' . $this->ext;
		$this->_obj_file = $this->com_path . '/' . $folder . $file . '.' . $this->ext . '.php';
	}

	/**
	 * Create Directory in the view folder
	 *
	 * @access	private
	 * @param	string
	 * @return	string
	 */
	function _mkdir($file)
	{
		$tmp = explode('/', $file);

		$folder = $tmp_folder = $this->com_path . '/' . $this->_folder;

		if($this->_folder)
		{
			if(!is_dir($tmp_folder))
			{
				mkdir($tmp_folder);
				chmod($tmp_folder, 0777);
			}
		}

		if( ($count = count($tmp)) > 1 )
		{
			unset($tmp[$count - 1]);
			foreach($tmp as $val)
			{
				$folder .= '/' . $val;
				if(!is_dir($folder))
				{
					mkdir($folder);
					chmod($folder, 0777);
				}
			}
		}
	}

	/**
	 * Strip tags
	 *
	 * @access	private
	 * @param	string
	 * @param	string
	 * @return	string
	 */
	function _strip_vtags($expr, $statement)
	{
		$expr = preg_replace("/\<\?\=(\\\$.+?)\s*\?\>/s", "\\1", $expr);
		$expr = str_replace("\\\"", "\"", $expr);
		$statement = str_replace("\\\"", "\"", $statement);
		return $expr . $statement;
	}

	/**
	 * Escape & character
	 *
	 * @access	private
	 * @param	string
	 * @return	string
	 */
	function _escape_amp($str)
	{
		$str = str_replace('&', '&amp;', $str);
		$str = str_replace('&amp;amp;', '&amp;', $str);
		$str = str_replace('\&amp;', '&', $str);
		$str = str_replace('\"', '"', $str);
		return $str;
	}

	/**
	 * Fetch the path of the compiled view file
	 *
	 * @access	public
	 * @param	string
	 * @return	string
	 */
	function fetch($file)
	{
		$this->_set_files($file);

		if(file_exists($this->_tpl_file) && !file_exists($this->_obj_file))
			$this->_compile($file);
		if(!file_exists($this->_tpl_file) && file_exists($this->_obj_file))
			@unlink($this->_obj_file);
		if(file_exists($this->_obj_file) && @filemtime($this->_tpl_file) > @filemtime($this->_obj_file))
			$this->_compile($file);

		return $this->_obj_file;
	}

	/* the folowings are modifier fucntions */

	/**
	 * Append another string at the end of a string
	 *
	 * @access	public
	 * @param	string
	 * @param	string
	 * @return	string
	 */
	function append($str = '', $append = '')
	{
		return $str . $append;
	}

	/**
	 * Turn string into lower case
	 *
	 * @access	public
	 * @param	string
	 * @return	string
	 */
	function lower($str = '')
	{
		return strtolower($str);
	}

	/**
	 * Turn string into upper case
	 *
	 * @access	public
	 * @param	string
	 * @return	string
	 */
	function upper($str = '')
	{
		return strtoupper($str);
	}

	/**
	 * Return a formatted date
	 *
	 * @access	public
	 * @param	int
	 * @param	string
	 * @param	int
	 * @return	string
	 */
	function date_format($timestamp = 0, $format = 'Y-m-d H:i', $timezone = 0)
	{
		if(!$timestamp)
			$timestamp = time();
		return gmdate($format, $timestamp + intval($timezone) * 3600);
	}

	/**
	 * Return the year of a given timestamp
	 *
	 * @access	public
	 * @param	int
	 * @param	int
	 * @param	string
	 * @return	string
	 */
	function year($timestamp = 0, $timezone = 0, $format = 'Y')
	{
		return Booster::date_format($timestamp, $format, $timezone);
	}
	/**
	 * Return the month of a given timestamp
	 *
	 * @access	public
	 * @param	int
	 * @param	int
	 * @param	string
	 * @return	string
	 */
	function month($timestamp = 0, $timezone = 0, $format = 'n')
	{
		return Booster::date_format($timestamp, $format, $timezone);
	}

	/**
	 * Return the day of month of a given timestamp
	 *
	 * @access	public
	 * @param	int
	 * @param	int
	 * @param	string
	 * @return	string
	 */
	function day($timestamp = 0, $timezone = 0, $format = 'j')
	{
		return Booster::date_format($timestamp, $format, $timezone);
	}

	/**
	 * Return the day of week of a given timestamp
	 *
	 * @access	public
	 * @param	int
	 * @param	int
	 * @param	string
	 * @return	string
	 */
	function week_day($timestamp = 0, $timezone = 0, $format = 'l')
	{
		return Booster::date_format($timestamp, $format, $timezone);
	}

	/**
	 * Default value for unset or empty variable
	 *
	 * @access	public
	 * @param	string
	 * @param	string
	 * @return	string
	 */
	function default_to($str, $default = '')
	{
		$OBJ = &get_instance();
		if($OBJ->lang->fetch($default) !== false)
			$default = $OBJ->lang->fetch($default);

		return !isset($str) || strlen($str) == 0 ? $default : $str;
	}

	/**
	 * Replace string
	 *
	 * @access	public
	 * @param	string
	 * @param	string
	 * @param	string
	 * @return	string
	 */
	function replace($str = '', $search = '', $replace = '')
	{
		$func = $this->lang_callback;
		if($func($replace) !== false)
			$replace = $func($replace);

		return str_replace($search, $replace, $str);
	}

	/**
	 * A regular expression search and replace
	 *
	 * @access	public
	 * @param	string
	 * @param	string
	 * @param	string
	 * @return	string
	 */
	function regex_replace($str, $search, $replace)
	{
		$func = $this->lang_callback;
		if($func($replace) !== false)
			$replace = $func($replace);

		if(preg_match('!([a-zA-Z\s]+)$!s', $search, $match) && strpos($match[1], 'e') !== false)
		{
			/* remove eval-modifier from $search */
			$search = substr($search, 0, -strlen($match[1])) . preg_replace('![e\s]+!', '', $match[1]);
		}
		return preg_replace($search, $replace, $str);
	}

	/**
	 * Return a formatted string
	 *
	 * @access	public
	 * @param	string
	 * @param	string
	 * @return	string
	 */
	function string_format($str, $format)
	{
		return sprintf($format, $str);
	}

	/**
	* Return $a if $str is true, otherwise return $b
	*
	 * @access	public
	* @param	string
	* @param	string
	* @param	string
	* @param	string
	* @return	string
	*/
	function is_true($str, $a, $b, $val = '')
	{
		if($val)
			return $str == $val ? $a : $b;
		return $str ? $a : $b;
	}

	/**
	 * View Loader
	 *
	 * @access	public
	 * @param	string	the template file name without extension, can include folder name
	 * @param	array/object
	 * @return	bool
	 */
	function load($view, $vars = array())
	{
		if(is_object($vars))
			extract(get_object_vars($vars), EXTR_OVERWRITE);
		elseif(is_array($vars))
			extract($vars, EXTR_OVERWRITE);

		$file = $this->fetch($view);

		if(file_exists($file))
			include($file);
		else
			trigger_error('Unable to load view: ' . $file);
	}

	function memory_get_usage()
	{
		if(function_exists('memory_get_usage'))
		{
			return memory_get_usage();
		}
		else
		{
			if(substr(PHP_OS, 0, 3) == 'WIN')
			{
				$output = array();
				exec('tasklist /FI "PID eq ' . getmypid() . '" /FO LIST', $output);
				return preg_replace('/[\D]/', '', $output[5]) * 1024;
			}
			else
			{
				$pid = getmypid();
				exec("ps -eo%mem,rss,pid | grep $pid", $output);
				$output = explode("  ", $output[0]);
				return $output[1] * 1024;
			}
		}
	}
}

function _fetch($view)
{
	$b = new Booster();
	return $b->fetch($view);
}

if(!function_exists('booster_lang'))
{
	function booster_lang($token)
	{
		return $token;
	}
}

?>
Return current item: Booster Template