Created
May 16, 2018 20:27
-
-
Save savasdersimcelik/71c722043638367e5a2d76021f99a9a3 to your computer and use it in GitHub Desktop.
RainTPL Classına ait kodlar
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 | |
/** | |
* RainTPL | |
* ------- | |
* Realized by Federico Ulfo & maintained by the Rain Team | |
* Distributed under the MIT license http://www.opensource.org/licenses/mit-license.php | |
* | |
* @version 2.7.2 | |
*/ | |
class RainTPL{ | |
// ------------------------- | |
// CONFIGURATION | |
// ------------------------- | |
/** | |
* Template directory | |
* | |
* @var string | |
*/ | |
static $tpl_dir = "tpl/"; | |
/** | |
* Cache directory. Is the directory where RainTPL will compile the template and save the cache | |
* | |
* @var string | |
*/ | |
static $cache_dir = "tmp/"; | |
/** | |
* Template base URL. RainTPL will add this URL to the relative paths of element selected in $path_replace_list. | |
* | |
* @var string | |
*/ | |
static $base_url = null; | |
/** | |
* Template extension. | |
* | |
* @var string | |
*/ | |
static $tpl_ext = "html"; | |
/** | |
* Path replace is a cool features that replace all relative paths of images (<img src="...">), stylesheet (<link href="...">), script (<script src="...">) and link (<a href="...">) | |
* Set true to enable the path replace. | |
* | |
* @var unknown_type | |
*/ | |
static $path_replace = false; | |
/** | |
* You can set what the path_replace method will replace. | |
* Avaible options: a, img, link, script, input | |
* | |
* @var array | |
*/ | |
static $path_replace_list = array( 'a', 'img', 'link', 'script', 'input' ); | |
/** | |
* You can define in the black list what string are disabled into the template tags | |
* | |
* @var unknown_type | |
*/ | |
static $black_list = array( '\$this', 'raintpl::', 'self::', '_SESSION', '_SERVER', '_ENV', 'eval', 'exec', 'unlink', 'rmdir' ); | |
/** | |
* Check template. | |
* true: checks template update time, if changed it compile them | |
* false: loads the compiled template. Set false if server doesn't have write permission for cache_directory. | |
* | |
*/ | |
static $check_template_update = true; | |
/** | |
* PHP tags <? ?> | |
* True: php tags are enabled into the template | |
* False: php tags are disabled into the template and rendered as html | |
* | |
* @var bool | |
*/ | |
static $php_enabled = false; | |
/** | |
* Debug mode flag. | |
* True: debug mode is used, syntax errors are displayed directly in template. Execution of script is not terminated. | |
* False: exception is thrown on found error. | |
* | |
* @var bool | |
*/ | |
static $debug = false; | |
/** | |
* Path for the root directory | |
* | |
* @var string | |
*/ | |
static $root_dir = ''; | |
// ------------------------- | |
// ------------------------- | |
// RAINTPL VARIABLES | |
// ------------------------- | |
/** | |
* Is the array where RainTPL keep the variables assigned | |
* | |
* @var array | |
*/ | |
public $var = array(); | |
protected $tpl = array(), // variables to keep the template directories and info | |
$cache = false, // static cache enabled / disabled | |
$cache_id = null; // identify only one cache | |
protected static $config_name_sum = array(); // takes all the config to create the md5 of the file | |
// ------------------------- | |
const CACHE_EXPIRE_TIME = 3600; // default cache expire time = hour | |
/** | |
* Assign variable | |
* eg. $t->assign('name','mickey'); | |
* | |
* @param mixed $variable_name Name of template variable or associative array name/value | |
* @param mixed $value value assigned to this variable. Not set if variable_name is an associative array | |
*/ | |
function assign( $variable, $value = null ){ | |
if( is_array( $variable ) ) | |
$this->var = $variable + $this->var; | |
else | |
$this->var[ $variable ] = $value; | |
} | |
/** | |
* Draw the template | |
* eg. $html = $tpl->draw( 'demo', TRUE ); // return template in string | |
* or $tpl->draw( $tpl_name ); // echo the template | |
* | |
* @param string $tpl_name template to load | |
* @param boolean $return_string true=return a string, false=echo the template | |
* @return string | |
*/ | |
function draw( $tpl_name, $return_string = false ){ | |
try { | |
// compile the template if necessary and set the template filepath | |
$this->check_template( $tpl_name ); | |
} catch (RainTpl_Exception $e) { | |
$output = $this->printDebug($e); | |
die($output); | |
} | |
// Cache is off and, return_string is false | |
// Rain just echo the template | |
if( !$this->cache && !$return_string ){ | |
extract( $this->var ); | |
include $this->tpl['compiled_filename']; | |
unset( $this->tpl ); | |
} | |
// cache or return_string are enabled | |
// rain get the output buffer to save the output in the cache or to return it as string | |
else{ | |
//---------------------- | |
// get the output buffer | |
//---------------------- | |
ob_start(); | |
extract( $this->var ); | |
include $this->tpl['compiled_filename']; | |
$raintpl_contents = ob_get_clean(); | |
//---------------------- | |
// save the output in the cache | |
if( $this->cache ) | |
file_put_contents( $this->tpl['cache_filename'], "<?php if(!class_exists('raintpl')){exit;}?>" . $raintpl_contents ); | |
// free memory | |
unset( $this->tpl ); | |
// return or print the template | |
if( $return_string ) return $raintpl_contents; else echo $raintpl_contents; | |
} | |
} | |
/** | |
* If exists a valid cache for this template it returns the cache | |
* | |
* @param string $tpl_name Name of template (set the same of draw) | |
* @param int $expiration_time Set after how many seconds the cache expire and must be regenerated | |
* @return string it return the HTML or null if the cache must be recreated | |
*/ | |
function cache( $tpl_name, $expire_time = self::CACHE_EXPIRE_TIME, $cache_id = null ){ | |
// set the cache_id | |
$this->cache_id = $cache_id; | |
if( !$this->check_template( $tpl_name ) && file_exists( $this->tpl['cache_filename'] ) && ( time() - filemtime( $this->tpl['cache_filename'] ) < $expire_time ) ){ | |
// return the cached file as HTML. It remove the first 43 character, which are a PHP code to secure the file <?php if(!class_exists('raintpl')){exit;}? > | |
return substr( file_get_contents( $this->tpl['cache_filename'] ), 43 ); | |
} | |
else{ | |
//delete the cache of the selected template | |
if (file_exists($this->tpl['cache_filename'])) | |
unlink($this->tpl['cache_filename'] ); | |
$this->cache = true; | |
} | |
} | |
/** | |
* Configure the settings of RainTPL | |
* | |
*/ | |
static function configure( $setting, $value = null ){ | |
if( is_array( $setting ) ) | |
foreach( $setting as $key => $value ) | |
self::configure( $key, $value ); | |
else if( property_exists( __CLASS__, $setting ) ){ | |
self::$$setting = $value; | |
self::$config_name_sum[ $setting ] = $value; // take trace of all config | |
} | |
} | |
// check if has to compile the template | |
// return true if the template has changed | |
protected function check_template( $tpl_name ){ | |
if( !isset($this->tpl['checked']) ){ | |
$tpl_basename = basename( $tpl_name ); // template basename | |
$tpl_basedir = strpos($tpl_name,"/") ? dirname($tpl_name) . '/' : null; // template basedirectory | |
$this->tpl['template_directory'] = self::$tpl_dir . $tpl_basedir; // template directory | |
$this->tpl['tpl_filename'] = self::$root_dir . $this->tpl['template_directory'] . $tpl_basename . '.' . self::$tpl_ext; // template filename | |
$temp_compiled_filename = self::$root_dir . self::$cache_dir . $tpl_basename . "." . md5( $this->tpl['template_directory'] . serialize(self::$config_name_sum)); | |
$this->tpl['compiled_filename'] = $temp_compiled_filename . '.rtpl.php'; // cache filename | |
$this->tpl['cache_filename'] = $temp_compiled_filename . '.s_' . $this->cache_id . '.rtpl.php'; // static cache filename | |
$this->tpl['checked'] = true; | |
// if the template doesn't exist and is not an external source throw an error | |
if( self::$check_template_update && !file_exists( $this->tpl['tpl_filename'] ) && !preg_match('/http/', $tpl_name) ){ | |
$e = new RainTpl_NotFoundException( 'Template '. $tpl_basename .' not found!' ); | |
throw $e->setTemplateFile($this->tpl['tpl_filename']); | |
} | |
// We check if the template is not an external source | |
if(preg_match('/http/', $tpl_name)){ | |
$this->compileFile('', '', $tpl_name, self::$root_dir . self::$cache_dir, $this->tpl['compiled_filename'] ); | |
return true; | |
} | |
// file doesn't exist, or the template was updated, Rain will compile the template | |
elseif( !file_exists( $this->tpl['compiled_filename'] ) || ( self::$check_template_update && filemtime($this->tpl['compiled_filename']) < filemtime( $this->tpl['tpl_filename'] ) ) ){ | |
$this->compileFile( $tpl_basename, $tpl_basedir, $this->tpl['tpl_filename'], self::$root_dir . self::$cache_dir, $this->tpl['compiled_filename'] ); | |
return true; | |
} | |
} | |
} | |
/** | |
* execute stripslaches() on the xml block. Invoqued by preg_replace_callback function below | |
* @access protected | |
*/ | |
protected function xml_reSubstitution($capture) { | |
return "<?php echo '<?xml ".stripslashes($capture[1])." ?>'; ?>"; | |
} | |
/** | |
* Compile and write the compiled template file | |
* @access protected | |
*/ | |
protected function compileFile( $tpl_basename, $tpl_basedir, $tpl_filename, $cache_dir, $compiled_filename ){ | |
//read template file | |
$this->tpl['source'] = $template_code = file_get_contents( $tpl_filename ); | |
//xml substitution | |
$template_code = preg_replace( "/<\?xml(.*?)\?>/s", "##XML\\1XML##", $template_code ); | |
//disable php tag | |
if( !self::$php_enabled ) | |
$template_code = str_replace( array("<?","?>"), array("<?","?>"), $template_code ); | |
//xml re-substitution | |
$template_code = preg_replace_callback ( "/##XML(.*?)XML##/s", array($this, 'xml_reSubstitution'), $template_code ); | |
//compile template | |
$template_compiled = "<?php if(!class_exists('raintpl')){exit;}?>" . $this->compileTemplate( $template_code, $tpl_basedir ); | |
// fix the php-eating-newline-after-closing-tag-problem | |
$template_compiled = str_replace( "?>\n", "?>\n\n", $template_compiled ); | |
// create directories | |
if( !is_dir( $cache_dir ) ) | |
mkdir( $cache_dir, 0755, true ); | |
if( !is_writable( $cache_dir ) ) | |
throw new RainTpl_Exception ('Cache directory ' . $cache_dir . 'doesn\'t have write permission. Set write permission or set RAINTPL_CHECK_TEMPLATE_UPDATE to false. More details on https://feulf.github.io/raintpl'); | |
//write compiled file | |
file_put_contents( $compiled_filename, $template_compiled ); | |
} | |
/** | |
* Compile template | |
* @access protected | |
*/ | |
protected function compileTemplate( $template_code, $tpl_basedir ){ | |
//tag list | |
$tag_regexp = array( 'loop' => '(\{loop(?: name){0,1}="\${0,1}[^"]*"\})', | |
'break' => '(\{break\})', | |
'loop_close' => '(\{\/loop\})', | |
'if' => '(\{if(?: condition){0,1}="[^"]*"\})', | |
'elseif' => '(\{elseif(?: condition){0,1}="[^"]*"\})', | |
'else' => '(\{else\})', | |
'if_close' => '(\{\/if\})', | |
'function' => '(\{function="[^"]*"\})', | |
'noparse' => '(\{noparse\})', | |
'noparse_close'=> '(\{\/noparse\})', | |
'ignore' => '(\{ignore\}|\{\*)', | |
'ignore_close' => '(\{\/ignore\}|\*\})', | |
'include' => '(\{include="[^"]*"(?: cache="[^"]*")?\})', | |
'template_info'=> '(\{\$template_info\})', | |
'function' => '(\{function="(\w*?)(?:.*?)"\})' | |
); | |
$tag_regexp = "/" . join( "|", $tag_regexp ) . "/"; | |
//path replace (src of img, background and href of link) | |
$template_code = $this->path_replace( $template_code, $tpl_basedir ); | |
//split the code with the tags regexp | |
$template_code = preg_split ( $tag_regexp, $template_code, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY ); | |
//compile the code | |
$compiled_code = $this->compileCode( $template_code ); | |
//return the compiled code | |
return $compiled_code; | |
} | |
/** | |
* Compile the code | |
* @access protected | |
*/ | |
protected function compileCode( $parsed_code ){ | |
// if parsed code is empty return null string | |
if( !$parsed_code ) | |
return ""; | |
//variables initialization | |
$compiled_code = $open_if = $comment_is_open = $ignore_is_open = null; | |
$loop_level = 0; | |
//read all parsed code | |
foreach( $parsed_code as $html ){ | |
//close ignore tag | |
if( !$comment_is_open && ( strpos( $html, '{/ignore}' ) !== FALSE || strpos( $html, '*}' ) !== FALSE ) ) | |
$ignore_is_open = false; | |
//code between tag ignore id deleted | |
elseif( $ignore_is_open ){ | |
//ignore the code | |
} | |
//close no parse tag | |
elseif( strpos( $html, '{/noparse}' ) !== FALSE ) | |
$comment_is_open = false; | |
//code between tag noparse is not compiled | |
elseif( $comment_is_open ) | |
$compiled_code .= $html; | |
//ignore | |
elseif( strpos( $html, '{ignore}' ) !== FALSE || strpos( $html, '{*' ) !== FALSE ) | |
$ignore_is_open = true; | |
//noparse | |
elseif( strpos( $html, '{noparse}' ) !== FALSE ) | |
$comment_is_open = true; | |
//include tag | |
elseif( preg_match( '/\{include="([^"]*)"(?: cache="([^"]*)"){0,1}\}/', $html, $code ) ){ | |
if (preg_match("/http/", $code[1])) { | |
$content = file_get_contents($code[1]); | |
$compiled_code .= $content; | |
} else { | |
//variables substitution | |
$include_var = $this->var_replace( $code[ 1 ], $left_delimiter = null, $right_delimiter = null, $php_left_delimiter = '".' , $php_right_delimiter = '."', $loop_level ); | |
//get the folder of the actual template | |
$actual_folder = substr( $this->tpl['template_directory'], strlen(self::$tpl_dir) ); | |
//get the included template | |
$include_template = $actual_folder . $include_var; | |
// reduce the path | |
$include_template = $this->reduce_path( $include_template ); | |
// if the cache is active | |
if( isset($code[ 2 ]) ){ | |
//include | |
$compiled_code .= '<?php $tpl = new '.get_called_class().';' . | |
'if( $cache = $tpl->cache( "'.$include_template.'" ) )' . | |
' echo $cache;' . | |
'else{' . | |
'$tpl->assign( $this->var );' . | |
( !$loop_level ? null : '$tpl->assign( "key", $key'.$loop_level.' ); $tpl->assign( "value", $value'.$loop_level.' );' ). | |
'$tpl->draw( "'.$include_template.'" );'. | |
'}' . | |
'?>'; | |
} | |
else{ | |
//include | |
$compiled_code .= '<?php $tpl = new '.get_called_class().';' . | |
'$tpl->assign( $this->var );' . | |
( !$loop_level ? null : '$tpl->assign( "key", $key'.$loop_level.' ); $tpl->assign( "value", $value'.$loop_level.' );' ). | |
'$tpl->draw( "'.$include_template.'" );'. | |
'?>'; | |
} | |
} | |
} | |
//loop | |
elseif( preg_match( '/\{loop(?: name){0,1}="\${0,1}([^"]*)"\}/', $html, $code ) ){ | |
//increase the loop counter | |
$loop_level++; | |
//replace the variable in the loop | |
$var = $this->var_replace( '$' . $code[ 1 ], $tag_left_delimiter=null, $tag_right_delimiter=null, $php_left_delimiter=null, $php_right_delimiter=null, $loop_level-1 ); | |
//loop variables | |
$counter = "\$counter$loop_level"; // count iteration | |
$key = "\$key$loop_level"; // key | |
$value = "\$value$loop_level"; // value | |
//loop code | |
$compiled_code .= "<?php $counter=-1; if( !is_null($var) && is_array($var) && sizeof($var) ) foreach( $var as $key => $value ){ $counter++; ?>"; | |
} | |
// loop break | |
elseif( strpos( $html, '{break}' ) !== FALSE ) { | |
//else code | |
$compiled_code .= '<?php break; ?>'; | |
} | |
//close loop tag | |
elseif( strpos( $html, '{/loop}' ) !== FALSE ) { | |
//iterator | |
$counter = "\$counter$loop_level"; | |
//decrease the loop counter | |
$loop_level--; | |
//close loop code | |
$compiled_code .= "<?php } ?>"; | |
} | |
//if | |
elseif( preg_match( '/\{if(?: condition){0,1}="([^"]*)"\}/', $html, $code ) ){ | |
//increase open if counter (for intendation) | |
$open_if++; | |
//tag | |
$tag = $code[ 0 ]; | |
//condition attribute | |
$condition = $code[ 1 ]; | |
// check if there's any function disabled by black_list | |
$this->function_check( $tag ); | |
//variable substitution into condition (no delimiter into the condition) | |
$parsed_condition = $this->var_replace( $condition, $tag_left_delimiter = null, $tag_right_delimiter = null, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level ); | |
//if code | |
$compiled_code .= "<?php if( $parsed_condition ){ ?>"; | |
} | |
//elseif | |
elseif( preg_match( '/\{elseif(?: condition){0,1}="([^"]*)"\}/', $html, $code ) ){ | |
//tag | |
$tag = $code[ 0 ]; | |
//condition attribute | |
$condition = $code[ 1 ]; | |
//variable substitution into condition (no delimiter into the condition) | |
$parsed_condition = $this->var_replace( $condition, $tag_left_delimiter = null, $tag_right_delimiter = null, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level ); | |
//elseif code | |
$compiled_code .= "<?php }elseif( $parsed_condition ){ ?>"; | |
} | |
//else | |
elseif( strpos( $html, '{else}' ) !== FALSE ) { | |
//else code | |
$compiled_code .= '<?php }else{ ?>'; | |
} | |
//close if tag | |
elseif( strpos( $html, '{/if}' ) !== FALSE ) { | |
//decrease if counter | |
$open_if--; | |
// close if code | |
$compiled_code .= '<?php } ?>'; | |
} | |
//function | |
elseif( preg_match( '/\{function="(\w*)(.*?)"\}/', $html, $code ) ){ | |
//tag | |
$tag = $code[ 0 ]; | |
//function | |
$function = $code[ 1 ]; | |
// check if there's any function disabled by black_list | |
$this->function_check( $tag ); | |
if( empty( $code[ 2 ] ) ) | |
$parsed_function = $function . "()"; | |
else | |
// parse the function | |
$parsed_function = $function . $this->var_replace( $code[ 2 ], $tag_left_delimiter = null, $tag_right_delimiter = null, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level ); | |
//if code | |
$compiled_code .= "<?php echo $parsed_function; ?>"; | |
} | |
// show all vars | |
elseif ( strpos( $html, '{$template_info}' ) !== FALSE ) { | |
//tag | |
$tag = '{$template_info}'; | |
//if code | |
$compiled_code .= '<?php echo "<pre>"; print_r( $this->var ); echo "</pre>"; ?>'; | |
} | |
//all html code | |
else{ | |
//variables substitution (es. {$title}) | |
$html = $this->var_replace( $html, $left_delimiter = '\{', $right_delimiter = '\}', $php_left_delimiter = '<?php ', $php_right_delimiter = ';?>', $loop_level, $echo = true ); | |
//const substitution (es. {#CONST#}) | |
$html = $this->const_replace( $html, $left_delimiter = '\{', $right_delimiter = '\}', $php_left_delimiter = '<?php ', $php_right_delimiter = ';?>', $loop_level, $echo = true ); | |
//functions substitution (es. {"string"|functions}) | |
$compiled_code .= $this->func_replace( $html, $left_delimiter = '\{', $right_delimiter = '\}', $php_left_delimiter = '<?php ', $php_right_delimiter = ';?>', $loop_level, $echo = true ); | |
} | |
} | |
if( $open_if > 0 ) { | |
$e = new RainTpl_SyntaxException('Error! You need to close an {if} tag in ' . $this->tpl['tpl_filename'] . ' template'); | |
throw $e->setTemplateFile($this->tpl['tpl_filename']); | |
} | |
return $compiled_code; | |
} | |
/** | |
* Reduce a path, eg. www/library/../filepath//file => www/filepath/file | |
* @param type $path | |
* @return type | |
*/ | |
protected function reduce_path( $path ){ | |
$path = str_replace( "://", "@not_replace@", $path ); | |
$path = preg_replace( "#(/+)#", "/", $path ); | |
$path = preg_replace( "#(/\./+)#", "/", $path ); | |
$path = str_replace( "@not_replace@", "://", $path ); | |
while( preg_match( '#\.\./#', $path ) ){ | |
$path = preg_replace('#\w+/\.\./#', '', $path ); | |
} | |
return $path; | |
} | |
/** | |
* Replace URL according to the following rules: | |
* http://url => http://url | |
* url# => url | |
* /url => base_dir/url | |
* url => path/url (where path generally is base_url/template_dir) | |
* (The last one is => base_dir/url for <a> href) | |
* | |
* @param string $url Url to rewrite. | |
* @param string $tag Tag in which the url has been found. | |
* @param string $path Path to prepend to relative URLs. | |
* @return string rewritten url | |
*/ | |
protected function rewrite_url( $url, $tag, $path ) { | |
// If we don't have to rewrite for this tag, do nothing. | |
if( !in_array( $tag, self::$path_replace_list ) ) { | |
return $url; | |
} | |
// Make protocol list. It is a little bit different for <a>. | |
$protocol = 'http|https|ftp|file|apt|magnet'; | |
if ( $tag == 'a' ) { | |
$protocol .= '|mailto|javascript'; | |
} | |
// Regex for URLs that should not change (except the leading #) | |
$no_change = "/(^($protocol)\:)|(#$)/i"; | |
if ( preg_match( $no_change, $url ) ) { | |
return rtrim( $url, '#' ); | |
} | |
// Regex for URLs that need only base url (and not template dir) | |
$base_only = '/^\//'; | |
if ( $tag == 'a' or $tag == 'form' ) { | |
$base_only = '//'; | |
} | |
if ( preg_match( $base_only, $url ) ) { | |
return rtrim( self::$base_url, '/' ) . '/' . ltrim( $url, '/' ); | |
} | |
// Other URLs | |
return $path . $url; | |
} | |
/** | |
* replace one single path corresponding to a given match in the `path_replace` regex. | |
* This function has no reason to be used anywhere but in `path_replace`. | |
* @see path_replace | |
* | |
* @param array $matches | |
* @return replacement string | |
*/ | |
protected function single_path_replace ( $matches ){ | |
$tag = $matches[1]; | |
$_ = $matches[2]; | |
$attr = $matches[3]; | |
$url = $matches[4]; | |
$new_url = $this->rewrite_url( $url, $tag, $this->path ); | |
return "<$tag$_$attr=\"$new_url\""; | |
} | |
/** | |
* replace the path of image src, link href and a href. | |
* @see rewrite_url for more information about how paths are replaced. | |
* | |
* @param string $html | |
* @return string html sostituito | |
*/ | |
protected function path_replace( $html, $tpl_basedir ){ | |
if( self::$path_replace ){ | |
$tpl_dir = self::$base_url . self::$tpl_dir . $tpl_basedir; | |
// Prepare reduced path not to compute it for each link | |
$this->path = $this->reduce_path( $tpl_dir ); | |
$url = '(?:(?:\\{.*?\\})?[^{}]*?)*?'; // allow " inside {} for cases in which url contains {function="foo()"} | |
$exp = array(); | |
$tags = array_intersect( array( "link", "a" ), self::$path_replace_list ); | |
$exp[] = '/<(' . join( '|', $tags ) . ')(.*?)(href)="(' . $url . ')"/i'; | |
$tags = array_intersect( array( "img", "script", "input" ), self::$path_replace_list ); | |
$exp[] = '/<(' . join( '|', $tags ) . ')(.*?)(src)="(' . $url . ')"/i'; | |
$tags = array_intersect( array( "form" ), self::$path_replace_list ); | |
$exp[] = '/<(' . join( '|', $tags ) . ')(.*?)(action)="(' . $url . ')"/i'; | |
return preg_replace_callback( $exp, 'self::single_path_replace', $html ); | |
} | |
else | |
return $html; | |
} | |
// replace const | |
function const_replace( $html, $tag_left_delimiter, $tag_right_delimiter, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level = null, $echo = null ){ | |
// const | |
return preg_replace( '/\{\#(\w+)\#{0,1}\}/', $php_left_delimiter . ( $echo ? " echo " : null ) . '\\1' . $php_right_delimiter, $html ); | |
} | |
// replace functions/modifiers on constants and strings | |
function func_replace( $html, $tag_left_delimiter, $tag_right_delimiter, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level = null, $echo = null ){ | |
preg_match_all( '/' . '\{\#{0,1}(\"{0,1}.*?\"{0,1})(\|\w.*?)\#{0,1}\}' . '/', $html, $matches ); | |
for( $i=0, $n=count($matches[0]); $i<$n; $i++ ){ | |
//complete tag ex: {$news.title|substr:0,100} | |
$tag = $matches[ 0 ][ $i ]; | |
//variable name ex: news.title | |
$var = $matches[ 1 ][ $i ]; | |
//function and parameters associate to the variable ex: substr:0,100 | |
$extra_var = $matches[ 2 ][ $i ]; | |
// check if there's any function disabled by black_list | |
$this->function_check( $tag ); | |
$extra_var = $this->var_replace( $extra_var, null, null, null, null, $loop_level ); | |
// check if there's an operator = in the variable tags, if there's this is an initialization so it will not output any value | |
$is_init_variable = preg_match( "/^(\s*?)\=[^=](.*?)$/", $extra_var ); | |
//function associate to variable | |
$function_var = ( $extra_var and $extra_var[0] == '|') ? substr( $extra_var, 1 ) : null; | |
//variable path split array (ex. $news.title o $news[title]) or object (ex. $news->title) | |
$temp = preg_split( "/\.|\[|\-\>/", $var ); | |
//variable name | |
$var_name = $temp[ 0 ]; | |
//variable path | |
$variable_path = substr( $var, strlen( $var_name ) ); | |
//parentesis transform [ e ] in [" e in "] | |
$variable_path = str_replace( '[', '["', $variable_path ); | |
$variable_path = str_replace( ']', '"]', $variable_path ); | |
//transform .$variable in ["$variable"] | |
$variable_path = preg_replace('/\.\$(\w+)/', '["$\\1"]', $variable_path ); | |
//transform [variable] in ["variable"] | |
$variable_path = preg_replace('/\.(\w+)/', '["\\1"]', $variable_path ); | |
//if there's a function | |
if( $function_var ){ | |
// check if there's a function or a static method and separate, function by parameters | |
$function_var = str_replace("::", "@double_dot@", $function_var ); | |
// get the position of the first : | |
if( $dot_position = strpos( $function_var, ":" ) ){ | |
// get the function and the parameters | |
$function = substr( $function_var, 0, $dot_position ); | |
$params = substr( $function_var, $dot_position+1 ); | |
} | |
else{ | |
//get the function | |
$function = str_replace( "@double_dot@", "::", $function_var ); | |
$params = null; | |
} | |
// replace back the @double_dot@ with :: | |
$function = str_replace( "@double_dot@", "::", $function ); | |
$params = str_replace( "@double_dot@", "::", $params ); | |
} | |
else | |
$function = $params = null; | |
$php_var = $var_name . $variable_path; | |
// compile the variable for php | |
if( isset( $function ) ){ | |
if( $php_var ) | |
$php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . ( $params ? "( $function( $php_var, $params ) )" : "$function( $php_var )" ) . $php_right_delimiter; | |
else | |
$php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . ( $params ? "( $function( $params ) )" : "$function()" ) . $php_right_delimiter; | |
} | |
else | |
$php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . $php_var . $extra_var . $php_right_delimiter; | |
$html = str_replace( $tag, $php_var, $html ); | |
} | |
return $html; | |
} | |
function var_replace( $html, $tag_left_delimiter, $tag_right_delimiter, $php_left_delimiter = null, $php_right_delimiter = null, $loop_level = null, $echo = null ){ | |
//all variables | |
if( preg_match_all( '/' . $tag_left_delimiter . '\$(\w+(?:\.\${0,1}[A-Za-z0-9_]+)*(?:(?:\[\${0,1}[A-Za-z0-9_]+\])|(?:\-\>\${0,1}[A-Za-z0-9_]+))*)(.*?)' . $tag_right_delimiter . '/', $html, $matches ) ){ | |
for( $parsed=array(), $i=0, $n=count($matches[0]); $i<$n; $i++ ) | |
$parsed[$matches[0][$i]] = array('var'=>$matches[1][$i],'extra_var'=>$matches[2][$i]); | |
foreach( $parsed as $tag => $array ){ | |
//variable name ex: news.title | |
$var = $array['var']; | |
//function and parameters associate to the variable ex: substr:0,100 | |
$extra_var = $array['extra_var']; | |
// check if there's any function disabled by black_list | |
$this->function_check( $tag ); | |
$extra_var = $this->var_replace( $extra_var, null, null, null, null, $loop_level ); | |
// check if there's an operator = in the variable tags, if there's this is an initialization so it will not output any value | |
$is_init_variable = preg_match( "/^[a-z_A-Z\.\[\](\-\>)]*=[^=]*$/", $extra_var ); | |
//function associate to variable | |
$function_var = ( $extra_var and $extra_var[0] == '|') ? substr( $extra_var, 1 ) : null; | |
//variable path split array (ex. $news.title o $news[title]) or object (ex. $news->title) | |
$temp = preg_split( "/\.|\[|\-\>/", $var ); | |
//variable name | |
$var_name = $temp[ 0 ]; | |
//variable path | |
$variable_path = substr( $var, strlen( $var_name ) ); | |
//parentesis transform [ e ] in [" e in "] | |
$variable_path = str_replace( '[', '["', $variable_path ); | |
$variable_path = str_replace( ']', '"]', $variable_path ); | |
//transform .$variable in ["$variable"] and .variable in ["variable"] | |
$variable_path = preg_replace('/\.(\${0,1}\w+)/', '["\\1"]', $variable_path ); | |
// if is an assignment also assign the variable to $this->var['value'] | |
if( $is_init_variable ) | |
$extra_var = "=\$this->var['{$var_name}']{$variable_path}" . $extra_var; | |
//if there's a function | |
if( $function_var ){ | |
// check if there's a function or a static method and separate, function by parameters | |
$function_var = str_replace("::", "@double_dot@", $function_var ); | |
// get the position of the first : | |
if( $dot_position = strpos( $function_var, ":" ) ){ | |
// get the function and the parameters | |
$function = substr( $function_var, 0, $dot_position ); | |
$params = substr( $function_var, $dot_position+1 ); | |
} | |
else{ | |
//get the function | |
$function = str_replace( "@double_dot@", "::", $function_var ); | |
$params = null; | |
} | |
// replace back the @double_dot@ with :: | |
$function = str_replace( "@double_dot@", "::", $function ); | |
$params = str_replace( "@double_dot@", "::", $params ); | |
} | |
else | |
$function = $params = null; | |
//if it is inside a loop | |
if( $loop_level ){ | |
//verify the variable name | |
if( $var_name == 'key' ) | |
$php_var = '$key' . $loop_level; | |
elseif( $var_name == 'value' ) | |
$php_var = '$value' . $loop_level . $variable_path; | |
elseif( $var_name == 'counter' ) | |
$php_var = '$counter' . $loop_level; | |
else | |
$php_var = '$' . $var_name . $variable_path; | |
}else | |
$php_var = '$' . $var_name . $variable_path; | |
// compile the variable for php | |
if( isset( $function ) ) | |
$php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . ( $params ? "( $function( $php_var, $params ) )" : "$function( $php_var )" ) . $php_right_delimiter; | |
else | |
$php_var = $php_left_delimiter . ( !$is_init_variable && $echo ? 'echo ' : null ) . $php_var . $extra_var . $php_right_delimiter; | |
$html = str_replace( $tag, $php_var, $html ); | |
} | |
} | |
return $html; | |
} | |
/** | |
* Check if function is in black list (sandbox) | |
* | |
* @param string $code | |
* @param string $tag | |
*/ | |
protected function function_check( $code ){ | |
$preg = '#(\W|\s)' . implode( '(\W|\s)|(\W|\s)', self::$black_list ) . '(\W|\s)#'; | |
// check if the function is in the black list (or not in white list) | |
if( count(self::$black_list) && preg_match( $preg, $code, $match ) ){ | |
// find the line of the error | |
$line = 0; | |
$rows=explode("\n",$this->tpl['source']); | |
while( !strpos($rows[$line],$code) ) | |
$line++; | |
// stop the execution of the script | |
$e = new RainTpl_SyntaxException('Unallowed syntax in ' . $this->tpl['tpl_filename'] . ' template'); | |
throw $e->setTemplateFile($this->tpl['tpl_filename']) | |
->setTag($code) | |
->setTemplateLine($line); | |
} | |
} | |
/** | |
* Prints debug info about exception or passes it further if debug is disabled. | |
* | |
* @param RainTpl_Exception $e | |
* @return string | |
*/ | |
protected function printDebug(RainTpl_Exception $e){ | |
if (!self::$debug) { | |
throw $e; | |
} | |
$output = sprintf('<h2>Exception: %s</h2><h3>%s</h3><p>template: %s</p>', | |
get_class($e), | |
$e->getMessage(), | |
$e->getTemplateFile() | |
); | |
if ($e instanceof RainTpl_SyntaxException) { | |
if (null != $e->getTemplateLine()) { | |
$output .= '<p>line: ' . $e->getTemplateLine() . '</p>'; | |
} | |
if (null != $e->getTag()) { | |
$output .= '<p>in tag: ' . htmlspecialchars($e->getTag()) . '</p>'; | |
} | |
if (null != $e->getTemplateLine() && null != $e->getTag()) { | |
$rows=explode("\n", htmlspecialchars($this->tpl['source'])); | |
$rows[$e->getTemplateLine()] = '<font color=red>' . $rows[$e->getTemplateLine()] . '</font>'; | |
$output .= '<h3>template code</h3>' . implode('<br />', $rows) . '</pre>'; | |
} | |
} | |
$output .= sprintf('<h3>trace</h3><p>In %s on line %d</p><pre>%s</pre>', | |
$e->getFile(), $e->getLine(), | |
nl2br(htmlspecialchars($e->getTraceAsString())) | |
); | |
return $output; | |
} | |
} | |
/** | |
* Basic Rain tpl exception. | |
*/ | |
class RainTpl_Exception extends Exception{ | |
/** | |
* Path of template file with error. | |
*/ | |
protected $templateFile = ''; | |
/** | |
* Returns path of template file with error. | |
* | |
* @return string | |
*/ | |
public function getTemplateFile() | |
{ | |
return $this->templateFile; | |
} | |
/** | |
* Sets path of template file with error. | |
* | |
* @param string $templateFile | |
* @return RainTpl_Exception | |
*/ | |
public function setTemplateFile($templateFile) | |
{ | |
$this->templateFile = (string) $templateFile; | |
return $this; | |
} | |
} | |
/** | |
* Exception thrown when template file does not exists. | |
*/ | |
class RainTpl_NotFoundException extends RainTpl_Exception{ | |
} | |
/** | |
* Exception thrown when syntax error occurs. | |
*/ | |
class RainTpl_SyntaxException extends RainTpl_Exception{ | |
/** | |
* Line in template file where error has occured. | |
* | |
* @var int | null | |
*/ | |
protected $templateLine = null; | |
/** | |
* Tag which caused an error. | |
* | |
* @var string | null | |
*/ | |
protected $tag = null; | |
/** | |
* Returns line in template file where error has occured | |
* or null if line is not defined. | |
* | |
* @return int | null | |
*/ | |
public function getTemplateLine() | |
{ | |
return $this->templateLine; | |
} | |
/** | |
* Sets line in template file where error has occured. | |
* | |
* @param int $templateLine | |
* @return RainTpl_SyntaxException | |
*/ | |
public function setTemplateLine($templateLine) | |
{ | |
$this->templateLine = (int) $templateLine; | |
return $this; | |
} | |
/** | |
* Returns tag which caused an error. | |
* | |
* @return string | |
*/ | |
public function getTag() | |
{ | |
return $this->tag; | |
} | |
/** | |
* Sets tag which caused an error. | |
* | |
* @param string $tag | |
* @return RainTpl_SyntaxException | |
*/ | |
public function setTag($tag) | |
{ | |
$this->tag = (string) $tag; | |
return $this; | |
} | |
} | |
// -- end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment