Skip to content

Instantly share code, notes, and snippets.

@Swizec
Created February 3, 2022 16:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Swizec/90ab6872f60cdceb252c1c90fb53838d to your computer and use it in GitHub Desktop.
Save Swizec/90ab6872f60cdceb252c1c90fb53838d to your computer and use it in GitHub Desktop.
<?php
///////////////////////////////////////////////////////////////////
// //
// file: template.php //
// scripter: swizec //
// contact: swizec@swizec.com //
// started on: 18th May 2005 //
// version: 0.12.0 //
// //
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
// //
// This program is free software; you can redistribute it //
// and/or modify it under the terms of the GNU General Public //
// License as published by the Free Software Foundation; //
// either version 2 of the License, or (at your option) //
// any later version. //
// //
///////////////////////////////////////////////////////////////////
//
// Template engine for the Chlorine Boards
//
// basic security
if ( !defined( 'RUNNING_CL' ) )
{
ob_clean();
die( 'You bastard, this is not for you' );
}
// vars explanation
// template_files :: list of template files
// template_vars :: all the variables
// template_misc :: list of flags and such
// cache :: cache module
// block_hash :: references of all blocks
// forbidden_code :: class with forbidden code
// functions :: functions code
// debug :: debug mode flag
// folder :: the template folder to be used
// class creation
$vars = array( 'template_files', 'template_vars', 'template_misc', 'cache', 'block_hash', 'forbidden_code', 'functions', 'debug', 'folder' );
$visible = array( 'private', 'private', 'private', 'private', 'private', 'private', 'private', 'private', 'public' );
eval( Varloader::createclass( 'template', $vars, $visible ) );
// end class creation
class Template extends template_def
{
// used for creating a new template object
// $template = new template( $cache, $folder );
function template( $cache, $folder, $debug = FALSE )
{
// get global vars
global $Cl_root_path;
// get whats needed
include( $Cl_root_path . 'kernel/forbidden_code' . phpEx );
$this->template_files = array( );
$this->template_vars = array( );
$this->template_misc[ 'switches' ] = array( );
$this->template_code = array( );
$this->block_hash = array();
$this->functions = array();
$this->debug = $debug;
$this->folder = $folder;
// add modules
$this->cache = $cache;
$this->forbidden_code = new forbidden_code();
}
// used to clear everything that has been set thusfar
function clear()
{
$this->template_files = array( );
$this->template_vars = array( );
$this->template_misc[ 'switches' ] = array( );
$this->template_code = array( );
$this->block_hash = array();
$this->functions = array();
}
// used for changing the template folder
// $template->change_folder( $Cl_root_path . $newtemp )
function change_folder( $folder )
{
global $errors;
$errors->debug_info( $this->debug, 'Template', 'change_folder', 'changing template folder from' . $this->folder . ' to ' . $folder );
$this->folder = $folder . '/';
}
// used to find out if the handle is used
// $template->is_assignedfile( 'forums' )
function is_assignedfile( $handle )
{
global $errors;
$errors->debug_info( $this->debug, 'Template', 'is_assignedfile', 'finding out if handle ' . $handle . ' is a used' );
return isset( $this->template_files[ $handle ] );
}
// used to find out if the handle is executed
// $template->is_executedfile( 'forums' )
function is_executedfile( $handle )
{
global $errors;
$errors->debug_info( $this->debug, 'Template', 'is_executedfile', 'finding out if handle ' . $handle . ' has been executed' );
return isset( $this->template_files[ $handle ][ 'executed' ] );
}
// used for assigning template files
// $template->assign_files( array( 'handle1' => 'file1.tpl', 'handle2' => 'file2.tpl' ) );
function assign_files( $files )
{
global $errors;
// loop through the array and add
while ( list ( $handle, $file ) = each ( $files ) )
{
// add path to the filename
$file = $this->folder . $file;
// debug info
$errors->debug_info( $this->debug, 'Template', 'assign_files', 'linking ' . $file . ' with ' . $handle );
$this->template_files[ $handle ][ 'file' ] = $file;
$this->template_files[ $handle ][ 'executed' ] = FALSE;
}
}
// used to read a file
// internal use only
// $this->getfile( 'handle' );
function _getfile( $handle )
{
global $errors;
$cache = $this->cache; // saves typing
$file = $this->template_files[ $handle ][ 'file' ];
// get the code
if ( is_object( $cache ) )
{
// debug info
$errors->debug_info( $this->debug, 'Template', '_getfile', 'reading ' . $handle . ' from cache' );
// if possible use cache
$code = $cache->get_file( $file );
}else
{
// not possible :(
if ( is_readable( $file ) )
{
$errors->debug_info( $this->debug, 'Template', '_getfile', 'reading ' . $handle . ' from disk' );
// debug info
$code = file_get_contents( $file );
}else
{
// error if file couldn't be loaded
$errors->report_error( 'The file ' . $this->template_files[ $handle ] . ' could not be found', CRITICAL_ERROR, 'Template', '_getfile', __LINE__, ERROR_RAW );
}
}
return $code;
}
// used to output the compiled file
// $template->output( 'handle' );
// $template->output( array( 'handle1', 'handle2' ) );
function output( $handles )
{
global $errors;
$cache = $this->cache; // saves typing
// make array if not already
if ( !is_array( $handles ) )
{
$handles = array( $handles );
}
// do the stuff with each file
while ( list ( $key, $handle ) = each ( $handles ) )
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'output', 'fetching ' . $handle );
// get code
$code = $this->_getfile( $handle );
// compile it
if ( isset( $code ) ) // have to check :)
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'output', 'compiling ' . $handle );
$compiled = $this->compile( $code );
}else
{
// error if file couldn't be loaded
$errors->report_error( 'The file ' . $this->template_files[ $handle ] . ' could not be found', CRITICAL_ERROR, 'Template', '_getfile', __LINE__, ERROR_RAW );
}
// debug info
$errors->debug_info( $this->debug, 'Template', 'output', 'outputing ' . $handle );
// output it
echo $compiled;
// mark it executed
$this->template_files[ $handle ][ 'executed' ] = TRUE;
}
}
// used to fetch the compiled code of a file
// $compiled = $template->justcompile( 'handle' );
function justcompile( $handle )
{
global $errors;
// debug info
$errors->debug_info( $this->debug, 'Template', 'output', 'fetching ' . $handle );
// get code
$code = $this->_getfile( $handle );
// compile it
if ( isset( $code ) ) // have to check :)
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'justcompile', 'compiling ' . $handle );
$compiled = $this->compile( $code );
}else
{
// error if file couldn't be loaded
$errors->report_error( 'The file ' . $this->template_files[ $handle ] . ' could not be found', CRITICAL_ERROR, 'Template', '_getfile', __LINE__, ERROR_RAW );
}
// debug info
$errors->debug_info( $this->debug, 'Template', 'justcompile', 'returning ' . $handle );
// return what we got
return $compiled;
}
// used to pass variables to template
// $template->assign_vars( array( 'var1' => 'val1', 'var2' => 'val2' ) );
function assign_vars( $vars )
{
global $errors;
// go through the vars and add them
$cd = $this->_recursive_var_add( '', $vars, '$this->template_vars' );
// execute the code produced
eval( $cd );
}
// used to make a switch visible or hidden
// $template->assign_switch( 'block', TRUE );
function assign_switch( $block, $view = TRUE )
{
global $errors;
// make the block lowercase, for pretty
$block = strtolower( $block );
// $block MUST not be 'main' or _self_
if ( $block == 'main' || $block == '_self_' ) return;
// check if parent is viewable
// get parent
$par = explode( '.', $block );
if ( count( $par ) > 1 ) // if top don't bother
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'assign_switch', 'fetching parent viewabilty of ' . $block );
// separate this from parent
array_pop( $par );
$par = implode( '.', $par );
// only check last one
$cnt = '$cnt = count( $this->template_misc[ \'switches\' ]' . $this->block_hash[ $par ] . ') - 1;';
eval( $cnt );
// check
$show = '$show = $this->template_misc[ \'switches\' ]' . $this->block_hash[ $par ] . '[ ' . $cnt . ' ][ \'_self_\' ];';
eval( $show );
}else
{
$show = TRUE;
}
// if the block is not yet set set it
if ( !isset( $this->block_hash[ $block ] ) )
{
$this->assign_block_vars( $block, '', array() );
}
// generate code that will insert the flag where it is needed
if ( $show )
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'assign_switch', 'making ' . $block . ' viewable' );
$code = '$this->template_misc[ \'switches\' ]' . $this->block_hash[ $block ] . '[][ \'_self_\' ] = $view;';
}else
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'assign_switch', 'making ' . $block . ' unviewable' );
$code = '$this->template_misc[ \'switches\' ]' . $this->block_hash[ $block ] . '[][ \'_self_\' ] = FALSE;';
}
eval ( $code );
}
// used for adding levels to variables already set
// $template->assign_var_levels( 'block', 'VAR1', '', array( 'var2' => 'val2', 'var3' => 'val3' ) );
function assign_var_levels( $block, $var, $add, $itera = 'last' )
{
global $errors;
// var must not be _self_
if ( $var == '_self_' )
{
return;
}
$errors->debug_info( $this->debug, 'Template', 'assign_var_levels', 'assigning variables to ' . $block );
// set the var and simply call the correct var setting directive :)
$var = array( $var => $add );
if ( !empty( $block ) )
{
$this->assign_block_vars( $block, $itera, $var );
}else
{
$this->assign_vars( $var );
}
}
// internally used for compiling code for var assign
function _recursive_var_add( $cd, $vars, $arry )
{
global $errors;
while ( list( $var, $val ) = each ( $vars ) )
{
if ( is_array( $val ) )
{
$cd .= $this->_recursive_var_add( $cd, $val, $arry . '[ \'' . $var . '\' ]' );
}else
{
$var = strtoupper( $var );
// have been getting some nasty erros coz of this :)
// $val = preg_replace( "#^\'#", "\'", $val );
// $var = preg_replace( "#^\'#", "\'", $var );
$val = str_replace ( "'", "\'", $val );
$var = str_replace ( "'", "\'", $var );
// debug info
$errors->debug_info( $this->debug, 'Template', 'recursive_var_add', 'linking ' . $var . ' with ' . $val );
$cd .= $arry . '[ \'' . $var . '\' ][ \'_self_\' ] = ';
$cd .= ( is_string( $val ) ) ? '\'' . $val . '\';' : $val . ';';
}
}
// echo $cd .'<br/><br/>';
return $cd;
}
// used to pass objected vars to template
// $template->assign_block_vars( 'block', '', array( 'var1' => 'val1', 'var2' => 'val2' ) );
function assign_block_vars( $block, $itera, $vars )
{
global $errors;
// make the block lowercase, for pretty
$block = strtolower( $block );
// $block MUST not be 'main', _self_ or this
if ( $block == 'main' || $block == '_self_' )
{
$errors->debug_info( $this->debug, 'Template', 'assign_block_vars', $block . ' is a reserved block name' );
return;
}
// determine what iteration to add the vars to
$itera = strtolower( $itera );
if ( empty( $itera ) || $itera == 'new' )
{
$itera = '';
$ahead = TRUE;
}elseif( $itera == 'last' )
{
$itera = '';
$ahead = FALSE;
}else
{
$itera = intval( $itera );
$ahead = FALSE;
}
if ( strpos( $block, '.' ) !== FALSE ) // is this a nested thing
{
// explode nested block.
$blocks = explode( '.', $block );
$cur = end( $blocks ); // this will be added
$scope = $blocks[ count( $blocks ) - 2 ]; // this is where it needs to be added
// fetch scope from hash
$scope = $this->block_hash[ $scope ];
// this will ensure we insert to the last occurence
$c = '$cnt = count( $this->template_vars' . $scope .' ) - 1;';
eval( $c );
// debug info
$errors->debug_info( $this->debug, 'Template', 'assign_block_vars', 'assigning variables to ' . $block );
// code for insertion
if ( empty( $itera ) )
{ // get the last iteration if needed
$set = '( isset( $this->template_vars' . $scope. '[ $cnt ][ $cur . \'.\' ] ) )';
$cd = '$keys = ' . $set . ' ? array_keys( $this->template_vars' . $scope. '[ $cnt ][ $cur . \'.\' ] ) : \'\';';
eval( $cd );
$itera = ( !empty( $keys ) ) ? $keys[ count( $keys )-1 ] : -1 ;
if ( $ahead )
{ // if we're trying to go ahead
$itera++;
}
}
$arry = '$this->template_vars' . $scope. '[ $cnt ][ $cur . \'.\' ][ ' . $itera . ' ]';
$cd = $this->_recursive_var_add( '', $vars, $arry );
// execute the code produced
eval( $cd );
// debug info
$errors->debug_info( $this->debug, 'Template', 'assign_block_vars', 'adding ' . $block . ' to hash' );
// add to block hash
$this->block_hash[ $block ] = $scope. '[ ' . $cnt . ' ][ \'' . $cur . '.\' ]';
}
else
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'assign_block_vars', 'assigning variables to ' . $block );
// add the vars to the given block
if ( empty( $itera ) )
{ // get the last iteration if needed
$keys = ( isset( $this->template_vars[ $block . '.' ] ) ) ? array_keys( $this->template_vars[ $block . '.' ] ) : '';
eval( $cd );
$itera = ( !empty( $keys ) ) ? $keys[ count( $keys )-1 ] : -1 ;
if ( $ahead )
{ // if we're trying to go ahead
$itera++;
}
}
$arry = '$this->template_vars[ $block . \'.\' ][ ' . $itera . ' ]';
$cd = $this->_recursive_var_add( '', $vars, $arry );
// execute the code
eval( $cd );
// debug info
$errors->debug_info( $this->debug, 'Template', 'assign_block_vars', 'adding ' . $block . ' to hash' );// add to block hash
$this->block_hash[ $block ] = "[ '$block.' ]";
}
}
// used to retrieve the view flag of a switch
// internal use only
// $flag = $this->_getviewflag( $name, $chunk )
function _getviewflag( $switch, $chunk )
{
global $errors;
// debug info
$errors->debug_info( $this->debug, 'Template', '_getviewflag', 'fetching viewability for ' . $switch );
// if the switch is not set then it definately is not viewable
if ( !isset( $this->block_hash[ $switch ] ) )
{
return FALSE;
}
$c = $chunk[ $switch ][ 'var' ]; // loop count
// make code for flag retrieval
$block = '$this->template_misc[ \'switches\' ]' . $this->block_hash[ $switch ] . '[ ' . $c . ' ][ \'_self_\' ]';
$code = '$flag = ( isset( ' . $block . ' ) ) ? ' . $block . ' : FALSE;';
// execute
eval( $code );
return $flag;
}
// used to replace var calls with values
// internal use only
// $line = $this->_getvars( $line, $chunk );
function _getvars( $line, $chunk = 0, $count = 0 )
{
global $errors;
// find all variable references
preg_match_all( '#\{([a-z0-9\-_.:]*?)\}#is', $line, $matches );
// go through the matches
while ( list ( $v, $match ) = each ( $matches[ 1 ] ) )
{
// debug info
$errors->debug_info( $this->debug, 'Template', '_getvars', 'fetching value of ' . $match );
if ( strpos( $match, '.' ) !== FALSE )
{ // dot
// separate blocks from the variable itself
$blocks = explode( '.', $match );
$var = array_pop( $blocks );
$block = implode( '.', $blocks );
// loop count
if ( is_array( $chunk ) )
{ // normal operation
$c = $chunk[ $block ][ 'var' ];
}else
{ // manualy set operation
$c = $count;
}
if ( $block != 'this' )
{
$code = '$val = $this->template_vars' . $this->block_hash[ $block ] . '[ ' . $c . ' ]';
// make the code to retrieve value
if ( strpos( $var, ':' ) !== FALSE )
{
$var = explode( ':', $var );
while ( list ( $k, $vr ) = each ( $var ) )
{
$code .= '[ \'' . $vr . '\' ]';
}
$code .= '[ \'_self_\' ];';
}else
{
$code .= '[ \'' . $var . '\' ][ \'_self_\' ];';
}
// execute
eval( $code );
}else
{
// return data of current block
$var = strtolower( $var );
$d = end( $chunk );
$val = $d[ $var ];
}
// insert into the line
if ( isset( $var ) )
{
$line = str_replace( $matches[ 0 ][ $v ], $val, $line );
}else
{
$line = str_replace( $matches[ 0 ][ $v ], '', $line );
}
}else
{ // no dot
// deal with function argumenst
if ( strpos( $match, 'func:' ) !== FALSE )
{
$var = explode( ':', $match );
$val = $this->functions[ $var[ 1 ] ][ 'args' ][ $var[ 2 ] ];
}else
{
$code = '$val = $this->template_vars';
// make the code to retrieve value
if ( strpos( $match, ':' ) !== FALSE )
{ // aye
$var = explode( ':', $match );
while ( list ( $k, $vr ) = each ( $var ) )
{
$code .= '[ \'' . $vr . '\' ]';
}
$code .= '[ \'_self_\' ];';
}else
{ // nay
$code .= '[ \'' . $match . '\' ][ \'_self_\' ];';
}
// execute
eval( $code );
// replace with value in the array
}
if ( isset( $val ) )
{
$line = str_replace( $matches[ 0 ][ $v ], $val, $line );
}else
{
$line = str_replace( $matches[ 0 ][ $v ], '', $line );
}
}
}
return $line;
}
// used to get the number of loops a switch has
// internal only
// $num = $this->_countswitch( 'name', $chunk );
function _countswitch( $name, $chunk )
{
global $errors;
// debug info
$errors->debug_info( $this->debug, 'Template', '_countswitch', 'counting ' . $name );
// if block isn't set then count is 0
if ( !isset( $this->block_hash[ $name ] ) )
{
return FALSE;
}
// generate the code
$code = '$cnt = count( $this->template_misc[ \'switches\' ]' . $this->block_hash[ $name ] . ' );';
// execute it
eval( $code );
$errors->debug_info( $this->debug, 'Template', '_countswitch', 'Counted ' . $cnt );
return $cnt;
}
// used to parse a line of php to work
// internal use only
// $this->_parsephp( $line )
function _parsephp( $line )
{
global $errors;
// debug info
$errors->debug_info( $this->debug, 'Template', '_parsephp', 'parsing php line: <b>' . htmlspecialchars( $line ) . '</b>' );
// we have to make sure this won't mess up our variables
$line = str_replace( '$', '$embedded_', $line );
// add line delimiters if not there
if ( $line[ strlen( $line ) - 1] != ';' )
{
$line .= ';';
}
// we have to remove anything possibly dangerous
$line = preg_replace( $this->forbidden_code->php, '', $line ); // remove stuff
return $line;
}
// used to parse a line of pseudocode
// internal use only
// $this->_parsecode( $line )
function _parsecode( $line, $chunk )
{
global $errors;
// debug info
$errors->debug_info( $this->debug, 'Template', '_parsecode', 'parsing pseudocode line: <b>' . htmlspecialchars( $line ) . '</b>' );
// var calls replace with vars
$line = $this->_getvars( $line, $chunk );
// turn code into php code
$searches = array( '#([^!+-.=*/%&<>])=#',
'#(.*?)!and!(.*?)#',
'#(.*?)!or!(.*?)#',
'#not\((.*?)\)#',
'#(.*?)not(.*?)#',
'#(.*?)!div!(.*?)#',
'#(.*?)!mod!(.*?)#',
'#int\((.*?)\)#',
'#float\((.*?)\)#',
'#str\((.*?)\)#',
);
$replaces = array( '$1==',
'($1)&&($2)',
'($1)||($2)',
'!($1)',
'($1)!=($2)',
'($1)/($2)',
'($1)%($2)',
'intval("$1")',
'floatval("$1")',
'strval("$1")',
);
$line = preg_replace( $searches, $replaces, $line );
// debug info
$errors->debug_info( $this->debug, 'Template', '_parsecode', 'got line: <b>' . htmlspecialchars( $line ) . '</b>' );
return $line;
}
// used to include a file into the scope
// internal use only
// $this->_includefile( $file, $code, $point, 'php' )
function _includefile( $file, &$code, $point, &$codelength, $special = FALSE )
{
global $errors;
// debug info
$errors->debug_info( $this->debug, 'Template', '_includefile', 'fetching' . $file );
// get the code for inclusion
$insert = $this->_getfile( $file );
$insert = explode( "\n", $insert ); // separate into lines
// codelength has to be updated
$old = $codelength;
$codelength += count( $insert );
$errors->debug_info( $this->debug, 'Template', '_includefile', 'Updating codelength from ' . $old . ' to ' . $codelength );
// debug info
$errors->debug_info( $this->debug, 'Template', '_includefile', 'sticking fetched into the code scope' );
// insert the lines into the code
$rest = array_slice( $code, $point ); // code bellow the line
if ( !$special )
{
array_shift( $rest ); // remove this line
}else
{
switch ( $special )
{
case 'php':
// first line of insert delimits start of php
$insert = array_merge( array( '<!-- PHP -->' ), $insert );
// first line of rest delimits end of php
$rest[ 0 ] = '<!-- PHPEND -->';
break;
}
}
$rest = array_merge( $insert, $rest ); // exploded line and the rest
$code = array_slice( $code, 0, $point ); // get first part of code
$code = array_merge( $code, $rest ); // put together
}
// inserts code into the scope
// internal use only
// $this->_insertcode( $code, $point, array( 'line1', 'line2' ), $codelength );
// continue; (this is a must)
function _insertcode( &$code, &$point, $insert, &$codelength )
{
global $errors;
// codelength has to be updated
$old = $codelength;
$codelength += count( $insert );
$errors->debug_info( $this->debug, 'Template', '_insertcode', 'Updating codelength from ' . $old . ' to ' . $codelength );
// debug info
$errors->debug_info( $this->debug, 'Template', '_insertcode', 'inserting code into the scope: <b>' . htmlspecialchars( implode( ';;', $insert ) ) . '</b>' );
// insert
$rest = array_slice( $code, $point ); // code bellow the line
array_shift( $rest ); // remove this line
$rest = array_merge( $insert, $rest ); // exploded line and the rest
$code = array_slice( $code, 0, $point ); // get first part of code
$code = array_merge( $code, $rest ); // put together
// re-execute this line
$point--;
}
// generalizes line breaks (everything to \n)
function gennuline( $str )
{
return str_replace( "\r", "\n", str_replace( "\r\n", "\n", $str ) );
}
// used to compile template code
// $compiled = $template->compile( $code );
function compile( $code )
{
global $errors;
$compiled = array( );
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', '<b>compiler started</b>' );
// remove any php
$tags = array( '#\<\?php .*?\?\>#is', '#\<\script language="php".*?\>.*?\<\/script\>#is', '#\<\?.*?\?\>#s', '#\<%.*?%\>#s' );
$code = preg_replace( $tags, '', $code );
// separate code into lines
$code = explode( "\n", $code );
// go through lines and do the stuff
$point = 0; // line pointer
$chunk[ 'main' ][ 'view' ] = TRUE; // code chunk we're in
$codelength = count( $code ); // number of code lines
$is_special_code = FALSE; // tells if currently any special code is being used(php, JS..)
$special_code = array();// the special code goes here
$function = FALSE; // not adding a function are we now
$funct_code = array(); // you know why
$funct_name = ''; // no name yet
$justprint = FALSE; // not "justprinting"
while ( $point <= $codelength )
{
// get the line
$line = $code[ $point ];
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'got line <b>' . htmlspecialchars( $line ) . '</b>' );
//
// compile the line
//
// function creation
if ( $function && $line != '<!-- ENDFUNCTION -->' )
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'add line to function ' . $funct_name );
$funct_code[] = $line;
// no need to go on
$point++;
continue;
}
// end function creation
// determine if this is curently viewable
$info = end( $chunk );
if ( $info[ 'view' ] )
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'line viewable' );
}else
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'line unviewable' );
}
// special code support
if ( $is_special_code != FALSE && $line != '<!-- PHPEND -->' && $info[ 'view' ] )
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'adding line to ' . $is_special_code . ' code scope' );
// determine code and what to do
switch ( $is_special_code )
{
case 'php':
$parsed_line = $this->_parsephp( $line );
break;
}
// add to scope
$special_code[] = $parsed_line;
// jump through this
$point++;
continue;
}
// end special code support
// print this line only if not switch statement
if ( $justprint && strpos( $line, '<!-- END JUSTPRINT -->' ) === FALSE )
{ // just output the thing
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'add line to compiled scope' );
// add line to compiled code
$compiled[] = $line;
}elseif ( strpos( $line, '<!--' ) === FALSE )
{
// variables
if ( $info[ 'view' ] && !$function )
{
$line = $this->_getvars( $line, $chunk );
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'add line to compiled scope' );
// add line to compiled code
$compiled[] = $line;
}
}else
{
// switches/loops
// get the number of switch statements
preg_match_all( '#<!-- (.*?) -->#', $line, $matches );
$switches = count( $matches[ 1 ] );
// if more than one split the line
if ( $switches > 1 )
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'more than one switch statement, breaking line up' );
// split
$lines = preg_split( '#<!-- (.*?) -->#', $code[ $point ] );
// put the switch calls back in
$whereto = 0;
$i = 0;
while ( $i < count( $matches[ 1 ] ) )
{
if ( empty( $lines[ $whereto ] ) )
{
$switch = $matches[ 1 ][ $i ];
$lines[ $whereto ] = "<!-- $switch -->";
$i++;
}
$whereto++;
}
// insert the lines into the code
$this->_insertcode( $code, $point, $lines, $codelength );
continue;
}
// get the switch statement
preg_match( '#<!-- (.*?) -->#', $line, $switch );
// separate switch statement from it's name
$switch = explode( " ", $switch[ 1 ] );
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'executing switch specific stuff' );
// do according to the switch
$statement = $switch[ 0 ];
$name = $switch[ 1 ];
$viewable = $info[ 'view' ]; // when older code clashes with new stuff, this is what you need
switch ( $statement )
{
case 'ASSIGN':
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'executing assign variable command' );
// get values
$var = $name;
$val = $switch[ 2 ];
// do we need to fetch a var for the value
if ( strpos( $val, '{' ) !== FALSE )
{
$val = $this->_getvars( $val, $chunk );
}
// decide on the block to use
if ( strpos( $var, '.' ) === FALSE )
{
$this->assign_vars( array( $var => $val ) );
}else
{
// get the block
$blocks = explode( '.', $var );
$var = array_pop( $blocks );
$block = implode( '.', $blocks );
// execute according to the block
if ( $block == 'this' )
{
// check if 'this' is main
if ( count( $chunk ) == 1 )
{ // is main
$this->assign_vars( array( $var => $val ) );
}else
{ // not main
// get block
$d = end( $chunk );
$block = $d[ 'name' ];
$i = $d[ 'var' ];
$this->assign_block_vars( $block, $i, array( $var => $val ) );
}
}else
{
$this->assign_block_vars( $block, 'last', array( $var => $val ) );
}
}
break;
case 'FUNCTION':
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'beginning a function' );
// deal with the arguments
$args = explode( ',', $switch[ 2 ] );
while ( list( $k, $v ) = each( $args ) )
{
$this->functions[ $name ][ 'args' ][ $k ] = '';
}
// state that now we'll be adding a function
$function = TRUE;
$funct_code = array();
$funct_name = $name;
break;
case 'ENDFUNCTION':
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'ending a function' );
// generate the function
$funct_code = implode( "\n", $funct_code );
$this->functions[ $funct_name ][ '_code_' ] = $funct_code;
// state we're no longer in a function
$function = FALSE;
$funct_code = array();
$funct_name = '';
break;
case 'EXECUTE':
// don't bother if not visible
if ( $viewable )
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'executing a function' );
// deal with the arguments
$args = explode( ',', $switch[ 2 ] );
// enough arguments?
if ( count( $args ) != count( $this->functions[ $name ][ 'args' ] ) )
{
continue;
}
// set values
while ( list( $k, $v ) = each( $args ) )
{
$this->functions[ $name ][ 'args' ][ $k ] = $v;
}
// get code
$funct = $this->functions[ $name ][ '_code_' ];
$funct = explode( "\n", $funct );
// insert the function into the code
$this->_insertcode( $code, $point, $funct, $codelength );
continue;
}
break;
case 'PHP':
// don't bother if this is currently hidden
if ( $viewable )
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'beginning php code' );
// denote start of php code
$is_special_code = 'php';
$special_code = array();
}
break;
case 'PHPEND':
// don't bother if this is currently hidden
if ( $viewable )
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'ending php code' );
// execute gathered php code
$special_code = implode( "\n", $special_code );
eval( $special_code );
// denote end of php code
$is_special_code = FALSE;
$special_code = array();
}
break;
case 'ELSE':
// still needs checking?
if ( $chunk[ $name ][ 'check' ] )
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', '"elsing"' );
// set the name of chunk for easier use later on
$chunk[ $name ][ 'name' ] = $name;
// set the var pointer
$chunk[ $name ][ 'var' ] = 0;
// loop count to none as it's in no way a loop
$chunk[ $name ][ 'count' ] = 1;
$chunk[ $name ][ 'view' ] = TRUE; // viewable
$chunk[ $name ][ 'check' ] = FALSE; // don't check anymore
}else
{
$chunk[ $name ][ 'view' ] = FALSE;
}
break;
case 'ELSEIF':
// still needs checking?
if ( $chunk[ $name ][ 'check' ] )
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', '"elseifing"' );
// set the name of chunk for easier use later on
$chunk[ $name ][ 'name' ] = $name;
// set the var pointer
$chunk[ $name ][ 'var' ] = 0;
// loop count to none as it's in no way a loop
$chunk[ $name ][ 'count' ] = 1;
// get code to parse
$ln = implode( " ", $switch );
$pseudo = $switch[ 2 ];
$pseudo = $this->_parsecode( $pseudo, $chunk );
$show = FALSE;
$pseudo = 'if (' . $pseudo . ') $show = TRUE;';
// execute code
eval( $pseudo );
if ( $show ) // check
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'making viewable' );
$chunk[ $name ][ 'view' ] = TRUE; // viewable
$chunk[ $name ][ 'check' ] = FALSE; // don't check anymore
}else
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'making nonviewable' );
$chunk[ $name ][ 'view' ] = FALSE; // nonviewable
$chunk[ $name ][ 'check' ] = TRUE; // do check more
}
}else
{
$chunk[ $name ][ 'view' ] = FALSE;
}
break;
case 'IF':
// don't bother if this is currently hidden
if ( $viewable )
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', '"ifing"' );
// set the name of chunk for easier use later on
$chunk[ $name ][ 'name' ] = $name;
// set the var pointer
$chunk[ $name ][ 'var' ] = 0;
// loop count to none as it's in no way a loop
$chunk[ $name ][ 'count' ] = 1;
// get code to parse
$ln = implode( " ", $switch );
$pseudo = $switch[ 2 ];
$pseudo = $this->_parsecode( $pseudo, $chunk );
$show = FALSE;
$pseudo = 'if (' . $pseudo . ') $show = TRUE;';
// execute code
eval( $pseudo );
if ( $show ) // check
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'making viewable' );
$chunk[ $name ][ 'view' ] = TRUE; // viewable
$chunk[ $name ][ 'check' ] = FALSE; // don't check anymore
}else
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'making nonviewable' );
$chunk[ $name ][ 'view' ] = FALSE; // nonviewable
$chunk[ $name ][ 'check' ] = TRUE; // do check more
}
}
break;
case 'INCLUDE':
// don't bother if this is currently hidden
if ( $viewable )
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'including ' . $name );
$this->_includefile( $name, $code, $point, $codelength ); // include
$point--; // this line needs to get recompiled
continue; // just jump through
}
break;
case 'INCLUDEPHP':
// don't bother if this is currently hidden
if ( $viewable )
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'including php ' . $name );
$this->_includefile( $name, $code, $point, $codelength . 'php' ); // include
$point--; // this line needs to get recompiled
continue; // just jump through
}
break;
case 'EVEN':
// don't bother if this is currently hidden
if ( $viewable )
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'is even? ' . $switch[ 2 ] );
// set the name of chunk for easier use later on
$chunk[ $name ][ 'name' ] = $name;
// set the var pointer
$chunk[ $name ][ 'var' ] = 0;
// loop count to none as it's in no way a loop
$chunk[ $name ][ 'count' ] = 1;
$var = $switch[ 2 ]; // get the var to check
$var = $this->_getvars( $var, $chunk ); // change to value
if ( $var % 2 == 0 || $var == 0 ) // check
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'it is' );
$chunk[ $name ][ 'view' ] = TRUE; // viewable
}else
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'it isn\'t' );
$chunk[ $name ][ 'view' ] = FALSE; // nonviewable
}
}
break;
case 'ODD':
// don't bother if this is currently hidden
if ( $viewable )
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'is odd? ' . $switch[ 2 ] );
// set the name of chunk for easier use later on
$chunk[ $name ][ 'name' ] = $name;
// set the var pointer
$chunk[ $name ][ 'var' ] = 0;
// loop count to none as it's in no way a loop
$chunk[ $name ][ 'count' ] = 1;
$var = $switch[ 2 ]; // get the var to check
$var = $this->_getvars( $var, $chunk ); // change to value
if ( $var % 2 != 0 ) // check
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'it is' );
$chunk[ $name ][ 'view' ] = TRUE; // viewable
}else
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'it isn\'t' );
$chunk[ $name ][ 'view' ] = FALSE; // nonviewable
}
}
break;
case 'NOT':
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'negating switch ' . $name );
if ( !isset( $chunk[ $name ] ) ) // only set the first time
{
// set return point
$chunk[ $name ][ 'return' ] = $point;
// set the name of chunk for easier use later on
$chunk[ $name ][ 'name' ] = $name;
// set the var pointer
$chunk[ $name ][ 'var' ] = 0;
// loop count
$chunk[ $name ][ 'count' ] = $this->_countswitch( $name, $chunk );
}
// parent view flag
$info = $chunk;
array_pop( $info );
$info = end( $info );
// set the view flag
if ( !$this->_getviewflag( $name, $chunk ) && $info[ 'view' ] )
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'viewable' );
$chunk[ $name ][ 'view' ] = TRUE; // viewable
}else
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'nonviewable' );
$chunk[ $name ][ 'view' ] = FALSE; // nonviewable
}
break;
case 'BEGIN':
// check for justprint
if ( $name == 'JUSTPRINT' )
{
$justprint = TRUE;
$point++;
continue;
}
if ( !isset( $chunk[ $name ] ) ) // only set the first time
{
// set return point
$chunk[ $name ][ 'return' ] = $point;
// set the name of chunk for easier use later on
$chunk[ $name ][ 'name' ] = $name;
// set the var pointer
$chunk[ $name ][ 'var' ] = 0;
// loop count
$chunk[ $name ][ 'count' ] = $this->_countswitch( $name, $chunk );
}
// set the view flag
if ( $this->_getviewflag( $name, $chunk ) && $viewable )
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'block ' . $name . ' viewable' );
$chunk[ $name ][ 'view' ] = TRUE; // viewable
}else
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'block ' . $name . ' nonviewable' );
$chunk[ $name ][ 'view' ] = FALSE; // nonviewable
}
break;
case 'END':
// check for justprint
if ( $name == 'JUSTPRINT' )
{
$justprint = FALSE;
$point++;
continue;
}
// loop if needed
if ( $chunk[ $name ][ 'count' ] > 1 )
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'go for another loop of ' . $name );
$chunk[ $name ][ 'count' ]--; // loop count decrease
$chunk[ $name ][ 'var' ]++; // var pointer increase
$point = $chunk[ $name ][ 'return' ] - 1; // line pointer...
}else
{
// debug info
$errors->debug_info( $this->debug, 'Template', 'compile', 'end block ' . $name );
// remove chunk data
unset( $chunk[ $name ] );
}
break;
}
// end switch stuff
} // end is switch if
// increase line pointer
$point++;
}
// put the compiled code together
$compiled = implode( "\n", $compiled );
return $compiled;
}
//
// End template class
//
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment