<?
define('_IN_NSTEMPLATE', 1);
class templateconf{
public $conf = array(
'root' => './',
'lang' => 'chs',
'compiledfolder' => 'compiled',
'unknowns' => 'comment',
'cachetimeout' => 20000,
'enablecahce' => false,
'erron' => true,
'debugon' => false,
);
public $_block_regcounterstr = 255;
public $_last_selectedblock = 0;
public $_reg_blocks = array();
public $_blockmap = array();
public $_blockstrmap = array();
}
class template extends templateconf{
function __construct($tplpath, $conf = array()){
//配置
if(!empty($conf)){
foreach($conf as $varname => $value){
$this->conf[$varname] = $value;
}
}
//原始文件路径
$this->tplpath = $tplpath;
//临时文件路径
$this->temporarypath = $this->conf['root'].$this->conf['compiledfolder'].'/temporary-'.$this->conf['lang'].'-'.md5(basename($this->tplpath)).'.tmp.php';
//编译文件路径
$this->compiledpath = $this->conf['root'].$this->conf['compiledfolder'].'/compiled-'.$this->conf['lang'].'-'.md5(basename($this->tplpath)).'.cp.php';
//编译数据文件路径
$this->compileddatpath = $this->conf['root'].$this->conf['compiledfolder'].'/compiled-dat-'.$this->conf['lang'].'-'.md5(basename($this->tplpath)).'.data.php';
if(!is_readable($this->tplpath)){
$this->_halt('模板载入错误,文件不存在或无法读取', "{$this->tplpath}");
}
if(!file_exists($this->conf['root'].$this->conf['compiledfolder'])){
$this->_halt('临时文件夹不存在',"\"{$this->conf['root']}{$this->conf['compiledfolder']}\" 不存在");
}
if(!is_readable($this->compiledpath)){
//编译模板
$this->cachedfile = false;
$this->_preprocess();
}elseif((intval(time() - @filemtime($this->compiledpath)) > $this->conf['cachetimeout']) || !$this->conf['enablecahce']){
//编译模板
$this->cachedfile = false;
$this->_preprocess();
}else{
require($this->compileddatpath);
}
}
//处理静态变量,模块
function _preprocess(){
//读原始模板
$this->source = implode('', @file($this->tplpath));
$this->_safe_check();
$this->_process();
if($this->conf['enablecahce'] && !$this->cachedfile){
$this->writetofile($this->compiledpath, $this->datafileheader().$this->source);
}
}
function _process(){
//取词
do{
$this->_tokenstatement();
$this->handletoken($this->_token, $this->source);
}while(!empty($this->_token));
//处理转义
$this->_process_trans();
$this->_storecompiled();
}
function block($blockname){
//获取BLOCK编号
if(isset($this->_blockmap[$blockname])){
$this->selectedblock = $this->_blockmap[$blockname];
}else{
$this->_halt('定义不存在的结构', "'{$blockname}'");
}
if(!isset($this->_temp_counter[$this->selectedblock])) $this->_temp_counter[$this->selectedblock] = 0;
//查找子BLOCK
$childthis->selectedblock = array_search($this->selectedblock, $this->_blockparent);
if(!empty($childthis->selectedblock) && ($this->_last_selectedblock !=$this->selectedblock)){
$this->_temp_counter[$childthis->selectedblock] = 0;
}
//当前BLOCK计数器
$this->_temp_counter[$this->selectedblock]++;
$this->_last_selectedblock = $this->selectedblock;
/* if($this->_block_reg != 0){
$this->_halt('重复定义BLOCK');
}*/
$_temp_strmap_compiled = $this->_blockstrmap[$this->selectedblock];
preg_match_all('/{$_i(.+?)}/', $_temp_strmap_compiled, $matches);
foreach($matches[1] as $name => $value){
$_temp_strmap_compiled = str_replace("{$_i{$value}}", $this->_temp_counter[$value], $_temp_strmap_compiled);
}
$_temp_strmap_compiled = preg_replace("/{(.+?)}/", '0', $_temp_strmap_compiled);
preg_match('/^(.*)(?:_(.+?))+$/', $_temp_strmap_compiled, $matches);
if(isset($matches[1]))
$this->_strmap_compiled[$this->selectedblock][0] = $matches[1];
if(isset($matches[2]))
$this->_strmap_compiled[$this->selectedblock][1] = $matches[2];
$this->_strmap_compiled[$this->selectedblock][2] = $_temp_strmap_compiled;
}
function processblock(){
//
if(!empty($this->_blockparent[$this->selectedblock])){
$this->selectedblock = $this->_blockparent[$this->selectedblock];
}
}
function assign($varname, $value = ''){
global $_nstem_blockvars,$_nstem_vars;
if(empty($this->selectedblock)){
if (!is_array($varname)) {
$_nstem_vars[$varname] = $value;
$this->bdo("<b>Var set:</b> $_nstem_vars['$varname']='{$value}'");
}else{
foreach($varname as $name=> $value){
$_nstem_vars[$name] = $value;
$this->bdo("<b>Array set:</b> $_nstem_vars['$name']='{$value}'");
}
}
}else{
if (!is_array($varname)) {
if(!empty($this->_strmap_compiled[$this->selectedblock][0]) && !empty($this->_strmap_compiled[$this->selectedblock][1])){
$_nstem_blockvars[$this->selectedblock][$this->_strmap_compiled[$this->selectedblock][0]][$this->_strmap_compiled[$this->selectedblock][1]][$varname] = $value;
$_nstem_vars[$varname] = $value;
$this->bdo("<b>Var set:</b> $_nstem_blockvars['$this->selectedblock'][{$this->_strmap_compiled[$this->selectedblock][0]}][{$this->_strmap_compiled[$this->selectedblock][1]}]['$varname']='{$value}'");
}else{
$_nstem_blockvars[$this->selectedblock][$this->_strmap_compiled[$this->selectedblock][2]][$varname] = $value;
$_nstem_vars[$varname] = $value;
$this->bdo("<b>Var set:</b> $_nstem_blockvars['$this->selectedblock'][{$this->_strmap_compiled[$this->selectedblock][2]}]['$varname']='{$value}'");
}
}else{
foreach($varname as $name=> $value){
if(!empty($this->_strmap_compiled[$this->selectedblock][0]) && !empty($this->_strmap_compiled[$this->selectedblock][1])){
$_nstem_blockvars[$this->selectedblock][$this->_strmap_compiled[$this->selectedblock][0]][$this->_strmap_compiled[$this->selectedblock][1]][$name] = $value;
$_nstem_vars[$name] = $value;
$this->bdo("<b>Var set:</b> $_nstem_blockvars['$this->selectedblock'][{$this->_strmap_compiled[$this->selectedblock][0]}][{$this->_strmap_compiled[$this->selectedblock][1]}]['$name']='{$value}'");
}else{
$_nstem_blockvars[$this->selectedblock][$this->_strmap_compiled[$this->selectedblock][2]][$name] = $value;
$_nstem_vars[$name] = $value;
$this->bdo("<b>Var set:</b> $_nstem_blockvars['$this->selectedblock'][{$this->_strmap_compiled[$this->selectedblock][2]}]['$name']='{$value}'");
}
}
}
}
}
function setblocks($blockname, $parent = ''){
//设置嵌套结构
if(isset($this->_blockmap[$parent])){
$this->_blockparent[$this->_blockmap[$blockname]] = $this->_blockmap[$parent];
}else{
$this->_halt("定义不存在的结构", "'{$parent}'");
}
}
function push($pushout = true){
global $_nstem_blockvars,$_nstem_vars;
if($this->conf['enablecahce']){
if($pushout) require($this->compiledpath);
}else{
$this->writetofile($this->temporarypath, $this->datafileheader().$this->source);
if($pushout) require($this->temporarypath);
}
}
function _halt($message, $more = ''){
$this->lasterrmsg = $message;
if($this->conf['erron']){
die("<h4>错误: {$message}</h4>
{$more}");
}
}
function datafileheader(){
return "<?phpn/* NSTemplate 0.14 Build 2250 */nif(!defined('_IN_NSTEMPLATE'))die('Access Denied');nerror_reporting(E_ALL&~E_NOTICE);n?>nn";
}
function _storecompiled(){
$temp = $this->datafileheader()."<?phpn";
foreach($this->_blockmap as $key => $value){
$temp .= "$this->_blockmap['{$key}'] = '{$value}';n";
}
foreach($this->_blockstrmap as $key => $value){
$temp .= "$this->_blockstrmap['{$key}'] = '{$value}';n";
}
$temp .= "$this->_block_reg = 0;n?>";
$this->writetofile($this->compileddatpath, $temp);
}
function bdo($message){
$this->lasterrmsg = $message;
if($this->conf['debugon']){
echo("<br />{$message}");
}
}
function _safe_check(){
$this->source = $this->_source = preg_replace("/<s*?(.*)?s*>/is", "", $this->source);
}
function writetofile($filename, $source){
$fp = fopen($filename, 'w');
flock($fp, LOCK_EX);
$file_source = fwrite($fp, $source);
fclose($fp);
}
function _tokenstatement(){
//获取表达式
if(preg_match("/((?:<!--s*#s*|!|){(.+?)}(?:s*#s*-->|))/", $this->_source, $matches)){
//完整表达式内容statement
$this->_token = trim($matches[2]);
//完整表达式{statement} or <!--#statement#-->
$this->_tokenstr = trim($matches[1]);
$this->bdo("<b>Tokenstr:</b> {$this->_tokenstr}");
if(substr($this->_tokenstr, 0, 1) == '!'){
//转义
$this->source = str_replace($this->_tokenstr, "{trans:{$this->_token}}", $this->source);
$this->_source = str_replace($this->_tokenstr, '', $this->_source);
$this->_token = "trans:{$this->_token}";
$this->_tokenstr = "{trans:{$this->_token}}";
}else{
$_replace_tokenstr = '/'.str_replace('/', '/' , preg_quote($this->_tokenstr)).'/';
$this->_source = preg_replace($_replace_tokenstr, '', $this->_source, 1);
}
}else{
$this->_token = '';
$this->_tokenstr = '';
}
}
//处理开始==========================================================================================
function handletoken($statement){
//statement(statement):statement
if(preg_match("/^(.+?)((.+?)):(.+?)$/",$statement, $matches)){
$this->laststatement = $matches[1];
switch ($this->laststatement) {
case 'set':
$this->_process_set($matches[2], $matches[3]);
break;
}
//statement:statement
}elseif(preg_match("/^(.+?):(.+?)$/",$statement, $matches)){
$this->laststatement = $matches[1];
switch ($this->laststatement) {
case 'php':
$this->_set($matches[2]);
break;
case 'if':
$this->_process_if($matches[2]);
break;
case 'elseif':
$this->_process_if($matches[2], 'elseif');
break;
case 'lang':
$this->_process_lang($matches[2]);
break;
case 'definelang':
$this->_process_definelang($matches[2]);
break;
case 'static':
$this->_process_static($matches[2]);
break;
case 'global':
$this->_process_vars($matches[2], 'global');
break;
case 'block':
$this->_process_blockbegin($matches[2]);
break;
}
//statement
}else{
$this->laststatement = $statement;
switch ($this->laststatement) {
case 'else':
$this->_set("}else{");
break;
case '/if':
$this->_process_endtag();
break;
case '/block':
$this->_process_blockend();
break;
default:
$this->_process_vars($statement);
break;
}
}
}
//处理结束==========================================================================================
//模块处理====================================================================================================
function _set($statement){
$this->source = str_replace($this->_tokenstr, "<?php {$statement} ?>", $this->source);
}
function _process_endtag(){
$this->_set("}");
}
function _process_trans(){
$this->source = preg_replace("/(?:<!--s*#s*|){trans:(.+?)}(?:s*#s*-->|)/is", "{\1}", $this->source);
}
function _process_blockbegin($blockname){
$this->_block_reg++;
$this->_block_regcounterstr--;
$this->_blockmap[$blockname] = $this->_block_regcounterstr;
if($this->_block_reg != 1){
$this->_block_counterstr .= "_{$_i{$this->_block_regcounterstr}}";
$this->block_counterstr .= ".'_'.$_i{$this->_block_regcounterstr}";
}else{
$this->_block_counterstr = "{$_i{$this->_block_regcounterstr}}";
$this->block_counterstr = "$_i{$this->_block_regcounterstr}";
}
$this->_blockstrmap[$this->_block_regcounterstr] = $this->_block_counterstr;
preg_match("/^(.*).'_'.(.*)$/", $this->block_counterstr, $matches);
if(isset($matches[1])) $this->blockstrmap[$this->_block_regcounterstr][0] = $matches[1];
if(isset($matches[2])) $this->blockstrmap[$this->_block_regcounterstr][1] = $matches[2];
$this->blockstrmap[$this->_block_regcounterstr][2] = $this->block_counterstr;
if(!empty($this->blockstrmap[$this->_block_regcounterstr][0])) $blockstrmap_temp = "[{$this->blockstrmap[$this->_block_regcounterstr][0]}]";else $blockstrmap_temp ='';
$this->_set("n$_end{$this->_block_regcounterstr}=count($_nstem_blockvars[{$this->_block_regcounterstr}]{$blockstrmap_temp});nfor($_i{$this->_block_regcounterstr}=1;$_i{$this->_block_regcounterstr}<=$_end{$this->_block_regcounterstr};$_i{$this->_block_regcounterstr}++){n");
array_unshift($this->_reg_blocks, $this->_block_regcounterstr);
}
function _process_blockend(){
$this->_block_reg--;
$this->_set("}");
array_shift($this->_reg_blocks);
}
function _process_if($expression, $type = 'if'){
preg_match_all('/((?:'|"|$|)s*[w]+s*(?:'|"|(|))/', $expression, $matches);
foreach($matches[1] as $name => $value){
$_value = trim($value);
if(!preg_match('/(?:^[0-9]+|^'|$|^\")|(?:($)|(?:true|false)/', $_value)){
$expression = preg_replace('/'.preg_quote($value).'/', "$_nstem_vars['{$_value}']", $expression, 1);
}
}
if($type == 'if'){
$this->_set("if({$expression}){");
}else{
$this->_set("}elseif({$expression}){");
}
}
function _process_static($varname){
global $$varname;
$this->source = str_replace($this->_tokenstr, $$varname, $this->source);
}
function _process_lang($varname){
$langvar = $this->_langvar;
global $$langvar;
$lang = $$langvar;
$this->source = str_replace($this->_tokenstr, $lang[$this->conf['lang']][$varname], $this->source);
}
function _process_definelang($varname){
preg_match('/^$(.*?)$/', $varname, $matches);
$this->_langvar = $matches[1];
$this->source = str_replace($this->_tokenstr, '', $this->source);
}
function _process_set($varname, $value){
if(preg_match("/^'(.*)'$/", $value, $matches)){
$_nstem_vars[$varname] = $matches[1];
$this->source = str_replace($this->_tokenstr, "<?php $_nstem_vars['{$varname}'] = '{$matches[1]}' ?>", $this->source);
}else{
$_nstem_vars[$varname] = $_nstem_vars[$value];
$this->source = str_replace($this->_tokenstr, "<?php $_nstem_vars['{$varname}'] = $_nstem_vars['{$value}'] ?>", $this->source);
}
}
function _process_vars($varname, $first='block'){
global $_nstem_blockvars,$_nstem_vars;
if(!empty($this->_reg_blocks) && !empty($varname) && $first == 'block'){
$_current_blocks = array_shift($this->_reg_blocks);
array_unshift($this->_reg_blocks, $_current_blocks);
$_replace_tokenstr = '/'.str_replace('/', '/' , preg_quote($this->_tokenstr)).'/';
if(!empty($this->blockstrmap[$_current_blocks][0])) $blockstrmap_temp_0 = "[{$this->blockstrmap[$_current_blocks][0]}]";else $blockstrmap_temp_0 = "[{$this->blockstrmap[$_current_blocks][2]}]";
if(!empty($this->blockstrmap[$_current_blocks][1])) $blockstrmap_temp_1 = "[{$this->blockstrmap[$_current_blocks][1]}]";else $blockstrmap_temp_1 ='';
$this->source = preg_replace($_replace_tokenstr, "<?php echo isset($_nstem_blockvars[$_current_blocks]{$blockstrmap_temp_0}{$blockstrmap_temp_1}['{$varname}']) ? $_nstem_blockvars[$_current_blocks]{$blockstrmap_temp_0}{$blockstrmap_temp_1}['{$varname}'] : $_nstem_vars['{$varname}']; ?>", $this->source, 1);
}elseif(!empty($varname)){
$_replace_tokenstr = '/'.str_replace('/', '/' , preg_quote($this->_tokenstr)).'/';
$this->source = preg_replace($_replace_tokenstr, "<?php echo $_nstem_vars['{$varname}']; ?>", $this->source, 1);
}
}
}
?>
静态变量与多语言
===========================
代码====
<?php
include_once('nstemplate.php');
$lang['en']['1']='Test';
$lang['chs']['1']='测试静态';
$hhh = 'aaa';
$tpl = new template('testtpl.txt', array('lang' => 'en'));
$tpl->push();
?>
模板====
QUOTE:
<!--# {definelang:$lang}#-->
{lang:1}
{static:hhh}
===========================
嵌套与循环
===========================
代码====
<?php
include_once('nstemplate.php');
$t = new Template('testtpl.txt');
$t->setblocks("1","2");
$t->setblocks("2","3");
for ($k=0;$k<2;$k++){
$t->block("3");
$t->assign("for3","循环3");
$t->processblock();
for ($i=0;$i<2;$i++){
$t->block("2");
<