Created
February 3, 2022 16:06
-
-
Save Swizec/90ab6872f60cdceb252c1c90fb53838d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/////////////////////////////////////////////////////////////////// | |
// // | |
// file: template.php // | |
// scripter: swizec // | |
// contact: [email protected] // | |
// 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