<?php
/**
* Template类:一个简单的模版处理类,支持模版变量定义,条件语句,循环语句,模版导入语句
* 版本:0.4 Alpha
* 作者:lazy
* 邮件:o0lazy0o at gmail dot com
* 版权:无,可任意使用;如果可以请保留此信息,如您对它做出修改及添加功能请发一个拷贝给我,谢谢!
* Log:
* 0.4=>
* 加入:直接支持define定义的变量,支持使用模版注册过的类跟函数(不支持在if和section语句内使用函数,下一版本考虑支持)
* 修复:模板修改后第一次无法显示的bug
* 修复Import包含模版文件后无法使用的bug
* 0.3 加入 循环支持 和 包含模版支持,去除模版内的<? <?php ?>标识(安全问题)
* 0.2 加入 多数组支持 和 自定义语句跟变量标识符
* 0.1 最初版本,只支持 模版变量(非数组)跟条件语句
* Welcome to http://www.52radio.net/
* 例子:请查看example.php,example.tpl,Import.tpl
* 注意:此版本只做了简单测试.
*/
Class template extends application{
Var $VL='{';
Var $VR='}';
Var $SL='<!--';
Var $SR='-->';
Var $Data=array();
Var $Func=array('date'=>true,'long2ip'=>true,'strftime'=>true);
Var $Class=array();
Var $TplPath='';
Var $CachePath='.';
Var $Filename='';
Var $Savename='';
Var $Content='';
Function template($Filename=null){
$this->Filename=isset($Filename)?$Filename:null;
defined('TPL')?$this->TplPath=TPL:'';
defined('CACHE')?$this->CachePath=CACHE:'';
defined('STYLE')?$this->TplPath=STYLE:'';
}
Function assign($Name,$Value){
return $this->Data[$Name]=$Value;
}
Function reg_func($Name){
return $this->Func[$Name]=true;
}
Function reg_class($Name){
return class_exists($Name)?$this->Class[$Name]=true:null;
}
Function parse_var(){
$RegExp[]='/<{\(((?:(?:[a-zA-Z_](?:.[a-zA-Z0-9_])*)+)|(?:[0-9]{1,9}))\)}>/e';
$Replace[]="\$this->process_var('\$1',false)";
$RegExp[]="/{$this->VL}((?:[a-zA-Z_](?:.[a-zA-Z0-9_])*)+){$this->VR}/e";
$Replace[]="\$this->process_var('\$1',true)";
return $this->Content=preg_replace($RegExp,$Replace,$this->Content);
}
Function parse_if(){
$RegExp[]="/{$this->SL} if ((?:[a-zA-Z_](?:.[a-zA-Z0-9_])*)+) (==|<=|>=|<|>) ((?:[a-zA-Z_](?:.[a-zA-Z0-9_])*)+|'[a-zA-Z0-9]+'|[0-9]+) {$this->SR}/";
$Replace[]="<?php if( <{(\$1)}> \$2 <{(\$3)}> ){ ?>\n";
$RegExp[]="/{$this->SL} elseif ((?:[a-zA-Z_](?:.[a-zA-Z0-9_])*)+) (==|<=|>=|<|>) ((?:[a-zA-Z_](?:.[a-zA-Z0-9_])*)+|'[a-zA-Z0-9]+'|[0-9]+) {$this->SR}/";
$Replace[]="<?php }elseif( <{(\$1)}> \$2 <{(\$3)}> ){ ?>\n";
return $this->Content=preg_replace($RegExp,$Replace,$this->Content);
}
Function parse_for(){
$RegExp="/{$this->SL} section ([a-zA-Z_][a-zA-Z0-9_]+) from ((?:[a-zA-Z_](?:.[a-zA-Z0-9_])*)+) {$this->SR}/";
$Replace="<?php \n";
$Replace.="foreach( <{(\$2)}> as \$__KEY => \$\${1} ){ \n";
$Replace.="\$this->assign('__KEY',\$__KEY); \n";
$Replace.="\$this->assign('\$1',\$\$1); \n";
$Replace.="?> \n";
return $this->Content=preg_replace($RegExp,$Replace,$this->Content);
}
Function parse_end(){
$Search[]="{$this->SL} else {$this->SR}";
$Search[]="{$this->SL} endif {$this->SR}";
$Search[]="{$this->SL} endsection {$this->SR}";
$Replace[]="<?php }else{ ?>";
$Replace[]="<?php } ?>";
$Replace[]="<?php } ?>";
return $this->Content=str_replace($Search,$Replace,$this->Content);
}
Function parse_func(){
$RegExp="/{$this->SL} ([a-zA-Z0-9_]+)(\(\)|\([^\)]+\)) {$this->SR}/e";
$Replace="\$this->process_func('\$1','\$2')";
return $this->Content=preg_replace($RegExp,$Replace,$this->Content);
}
Function parse_class(){
$RegExp="/{$this->SL} ([a-zA-Z0-9_]+)::([a-zA-Z0-9_]+)(\(\)|\([^\)]+\)) {$this->SR}/e";
$Replace="\$this->process_class('\$1','\$2','\$3')";
return $this->Content=preg_replace($RegExp,$Replace,$this->Content);
}
Function parse_import($Filename){
$Backup['Filename']=$this->Filename;
$Backup['Savename']=$this->Savename;
$Backup['Content']=$this->Content;
$Return = $this->display($Filename,true);
unset($this->Filename,$this->Savename,$this->Content);
$this->Filename=$Backup['Filename'];
$this->Savename=$Backup['Savename'];
return $Return;
}
Function process_var($Value,$Echo=false){
if(is_numeric($Value) or $Value=='TRUE' or $Value=='FALSE'){
return $Value;
}
if(defined($Value)){
return $Echo?'<?php echo '.$Value.'?>':$Value;
}
$VarArray=explode('.',$Value);
$Count=count($VarArray);
if($Count>1){
for($Tmp=1;$Tmp<$Count;$Tmp++){
is_numeric($VarArray[$Tmp])?$VarStr.="[{$VarArray[$Tmp]}]":$VarStr.="[\"{$VarArray[$Tmp]}\"]";
}
$PHPVar=strtoupper($VarArray[0]);
if($PHPVar=='_GET' or $PHPVar=='_POST' or $PHPVar=='_COOKIE' or $PHPVar=='_SESSION'){
return $Echo?'<?php echo $'.$PHPVar.$VarStr.'?>':'$'.$PHPVar.$VarStr;
}else{
return $Echo?'<?php echo $this->Data["'.$VarArray[0].'"]'.$VarStr.' ?>':'$this->Data["'.$VarArray[0].'"]'.$VarStr;
}
}
if(array_key_exists($Value,$this->Data)){
return $Echo?'<?php echo $this->Data["'.$Value.'"] ?>':'$this->Data["'.$Value.'"]';
}
return $Echo==false?'"'.str_replace('"','\"',$Value).'"':'<?php echo $this->Data["'.$Value.'"] ?>';
}
Function process_func($FuncName,$FuncArgv){
if(!array_key_exists($FuncName,$this->Func)){
return 'Error:The Function=>'.$FuncName.'Was Not Been Register';
}
$Length=&strlen($FuncArgv);
$FuncArgv=substr($FuncArgv,1,$Length-2);
$FuncArgv=explode(',',$FuncArgv);
$Count=count($FuncArgv);
if($Count==1){
$FuncArgv=&$FuncArgv[0];
return empty($FuncArgv)?"<?php echo $FuncName(); ?> \n":"<?php echo $FuncName(<{(".trim($FuncArgv,"'\"").")}>); ?> \n";
}else{
$Argv=$Tmp=null;
$Count--;
foreach($FuncArgv as $TmpArgv){
$Argv .= $Tmp==$Count?'<{('.trim($TmpArgv,"'\"").')}>':'<{('.trim($TmpArgv,"'\"").')}>,';
$Tmp++;
}
return "<?php echo $FuncName(".$Argv."); ?> \n";
}
}
Function process_class($ClassName,$FuncName,$FuncArgv){
if(class_exists($ClassName) and in_array($ClassName,$this->Class)){
$Return="<?php \$$ClassName=new $ClassName(); ?> \n";
$Return.="<?php if(method_exists(\$$ClassName,'$FuncName')){ ?> \n";
$Length=&strlen($FuncArgv);
$FuncArgv=substr($FuncArgv,1,$Length-2);
$FuncArgv=explode(',',$FuncArgv);
$Count=count($FuncArgv);
if($Count==1){
$FuncArgv=&$FuncArgv[0];
$Return .= empty($FuncArgv)?"<?php echo \${$ClassName}->{$FuncName}(); ?> \n":"<?php echo \${$ClassName}->{$FuncName}(<{(".trim($FuncArgv,"'\"").")}>); ?> \n";
}else{
$Argv=$Tmp=null;
$Count--;
foreach($FuncArgv as $TmpArgv){
$Argv .= $Tmp==$Count?'<{('.trim($TmpArgv,"'\"").')}>':'<{('.trim($TmpArgv,"'\"").')}>,';
$Tmp++;
}
$Return .= "<?php echo \${$ClassName}->{$FuncName}(".$Argv."); ?> \n";
}
$Return .= "<?php }else{ ?> \n";
$Return .= "<?php echo 'The Function=>{$FuncName} Not Exists!' ?>\n";
$Return .= "<?php }?> \n";
return $Return;
}else{
return "The Class=>$ClassName Was Not Been Register";
}
}
Function compile(){
$FuncList[]='parse_if';
$FuncList[]='parse_for';
$FuncList[]='parse_end';
$FuncList[]='parse_func';
$FuncList[]='parse_class';
$FuncList[]='parse_var';
foreach($FuncList as $Call){
if($this->$Call()==false){
$this->error($Call.'=>Compile Fail.');
}
}
if(is_writeable($this->CachePath)){
$Handle=fopen($this->CachePath.'/'.$this->Savename,'wb+');
flock($Handle,LOCK_EX+LOCK_NB);
fwrite($Handle,$this->Content);
fclose($Handle);
return $this->CachePath.$this->Savename;
}else{
return $this->error('Cound not write to cache'.$this->CachePath);
}
}
Function display($Filename,$Import=false){
empty($Filename)?empty($this->Filename)?$this->error('Not Tpl File Define'):$this->Filename:$this->Filename=$Filename;
$HolisticTPL=$this->TplPath.$this->Filename;
if(!file_exists($HolisticTPL)){
$this->error($Filename.' => No Such Tpl File Exists...'.$HolisticTPL);
}
$this->Savename=md5($HolisticTPL).'.tpl.php';
$HolisticCache=$this->CachePath.'/'.$this->Savename;
$this->Content=$this->remove_php_tag(file_get_contents($HolisticTPL));
if(preg_match("/{$this->SL} import '((?:[a-zA-Z_](?:.[a-zA-Z0-9_])*)+)' {$this->SR}/",$this->Content)){
$RegExp="/{$this->SL} import '((?:[a-zA-Z_](?:.[a-zA-Z0-9_])*)+)' {$this->SR}/e";
$Replace="'<?php require_once(\"'.\$this->parse_import('\${1}').'\") ?>'";
$Tmp=preg_replace($RegExp,$Replace,$this->Content);
$this->Content=$Tmp;
}
if(file_exists($HolisticCache)){
$TplFileTime=$this->m_time($HolisticTPL);
$CacheFileTime=$this->m_time($HolisticCache);
if($TplFileTime < $CacheFileTime){
return $Import?$this->Savename:require($HolisticCache);
}
}
$Return = $this->compile();
return $Import==true?($Return):(file_exists($Return)?require($Return):$this->Content);
}
Function result($Filename){
ob_start();
$this->display($Filename);
$Contents=ob_get_contents();
ob_end_clean();
return $Contents;
}
Function m_time($File){
return file_exists($File)?filemtime($File):false;
}
Function remove_php_tag($Strings){
$Search[]='<?';
$Search[]='?>';
$Replace[]='<?';
$Replace[]='?>';
return str_replace($Search,$Replace,$Strings);
}
/*
Function error($ErrStr){
exit(
"<html><head><title>Error & Stop</title></head><body>".
"<div align='center'>".
"<font color='red' size='6'>Template Error:</font> {$ErrStr}".
"<br /><br />Exec Time: ".$this->exectime()."ms".
"</div></body></html>"
);
}
*/
}
?>