21,886
社区成员
发帖
与我相关
我的任务
分享
class Template
{
public $template_dir = null; // 模板目录
public $compile_dir = null; // 编译目录
public $cache_dir = null; // 缓存目录
public $cache_life = 0; // 缓存时间
public $force_compile = false; // 是否强制编译
public $left_delimiter = '{'; // 左边界符
public $right_delimiter = '}'; // 右边界符
public $var_list = array(); // 变量集合
public $tpl_name = null;
/**
* 编译并显示模板
*
* @param string|array $var 变量名|变量数组
* @param all 变量值
*/
public function assign($var, $value = null)
{
if (is_array($var)) {
$this->_assign_arr($var);
} else {
$this->_assign_var($var, $value);
}
}
/**
* 编译并显示模板
*
* @param string $string
*/
public function display($tpl_name)
{
$this->template_dir = rtrim($this->template_dir, '/');
$tpl = $this->template_dir . '/' . $tpl_name;
if (is_file($tpl)) {
$this->tpl_name = $tpl_name;
$this->fetch(file_get_contents($tpl), true);
} else {
throw new Exception("Template \"{$tpl_name}\" does not exist");
}
}
/**
* 编译字符串
*
* @param string $content
* @param bool $print 是否输出(true-输出)
* @param bool $print_exit 输出终止
* @return echo|string
*/
public function fetch($content, $print = false, $print_exit = true)
{
$contents = false;
if ($this->cacheing) {
$contents = $this->_get_cache();
}
if ($contents === false) {
$compile_file_path = $this->_compile($content);
extract($this->var_list);
ob_start();
require_once($compile_file_path);
$content = ob_get_contents();
ob_end_clean();
if ($this->cacheing) {
$this->_set_cache($content);
}
} else {
$content = $contents;
}
if ($print) {
echo $content;
if ($print_exit) exit;
} else {
return $content;
}
}
/**
* 设置缓存
*
* @param string $content
* @return string
*/
private function _set_cache($content)
{
$cache_file = $this->tpl_name;
$cache_file_path = $this->cache_dir . '/' . $cache_file;
$this->_mkdir('cache_dir', '0777', true);
@file_put_contents($cache_file_path, $content . "<!--{/**{$this->cache_life}**/}-->");
}
/**
* 获取缓存
*
* @return bool/string
*/
private function _get_cache()
{
$cache_file = $this->tpl_name;
$cache_file_path = $this->cache_dir . '/' . $cache_file;
if (is_file($cache_file_path)) {
$contents = file_get_contents($cache_file_path);
$cache_life_match = preg_match('#<\!--{\/\*\*(\d+)\*\*\/}-->#', $contents, $arr);
if (!$cache_life_match) {
return false;
}
$cache_life = $arr[1];
$filemtime = filemtime($cache_file_path);
if ($filemtime + $cache_life > time()) {
return file_get_contents($cache_file_path);
} else {
return false;
}
}
return false;
}
/**
* 编译
*
* @param string $content
* @return string
*/
private function _compile($content)
{
$content = $this->_match($content);
$compile_file = md5_file($this->template_dir . '/' . $this->tpl_name) . $this->tpl_name . '.php';
$compile_file_path = $this->compile_dir . '/' . $compile_file;
if ($this->force_compile || !is_file($compile_file_path)) {
// 删除原编译文件
$unlink_file = '*' . $this->tpl_name . '.php';
if (strpos(strtolower(PHP_OS), 'win') === false) {
$cmd = "rm -f compile_dir/{$unlink_file}";
} else {
$cmd = "del compile_dir\\{$unlink_file}";
}
exec($cmd);
$this->_mkdir('compile_dir', '0777', true);
@file_put_contents($compile_file_path, $content);
}
return $compile_file_path;
}
/**
* 匹配
*
* @param string $content
* @return string
*/
private function _match($content)
{
// if
$replace = array(
'#' . $this->left_delimiter . 'if[ ]+([^' . $this->right_delimiter . ']+)' . $this->right_delimiter . '#is' => '<?php if (\1) {?>',
'#' . $this->left_delimiter . '/if' . $this->right_delimiter . '#is' => '<?php }?>',
);
$content = preg_replace(array_keys($replace), array_values($replace), $content);
// foreach
$replace = array(
'#' . $this->left_delimiter . 'foreach[ ]+from=\$([a-z_]+\w*)[ ]+item=([a-z_]+\w*)[ ]*' . $this->right_delimiter . '#is' => '<?php foreach ($\1 as $\2) {?>',
'#' . $this->left_delimiter . '/foreach' . $this->right_delimiter . '#is' => '<?php }?>'
);
$content = preg_replace(array_keys($replace), array_values($replace), $content);
// variables
$content = preg_replace_callback('#' . $this->left_delimiter . '(((?!\?>).)*(\$(\.?\w+)+)[^' . $this->right_delimiter . ']*)' . $this->right_delimiter . '#i', array($this, '_back'), $content);
return $content;
}
private function _back($m)
{
$s = $m[1];
$r = '#\$(\.?\w+)+#i';
preg_match_all($r, $m[1], $list);
foreach ($list[0] as $val) {
$arr = explode('.', $val);
$var = '';
foreach($arr as $v) {
if (strpos($v, '$') === false) {
$var .= '[\'' . $v . '\']';
} else {
$var .= $v;
}
}
$s = strtr($s, array($val => $var));
}
return '<?php echo ' . $s . ';?>';
}
/**
* 创建内部目录
*
* @param string $type 创建类型(compile_dir-编译目录|cache_dir-缓存目录)
* @param string $mode 权限
* @param bool $recursive 是否递归创建
* @return bool
*/
private function _mkdir($type, $mode = '0777', $recursive = false)
{
$allow_type = array('compile_dir', 'cache_dir');
if (!in_array($type, $allow_type)) {
throw new Exception("Not allowed to create the type of \"{$type}\".");
}
$dir = null;
switch ($type) {
case 'compile_dir':
$dir = $this->compile_dir;
break;
case 'cache_dir':
$dir = $this->cache_dir;
break;
}
if (!$dir) {
throw new Exception("Please specify the \"{$type}\" directory.");
}
if (!is_dir($dir) && !mkdir($dir, $mode, $recursive)) {
throw new Exception("\"{$dir}\" Failed to create \"{$type}\" directory");
}
return true;
}
/**
* 检测变量名是否和服
*
* @param string $var 变量名
* @return bool
*/
private function _check_var($var)
{
$var_rule = '#^[a-z_]+\w*$#i';
if (preg_match($var_rule, $var)) {
return true;
}
return false;
}
/**
* 单变量赋值
*/
private function _assign_var($var, $value)
{
if ($this->_check_var($var)) {
$this->var_list[$var] = $value;
}
}
/**
* 多变量赋值
*/
private function _assign_arr($data)
{
foreach ($data as $var => $value) {
if ($this->_check_var($var)) {
$this->var_list[$var] = $value;
}
}
}
}
$t = new Template;
$t->template_dir = 'template';
$t->compile_dir = 'compile_dir';
$t->cache_dir = 'cache_dir';
$t->cacheing = false;
$t->cache_life = 5;
$t->force_compile = true;
$t->left_delimiter = '{';
$t->right_delimiter = '}';
$c = array(
'user1' => array('username' => 'zhangsan', 'age' => 20),
'user2' => array('username' => 'thelisis', 'age' => 22)
);
$t->assign(array('a' => 123, 'b' => 'abc', 'c' => $c, 'x' => true));
$t->display('t.html');