>  기사  >  백엔드 개발  >  DolrPHP模板引擎DolrViews分享

DolrPHP模板引擎DolrViews分享

WBOY
WBOY원래의
2016-06-13 10:37:521014검색

【分享】DolrPHP模板引擎DolrViews分享
核心文件:DolrViews.class.php:

  1. /**
  2. * DolrPHP模板引擎
  3. * @author Joychao
  4. * @version 1.0 beta
  5. * @license http://www.Joychao.cc
  6. */
  7. defined('DOLRVIEWS') or define('DOLRVIEWS',true);
  8. defined('DIR_SEP') or define('DIR_SEP',DIRECTORY_SEPARATOR);
  9. class DolrViews
  10. {
  11. /**
  12. * 单例对象
  13. *
  14. * @static var
  15. * @var object DolrViews
  16. */
  17. protected static $_instance;
  18. /**
  19. * 模板变量
  20. *
  21. * @var array
  22. */
  23. protected $_tpl_vars=array();
  24. /**
  25. * 模板参数信息
  26. *
  27. * @var array
  28. */
  29. protected $_options=array(
  30. 'template_dir'=>'templates',
  31. 'compile_dir'=>'templates_c',
  32. 'cache_dir'=>'cache',
  33. 'caching'=>false,
  34. 'cache_lifetime'=>3600,
  35. 'plugins_dir'=>'plugins',
  36. 'tpl_suffix'=>'html',
  37. 'php_handing'=>false,
  38. );
  39. /**
  40. * 包含的插件
  41. * @var array
  42. */
  43. protected $includePlugins=array();
  44. /**
  45. * 主模板非包含模板
  46. * @var string
  47. */
  48. protected $mainTplFileName;
  49. /**
  50. * 单件模式调用方法
  51. *
  52. * @static
  53. * @return object DolrViews
  54. */
  55. public static function getInstance($options=array()) {
  56. if (!self :: $_instance instanceof self)
  57. self :: $_instance = new self($options);
  58. return self :: $_instance;
  59. }
  60. /**
  61. * 构造函数,初始化所有配置
  62. *
  63. * @param array $config=array(); 配置数组
  64. * @example:
  65. * $_options=array(
  66. * 'template_dir'=>'templates',
  67. * 'compile_dir'=>'templates_c',
  68. * 'cache_dir'=>'cache',
  69. * 'caching'=>false,
  70. * 'cache_lifetime'=>3600,
  71. * 'plugins_dir'=>'plugins',
  72. * 'php_handing'=>false,
  73. * );
  74. * $tpl=new DolrViews($_options);
  75. */
  76. public function __construct($options=array())
  77. {
  78. if (!empty($options))
  79. {
  80. $this->setOptions($options);
  81. }
  82. }
  83. /**
  84. * 分配变量到模板
  85. *
  86. * @param string $varName 变量名
  87. * @param mixed $varValue 变量值
  88. */
  89. public function assign($varName,$varValue)
  90. {
  91. $this->_tpl_vars[$varName]=&$varValue;
  92. }
  93. /**
  94. * 显示输出到页面
  95. *
  96. * @param string $tplFileName 模板文件名
  97. */
  98. public function display($tplFileName,$cacheId=null)
  99. {
  100. $cacheId=is_null($cacheId)?$_SERVER['REQUEST_URI']:$cacheId;
  101. $this->mainTplFileName=$tplFileName;
  102. $tplFilePath=$this->_getTplPath($tplFileName);
  103. extract($this->_tpl_vars);
  104. //内置变量
  105. extract($this->_getSystemVars($tplFileName));//系统变量
  106. //是否缓存
  107. if($this->_options['caching']){
  108. if($this->isCached($tplFileName,$cacheId)){
  109. include $this->_getCacheFile($tplFileName,$cacheId);
  110. }else{//否则缓存文件
  111. include $this->_writeCache($tplFileName,$this->_parseTpl($tplFileName,$cacheId),$cacheId);// 写入缓存
  112. }
  113. }else{//非缓存模式
  114. include $this->_parseTpl($tplFileName,$cacheId);//解析写入编译文件并包含
  115. }
  116. }
  117. /**
  118. * 配置模板选项
  119. *
  120. * @param array $options 配置数组
  121. */
  122. public function setOptions($options)
  123. {
  124. foreach ($options as $optionName => $optionValue) {
  125. $this->set($optionName,$optionValue);
  126. }
  127. }
  128. /**
  129. * 设置选项
  130. *
  131. * @param string $optionName 选项名称
  132. * @param mixed $optionValue 选项值
  133. */
  134. public function __set($optionName,$optionValue)
  135. {
  136. $this->set($optionName,$optionValue);
  137. }
  138. /**
  139. * 单独设置配置
  140. *
  141. * @param string $optionName 选项名称
  142. * @param mixed $optionValue 选项值
  143. */
  144. public function set($optionName,$optionValue)
  145. {
  146. switch (strtolower($optionName)) {
  147. case 'template_dir':
  148. $optionValue=$this->_trimPath($optionValue).DIR_SEP;
  149. if(!file_exists($optionValue))
  150. $this->_throwException('未找到指定的模板目录"'.$optionValue.'"');
  151. $this->_options['template_dir']=$optionValue;
  152. break;
  153. case 'compile_dir':
  154. $optionValue=$this->_trimPath($optionValue).DIR_SEP;
  155. if(!file_exists($optionValue))
  156. $this->_throwException('未找到指定的编译目录"'.$optionValue.'"');
  157. $this->_options['compile_dir']=$optionValue;
  158. break;
  159. case 'cache_dir':
  160. $optionValue=$this->_trimPath($optionValue).DIR_SEP;
  161. if(!file_exists($optionValue))
  162. $this->_throwException('未找到指定的缓存目录"'.$optionValue.'"');
  163. $this->_options['cache_dir']=$optionValue;
  164. break;
  165. case 'plugins_dir':
  166. $optionValue=$this->_trimPath($optionValue).DIR_SEP;
  167. if(!file_exists($optionValue))
  168. $this->_throwException('未找到指定的缓存目录"'.$optionValue.'"');
  169. $this->_options['plugins_dir']=$optionValue;
  170. break;
  171. case 'caching':
  172. $this->_options['caching']=(boolean)$optionValue;
  173. break;
  174. case 'cache_lifetime':
  175. $this->_options['cache_lifetime']=(float)$optionValue;
  176. break;
  177. case 'php_handing':
  178. $this->_options['php_handing']=(boolean)$optionValue;
  179. break;
  180. case 'tpl_suffix':
  181. $this->_options['tpl_suffix']=trim($optionValue);
  182. break;
  183. default:
  184. $this -> _throwException("未知的模板配置选项 \"$optionName\"");
  185. }
  186. }
  187. /**
  188. * 清除模板缓存
  189. *
  190. * @param string $tplFileName='' 模板文件名,不传入则删除所有缓存
  191. * @return boolean 成功或者失败
  192. */
  193. public function clearCache($tplFileName='',$cacheId=null)
  194. {
  195. $cacheId=is_null($cacheId)?$_SERVER['REQUEST_URI']:$cacheId;
  196. if(!empty($tplFileName)){
  197. $cacheFile=$this->_getCacheFile($tplFileName,$cacheId);
  198. if(file_exists($cacheFile)){
  199. chmod($cacheFile, 0777);
  200. @unlink($cacheFile);
  201. }
  202. }else{//删除所有缓存文件
  203. foreach (glob($this->_options['cache_dir'].'*') as $cacheFile) {
  204. chmod($cacheFile, 0777);
  205. @unlink($cacheFile);
  206. }
  207. }
  208. }
  209. /**
  210. * 检测是否缓存了指定模板文件
  211. *
  212. * @param string $tplFileName 模板文件名
  213. * @return boolean
  214. */
  215. public function isCached( $tplFileName,$cacheId=null)
  216. {
  217. $tplFilePath=$this->_getTplPath($tplFileName);
  218. $cacheId=is_null($cacheId)?$_SERVER['REQUEST_URI']:$cacheId;
  219. $cacheFile=$this->_getCacheFile($tplFileName,$cacheId);
  220. if(file_exists($cacheFile) //存在
  221. and filemtime($cacheFile)+$this->_options['cache_lifetime']>time()//未过期
  222. and filemtime($cacheFile)>filemtime($tplFilePath) //模板没有改动
  223. ){//存在并没过期
  224. return true;
  225. }else{
  226. return false;
  227. }
  228. }
  229. /**
  230. * 获取内置变量
  231. * @return array
  232. */
  233. protected function _getSystemVars($tplFileName){
  234. //内置变量
  235. $_sysVars=array();
  236. $_sysVars['dolr_now']=time();
  237. $_sysVars['dolr_get']=$_GET;
  238. $_sysVars['dolr_post']=$_POST;
  239. $_sysVars['dolr_request']=$_REQUEST;
  240. $_sysVars['dolr_cookie']=isset($_COOKIE)?$_COOKIE:null;
  241. $_sysVars['dolr_session']=isset($_SESSION)?$_SESSION:null;
  242. $_sysVars['dolr_template']=basename($tplFileName);
  243. $const=get_defined_constants(true);
  244. $_sysVars['dolr_const']=$const['user'];
  245. $_sysVars['dolr_url']="http://".$_SERVER ['HTTP_HOST'].$_SERVER['PHP_SELF'];
  246. if(!empty($_SERVER['QUERY_STRING'])){
  247. $_sysVars['dolr_url'].='?'.$_SERVER['QUERY_STRING'];
  248. }
  249. return $_sysVars;
  250. }
  251. /**
  252. * 获取模板文件路径
  253. *
  254. * @param string $tplFileName 模板文件
  255. * @return string 文件名
  256. */
  257. protected function _getTplPath($tplFileName)
  258. {
  259. return $this->_options['template_dir'].$this->_trimPath($tplFileName);
  260. }
  261. /**
  262. * 获取缓存的文件
  263. * @param string $tplFileName 模板文件
  264. * @return string 文件名
  265. */
  266. protected function _getCacheFile($tplFileName, $cacheId)
  267. {
  268. return $this->_options['cache_dir'].$tplFileName.'.cache.'.md5($cacheId).'.php';
  269. }
  270. /**
  271. * 获取编译的文件名
  272. *
  273. * @param string $tplFileName 模板文件
  274. * @return string 文件名
  275. */
  276. protected function _getCompileFile( $tplFileName, $cacheId)
  277. {
  278. return $this->_options['compile_dir'].$tplFileName.'.compile.php';
  279. }
  280. /**
  281. * 解析模板
  282. *
  283. * @param string $tplFileName 模板文件
  284. * @return string 解析后的内容
  285. */
  286. protected function _parseTpl($tplFileName,$cacheId)
  287. {
  288. $tplFilePath=$this->_getTplPath($tplFileName);
  289. if (!file_exists($tplFilePath) or !is_readable($tplFilePath)) {
  290. $this->_throwException('不能打开指定的模板文件"'.$tplFileName.'"');
  291. }
  292. $content=file_get_contents($tplFilePath);
  293. //检测包含,检测所有的include 'xxx.html'
  294. preg_match_all('/[\n\r\t]*[\n\r\t]*/s', $content, $matches);
  295. if(!empty($matches[1])){
  296. foreach ($matches[1] as $key=>$fileName) {
  297. $includeFilePath=$this->_getTplPath($fileName);
  298. if (!file_exists($includeFilePath) or !is_readable($includeFilePath)) {
  299. $this->_throwException('不能打开指定的模板文件"'.$includeFilePath.'"');
  300. }
  301. $includeCompilePath=$this->_getCompileFile($fileName,$cacheId);//得到编译文件名
  302. $this->_parseTpl($fileName,$cacheId);
  303. $content=str_replace($matches[0][$key], '', $content);
  304. }
  305. }
  306. //规则
  307. $pattern=array(
  308. '/ \?\>[\n\r]*\
  309. '/(]+)\s*>)/es',//直接输出变量内容
  310. '//s',//包含模板
  311. '/(.+?)/ies',//if /if
  312. '//ies',//elseif
  313. '//is',//else
  314. '/(.+?)(.+?)/ies',//loop $array $v
  315. '/(.+?)/ies',//loop $array $v
  316. '/(.+?)(.+?)/ies',//loop $array $k $v loopelse
  317. '/(.+?)/ies',//loop $array $k $v
  318. '//',//
  319. );
  320. //PHP格式
  321. $php=array(
  322. ' ',
  323. "\$this->_parseVar('\\1')",
  324. '_options['template_dir']."\\1';?>",
  325. "\$this->_stripvtags('','\\2');",
  326. "\$this->_stripvtags('','');",
  327. '',
  328. "\$this->_stripvtags('','\\3\\4');",
  329. "\$this->_stripvtags('','\\3\n');",
  330. "\$this->_stripvtags(' \\3) { ?>','\\4\\5');",
  331. "\$this->_stripvtags(' \\3) { ?>','\\4');",
  332. "",
  333. );
  334. $content=preg_replace($pattern, $php, $content);
  335. //包含插件
  336. $pluginsString='';
  337. if($tplFileName==$this->mainTplFileName){//如果为主模板则放入include文件
  338. foreach ($this->includePlugins as $plugin) {
  339. $pluginsString.="include \$this->_options['plugins_dir'].'{$plugin}';\n";
  340. }
  341. }
  342. $header=
  343. /**
  344. * {$tplFileName}
  345. * DolrViews 模板编译文件
  346. * @package {$this->mainTplFileName}
  347. */
  348. defined('DOLRVIEWS') or exit('Access denied');
  349. $pluginsString
  350. ?>\n
  351. DOLRVIEWS;
  352. $content=$header.$content;
  353. $compileFilePath=$this->_writeCompile($tplFileName,$content,$cacheId);//写入编译文件
  354. return $compileFilePath;
  355. }
  356. /**
  357. * 缓存模板文件
  358. *
  359. * @param string $tplFileName 模板文件
  360. * @param string $cacheId 缓存ID
  361. */
  362. protected function _writeCache($tplFileName,$cacheId)
  363. {
  364. $tplFilePath=$this->_getTplPath($tplFileName);
  365. $cacheFilePath=$this->_getCacheFile($tplFileName,$cacheId);//保存文件名
  366. $compileFilePath=$this->_getCompileFile($tplFileName,$cacheId);
  367. ini_set('error_reporting','off');//不缓存错误提示
  368. extract($this->_tpl_vars);//模板变量
  369. extract($this->_getSystemVars($tplFileName));//系统变量
  370. ob_start();
  371. if(file_exists($compileFilePath) and filemtime($compileFilePath)>filemtime($tplFilePath))//模板没有改动
  372. {
  373. include $compileFilePath;
  374. }else{
  375. include $this->_parseTpl($tplFileName,$cacheId);//解析并写入编译文件
  376. }
  377. $html=ob_get_contents();
  378. ob_clean();
  379. file_put_contents($cacheFilePath, $html);
  380. return $cacheFilePath;
  381. }
  382. /**
  383. * 写入编译文件
  384. *
  385. * @param string $tplFileName 模板文件
  386. * @param string $cacheId 缓存ID
  387. * @param string $content 网页
  388. */
  389. protected function _writeCompile($tplFileName,$content,$cacheId)
  390. {
  391. $compileFilePath=$this->_getCompileFile($tplFileName,$cacheId);//保存文件名
  392. if(!file_exists(dirname($compileFilePath))){
  393. $this->_makeDir(dirname($compileFilePath));
  394. }
  395. file_put_contents($compileFilePath,$content);
  396. return $compileFilePath;
  397. }
  398. /**
  399. * 将路径修正为适合操作系统的形式
  400. *
  401. * @param string $path 路径名称
  402. * @return string
  403. */
  404. protected function _trimPath( $path)
  405. {
  406. return rtrim(str_replace(array('/', '\\', '//', '\\\\'),DIR_SEP, $path),DIR_SEP);
  407. }
  408. /**
  409. * 根据指定的路径创建不存在的文件夹
  410. *
  411. * @param string $path 路径/文件夹名称
  412. * @return string
  413. */
  414. protected function _makeDir( $path)
  415. {
  416. $dirs = explode(DIR_SEP, $this ->_trimPath($path));
  417. $tmp = '';
  418. foreach ($dirs as $dir)
  419. {
  420. $tmp .= $dir . DIR_SEP;
  421. if (!file_exists($tmp) && [email protected]($tmp, 0777))
  422. return $tmp;
  423. }
  424. return true;
  425. }
  426. /**
  427. * 变量处理
  428. *
  429. * @param string $string 目标字符串
  430. * @return string
  431. */
  432. protected function _parseVar($string){
  433. $pattern=array(
  434. '/^',
  435. '/>$/',
  436. '/(\$\w+\|[^>\s]+)/e',//$title|striptags|html2text
  437. '/(\$[\w]+\.[\w]+)/e',
  438. );
  439. $replacement=array(
  440. "
  441. ' ?>',
  442. "\$this->_parseModifier('\\1');",
  443. "\$this->_parsePoint('\\1');",
  444. );
  445. return stripslashes(preg_replace($pattern, $replacement, $string));
  446. }
  447. /**
  448. * 变量调节器的处理
  449. *
  450. * @param string $string 模板中匹配到的变量
  451. * @return string 处理后的字符串
  452. */
  453. protected function _parseModifier($string)
  454. {
  455. $arr=explode('|', trim($string,';'));
  456. $tmp=array_shift($arr);
  457. foreach($arr as $value)
  458. {
  459. $tmpArr=explode(':',$value);//html2text
  460. $funcName=array_shift($tmpArr);//html2text
  461. $args=count($tmpArr)>0?','.join(',',$tmpArr):'';//参数用,号链接 arg1,arg2,arg3
  462. if(!function_exists($funcName)){//如果不是PHP内置函数则包含插件
  463. if(!file_exists($this->_options['plugins_dir'].'modifier_'.$funcName.'.php')){
  464. $this->_throwException('插件"'.$funcName.'"不存在');
  465. }
  466. $pluginFileName='modifier_'.$funcName.'.php';
  467. if(!in_array($pluginFileName, $this->includePlugins)){
  468. $this->includePlugins[]=$pluginFileName;//添加include插件
  469. }
  470. $tmp="dolr_modifier_{$funcName}($tmp{$args})";
  471. }else{
  472. $tmp="{$funcName}($tmp{$args})";
  473. }
  474. }
  475. return stripslashes($tmp.';');
  476. }
  477. /**
  478. * 数组操作的点支持
  479. *
  480. * @param string $string 目标字符串
  481. * @return string
  482. */
  483. protected function _parsePoint($string)
  484. {
  485. $arr=explode('.',$string);//$a.b.c.f
  486. $varName=array_shift($arr);//$a
  487. return $varName.'[\''.join('\'][\'',$arr).'\']';//$a['b']['c']['f']
  488. }
  489. /**
  490. * 去掉自定义标签
  491. *
  492. * @param string $expr 源文
  493. * @param string $statement 替换目标
  494. * @return string
  495. */
  496. protected function _stripvtags($expr, $statement)
  497. {
  498. $expr = str_replace("\\\"", "\"", preg_replace("/\/s", "\\1", $expr));
  499. $statement = str_replace("\\\"", "\"", $statement);
  500. return $expr . $statement;
  501. }
  502. /**
  503. * 抛出一个错误信息
  504. *
  505. * @param string $message
  506. * @return void
  507. */
  508. protected function _throwException($message)
  509. {
  510. trigger_error('DolrViews错误:'.$message);
  511. exit;
  512. }
  513. }
  514. /* vim: set expandtab: */

使用范例:
PHP:
  1. include 'DolrViews.class.php';
  2. $tpl=DolrViews::getInstance();//单例
  3. $_options=array(
  4. 'template_dir'=>'templates',//模板目录
  5. 'compile_dir'=>'templates_c',//编译目录
  6. 'cache_dir'=>'cache',//缓存目录
  7. 'caching'=>false,//是否缓存
  8. 'cache_lifetime'=>3600,//缓存有效期
  9. 'plugins_dir'=>'plugins',//插件目录
  10. 'tpl_suffix'=>'html',//模板后缀
  11. );
  12. $tpl->setOptions($_options);//保存如上设置
  13. $title="标题测试啊";
  14. $val=3;
  15. $array=array(
  16. array('username'=>'Joychao','password'=>'nowpass'),
  17. array('username'=>'DolrPHP','password'=>'password'),
  18. );
  19. $var='这里是带标签的HTML';
  20. //分配变量
  21. $tpl->assign('val',$val);
  22. $tpl->assign('title',$title);
  23. $tpl->assign('array',$array);
  24. //显示
  25. $tpl->display('index.html');
模板index.html:
  1. --包含文件----------------------------
  2. ------if else------------------------
  3. do anything
  4. do another
  5. Do not
  6. ---------------------------------
  7. ------loop------------------------
  8. 循环内容

  9. 交互式显示:
  10. 循环中的变量:
  11. 循环中的索引$dolr_index:ccc

  12. 没有内容
  13. ---------------------------------
  14. --包含文件----------------------------
  15. ------------------------------

目录范例:
DolrViews/
|--cache //缓存目录
|--plugins //插件目录
|--templates //模板目录
|--templates_c //编译文件目录
|--DolrViews.classs.php //引擎主文件
|--index.php //测试文件


目前插件只写了一个测试,插件规范是modifier_函数名.php 内容函数名:dolr_modifier_函数名($第一个参数必须[,其它参数])。范例:
  1. function dolr_modifier_html2text($string)
  2. {
  3. return strip_tags($string);
  4. }

今天刚写的,欢迎大家拍砖啊! 另外欢迎@安正超 !

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.