PageRenderTime 42ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/system/core/Template/TE/class.VTP.php

https://gitlab.com/vanthanhhoh/devlovebook
PHP | 496 lines | 426 code | 42 blank | 28 comment | 71 complexity | c1b1f22e9cd083b0d0cf40658a4784b8 MD5 | raw file
  1. <?php
  2. require './Exception.php';
  3. //$ArrayElement = '(\w+(?:\.\${0,1}[A-Za-z0-9_]+)*(?:(?:\[\${0,1}[A-Za-z0-9_]+\])|(?:\-\>\${0,1}[A-Za-z0-9_]+))*)(.*?)';
  4. class VTE
  5. {
  6. private $Tag = array('left' => '{', 'right' => '}');
  7. protected $SingleVar = '[a-zA-Z0-9\_]';
  8. protected $VarElement = '\w+(?:\.\${0,1}[A-Za-z0-9_]+)*(?:(?:\[\${0,1}[A-Za-z0-9_]+\])|(?:\-\>\${0,1}[A-Za-z0-9_]+))*(.*?)';
  9. private $CACHE_EXPIRE_TIME = 3600; // default cache expire time = hour
  10. private $InputTPLString = '';
  11. private $TPLFileName = '';
  12. private $HtmlString = '';
  13. private $CompiledPHPCode = '';
  14. private $TPLFilePath = '';
  15. private $CompiledFilePath = '';
  16. private $CachedFilePath = '';
  17. private $ReCompile = false;
  18. private $IsCache = false;
  19. private $VAR = array();
  20. static $TPLFileDir = '/';
  21. static $CompiledDir = '/';
  22. static $CacheDir = '/';
  23. static $MergedDir = '/';
  24. public $_TPLFileDir = '/';
  25. public $_CompiledDir = '/';
  26. public $_CacheDir = '/';
  27. public $_MergedDir = '/';
  28. public $TPLFileExt = '.tpl';
  29. static function TPLFileDir($TPLFileDir) {
  30. self::$TPLFileDir = $TPLFileDir;
  31. }
  32. public function __construct() {
  33. $this->_TPLFileDir = self::$TPLFileDir;
  34. $this->_CompiledDir = self::$CompiledDir;
  35. $this->_CacheDir = self::$CacheDir;
  36. $this->_MergedDir = self::$MergedDir;
  37. }
  38. public function SetDir($Name, $Value) {
  39. $Name = '_' . $Name;
  40. $this->$Name = $Value;
  41. return $this;
  42. }
  43. public function String($HtmlString = '', $ReCompile = false, $IsCache = false) {
  44. $this->ReCompile = $ReCompile;
  45. $this->IsCache = $IsCache;
  46. $this->HtmlString = $HtmlString;
  47. return $this;
  48. }
  49. public function Compiled($CompiledPHPCode, $ReCompile = false, $IsCache) {
  50. $this->ReCompile = $ReCompile;
  51. $this->IsCache = $IsCache;
  52. $this->CompiledPHPCode = $TPLFileOrHtmlStringOrCompiledPHPCode;
  53. return $this;
  54. }
  55. public function File($TPLFile = '', $ReCompile = false, $IsCache = false) {
  56. $this->ReCompile = $ReCompile;
  57. $this->IsCache = $IsCache;
  58. $this->TPLFileName = $TPLFile;
  59. $this->InputTPLString = $this->ReadTPLFile();
  60. return $this;
  61. }
  62. public function Assign($Name, $Value = NULL) {
  63. is_array($Name) ? $this->VAR += $Name : $this->VAR[$Name] = $Value;
  64. return $this;
  65. }
  66. public function Output($Return = false, $ReturnCompiled = false) {
  67. $TPLFileName = rtrim(basename($this->TPLFilePath), $this->TPLFileExt);
  68. $EncodedFileName = $TPLFileName . '_' . md5($this->TPLFilePath);
  69. $this->CompiledFilePath = $this->_CompiledDir . $EncodedFileName . '.php';
  70. $this->CachedFilePath = $this->_CacheDir . $EncodedFileName . '.html';
  71. if( $this->ReCompile ||
  72. !file_exists($this->CompiledFilePath) ||
  73. (file_exists($this->CompiledFilePath) && filemtime($this->CompiledFilePath) < filemtime($this->TPLFilePath))
  74. ) $ReCompile = true;
  75. else $ReCompile = false;
  76. if($ReCompile) $this->CompileTPL();
  77. if($ReturnCompiled) {
  78. $CompiledContent = file_get_contents($this->CompiledFilePath);
  79. return array('var' => $this->VAR, 'content' => $CompiledContent);
  80. }
  81. elseif($this->IsCache) {
  82. $CacheLifeTime = time() - filemtime($this->CachedFilePath);
  83. if(file_exists($this->CachedFilePath) && $CacheLifeTime < $this->CACHE_EXPIRE_TIME )
  84. file_get_contents( $this->CachedFilePath );
  85. else
  86. file_put_contents($this->CachedFilePath, $OutputContent );
  87. }
  88. elseif(!$Return && !$this->IsCache) {
  89. extract($this->VAR);
  90. include $this->CompiledFilePath;
  91. }
  92. else {
  93. ob_start();
  94. extract($this->VAR);
  95. include $this->CompiledFilePath;
  96. $OutputContent = ob_get_clean();
  97. // return or print the template
  98. if($Return) return $OutputContent; else echo $OutputContent;
  99. }
  100. }
  101. private function ReadTPLFile() {
  102. $this->TPLFilePath = $this->_TPLFileDir . $this->TPLFileName . $this->TPLFileExt;
  103. if(file_exists($this->TPLFilePath)) {
  104. return file_get_contents($this->TPLFilePath);
  105. }
  106. else {
  107. throw new VTE_Exception ('TPL file not found ' . $this->TPLFileName);
  108. trigger_error('TPL file not found ' . $this->TPLFileName);
  109. }
  110. }
  111. private function DetectCodeTag() {
  112. $SingleVar = $this->SingleVar;
  113. $VarElement = $this->VarElement;
  114. $CodesCheck =
  115. array(
  116. 'if' => 'if(:condition){0,1}\s*\(.*\)',
  117. 'elseif' => 'elseif(:condition){0,1}\s*\(.*\)',
  118. 'else' => 'else',
  119. 'end_if' => '\/if',
  120. 'for' => 'for\s+\$' . $SingleVar . '+\s+in\s+\$' . $VarElement . '*\s*(?: as\s+\$' . $SingleVar . '+)?',
  121. 'end_for' => '\/for',
  122. 'while' => 'while(:condition){0,1}\s*\(.*\)',
  123. 'end_while' => '\/while',
  124. 'skip' => 'skip',
  125. 'end_skip' => '\/skip',
  126. 'comment' => '\/\*\*',
  127. 'end_comment' => '\*\*\/'
  128. );
  129. $_c = array();
  130. foreach($CodesCheck as $key =>$code)
  131. $_c[$key] = '(\\' . $this->Tag['left'] . $code . '\\' . $this->Tag['right'] . ')';
  132. $CodesCheck = $_c; unset($_c);
  133. $CodesCheck = '/' . join('|', $CodesCheck) . '/';
  134. return preg_split ($CodesCheck, $this->InputTPLString, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
  135. }
  136. private function VariableTrueForm($Var) {
  137. $_temp = preg_split( "/\.|\[|\-\>/", $Var );
  138. $VarName = $_temp[0];
  139. //variable path
  140. $VariablePath = substr( $Var, strlen( $VarName ) );
  141. //parentesis transform [ e ] in [" e in "]
  142. $VariablePath = str_replace( '[', "['", $VariablePath );
  143. $VariablePath = str_replace( ']', "']", $VariablePath );
  144. //transform .$variable in ["$variable"] and .variable in ["variable"]
  145. $VariablePath = preg_replace('/\.(\${0,1}\w+)/', "['\\1']", $VariablePath );
  146. return $VarName . $VariablePath;
  147. }
  148. private function CompileFunction($Code, $echo = false) {
  149. if(preg_match_all('/' . '\{\#{0,1}(\"{0,1}.*?\"{0,1})(\|\w.*?)\#{0,1}\}' . '/', $Code, $matches)) {
  150. $Parsed = array();
  151. $TotalTags = count($matches[0]);
  152. for($i = 0; $i < $TotalTags; $i++) {
  153. $Tag['key'] = $matches[0][$i];
  154. $Tag['VariableName'] = $matches[1][$i];
  155. $Tag['ExtraFunction'] = $matches[2][$i];
  156. $Tag['FunctionName'] = '';
  157. $Tag['FunctionParams'] = '';
  158. if($Tag['ExtraFunction'] && $Tag['ExtraFunction'][0] == '|') {
  159. $Tag['ExtraFunction'] = ltrim($Tag['ExtraFunction'], '|');
  160. //Check Static Class method
  161. if(strpos($Tag['ExtraFunction'], '::') != NULL)
  162. $Tag['ExtraFunction'] = str_replace('::', '@@StaticClassMethodSignal@@', $Tag['ExtraFunction']);
  163. if(strpos($Tag['ExtraFunction'], ':') != NULL) {
  164. $_f = explode(':', $Tag['ExtraFunction']);
  165. $Tag['FunctionName'] = $_f[0];
  166. $Tag['FunctionParams'] = $_f[1];
  167. }
  168. else $Tag['FunctionName'] = $Tag['ExtraFunction'];
  169. $Tag['FunctionName'] = str_replace('@@StaticClassMethodSignal@@', '::', $Tag['FunctionName']);
  170. $FunctionName = $Tag['FunctionName'];
  171. $VariableName = $this->VariableTrueForm($Tag['VariableName']);
  172. $ExtraParams = $Tag['FunctionParams'];
  173. $PhpCompiled = ($echo ? 'echo ' : NULL) . (!empty($ExtraParams) ? "$FunctionName($VariableName,$ExtraParams)" : "$FunctionName($VariableName)");
  174. $PhpCompiled = '<?php ' . $PhpCompiled . ' ?>';
  175. $Code = str_replace($Tag['key'], $PhpCompiled, $Code);
  176. }
  177. }
  178. }
  179. return $Code;
  180. }
  181. private function CompileVariable($Code, $echo = true) {
  182. if(preg_match_all('/\{\$(' . $this->VarElement . ')\}/', $Code, $matches)) {
  183. $n = count($matches[0]);
  184. $Parsed = array();
  185. for($i = 0; $i < $n; $i++ )
  186. $Parsed[$matches[0][$i]] = array('Var' => $matches[1][$i],'ExtraVar'=>$matches[2][$i]);
  187. foreach($Parsed as $Key => $Value) {
  188. $IsInitializeVar = false;
  189. $VarKey = '';
  190. if(preg_match_all('/\{(\$' . $this->VarElement . ')((?:\+\+|\-\-|\+=|\-=|\*=|=)([^=].*))\}/', $Key, $m)) {
  191. $VarKey = $m[1][0];
  192. $IsInitializeVar = true;
  193. }
  194. if($IsInitializeVar) {
  195. $PhpCompiled = '<?php ' . $this->VariableTrueForm($VarKey) . $Value['ExtraVar'] . ' ?>';
  196. }
  197. elseif($echo) {
  198. $PhpCompiled = '<?php ' . ($echo ? 'echo ' : NULL) . $this->VariableTrueForm('$' . $Value['Var']) . ' ?>';
  199. }
  200. else
  201. $PhpCompiled = $this->VariableTrueForm('$' . $Value['Var']);
  202. $Code = str_replace($Key, $PhpCompiled, $Code);
  203. }
  204. }
  205. return $Code;
  206. }
  207. private function CompileConstant($Code, $echo = true) {
  208. if(preg_match_all('/\{\#(' . $this->VarElement . ')\}/', $Code, $matches)) {
  209. $n = count($matches[0]);
  210. $Parsed = array();
  211. for($i = 0; $i < $n; $i++ )
  212. $Parsed[$matches[0][$i]] = array('Var' => $matches[1][$i],'ExtraVar'=>$matches[2][$i]);
  213. foreach($Parsed as $Key => $Value) {
  214. $IsInitializeVar = false;
  215. $VarKey = '';
  216. if($echo) {
  217. $PhpCompiled = '<?php ' . ($echo ? 'echo ' : NULL) . $Value['Var'] . ' ?>';
  218. }
  219. else
  220. $PhpCompiled = $Value['Var'];
  221. $Code = str_replace($Key, $PhpCompiled, $Code);
  222. }
  223. }
  224. return $Code;
  225. }
  226. private function CompileCondition($Code, $echo = false) {
  227. if(preg_match_all('/\$(' . $this->VarElement . ')/', $Code, $matches)) {
  228. $n = count($matches[0]);
  229. $Parsed = array();
  230. for($i = 0; $i < $n; $i++ )
  231. $Parsed[$matches[0][$i]] = array('Var' => $matches[1][$i],'ExtraVar'=>$matches[2][$i]);
  232. foreach($Parsed as $Key => $Value) {
  233. if($echo)
  234. $PhpCompiled = '<?php ' . ($echo ? 'echo ' : NULL) . $this->VariableTrueForm('$' . $Value['Var']) . ' ?>';
  235. else
  236. $PhpCompiled = $this->VariableTrueForm('$' . $Value['Var']);
  237. $Code = str_replace($Key, $PhpCompiled, $Code);
  238. }
  239. }
  240. return $Code;
  241. }
  242. private function CompileTPL() {
  243. $TPLCodes = $this->DetectCodeTag();
  244. //n($TPLCodes);
  245. $CompiledCode = array();
  246. $IfOpen = $ForOpen = $WhileOpen = $CommentOpen = $SkipOpen = 0;
  247. $CheckCommand['if'] = '/\\' . $this->Tag['left'] . 'if\s*\(\s*(.*)\s*\)\s*\\' . $this->Tag['right'] . '/';
  248. $CheckCommand['elseif'] = '/\\' . $this->Tag['left'] . 'elseif(?: condition){0,1}\s*\(\s*(.*)\s*\)\s*\\' . $this->Tag['right'] . '/';
  249. $CheckCommand['for'] = '/\\' . $this->Tag['left'] . 'for\s+\$(?P<ArrayElement>' . $this->VarElement . ')\s+in\s+\$(?P<Array>' . $this->VarElement . ')\s*(?: as\s+\$(?P<ArrayKey>' . $this->VarElement . '))?\\' . $this->Tag['right'] . '/';
  250. $CheckCommand['while'] = '/\\' . $this->Tag['left'] . 'while\s*\(\s*(.*)\s*\)\s*\\' . $this->Tag['right'] . '/';
  251. while($Html = array_shift($TPLCodes)) {
  252. // Remove all comment tag
  253. if($Html == '{**/}') {
  254. if($CommentOpen < 1) continue;
  255. else $CommentOpen--;
  256. }
  257. elseif($Html == '{/**}') {
  258. $CommentOpen++;
  259. }
  260. elseif($CommentOpen > 0 ) continue;
  261. // Skip all betwen Skip tag
  262. elseif($Html == '{skip}') {
  263. $SkipOpen++;
  264. if($SkipOpen == 1) continue;
  265. else $CompiledCode[] = $Html;
  266. }
  267. elseif($Html == '{/skip}') {
  268. if($SkipOpen == 1) {
  269. $SkipOpen = 0;
  270. continue;
  271. }
  272. else {
  273. $SkipOpen--;
  274. $CompiledCode[] = $Html;
  275. }
  276. }
  277. elseif($SkipOpen > 0) $CompiledCode[] = $Html;
  278. // Compile If command
  279. elseif(preg_match($CheckCommand['if'], $Html, $Code)) {
  280. $IfOpen++;
  281. $IfCondition = $Code[1];
  282. $parsed_condition = $this->CompileCondition($IfCondition, false);
  283. $CompiledCode[] = "<?php if($parsed_condition) { ?>";
  284. }
  285. //elseif
  286. elseif( preg_match($CheckCommand['elseif'], $Html, $Code ) ){
  287. $tag = $code[0];
  288. $condition = $code[1];
  289. $parsed_condition = $this->CompileCondition($condition, false);
  290. $CompiledCode[] = "<?php } elseif($parsed_condition) { ?>";
  291. }
  292. //else
  293. elseif( strpos( $Html, '{else}' ) !== FALSE )
  294. $CompiledCode[] = '<?php }else{ ?>';
  295. //close if tag
  296. elseif( strpos( $Html, '{/if}' ) !== FALSE ) {
  297. $IfOpen--;
  298. $CompiledCode[] = '<?php } ?>';
  299. }
  300. // Compile For command
  301. elseif(preg_match($CheckCommand['for'], $Html, $Code)) {
  302. $ForOpen++;
  303. $Array = $this->VariableTrueForm('$' . $Code['Array']);
  304. $ArrayElement = $this->VariableTrueForm('$' . $Code['ArrayElement']);
  305. if(isset($Code['ArrayKey'])) {
  306. $ArrayKey = $this->VariableTrueForm('$' . $Code['ArrayKey']);
  307. $CompiledCode[] = "<?php foreach( $Array as $ArrayKey => $ArrayElement) { ?>";
  308. }
  309. else
  310. $CompiledCode[] = "<?php foreach( $Array as $ArrayElement) { ?>";
  311. }
  312. //close For tag
  313. elseif( strpos( $Html, '{/for}' ) !== FALSE ) {
  314. $ForOpen--;
  315. $CompiledCode[] = '<?php } ?>';
  316. }
  317. // Compile While command
  318. elseif(preg_match($CheckCommand['while'], $Html, $Code)) {
  319. $WhileOpen++;
  320. $While = $Code[1];
  321. $parsed_while = $this->CompileCondition($While, false);
  322. $CompiledCode[] = "<?php while($parsed_while) { ?>";
  323. }
  324. //close For tag
  325. elseif( strpos( $Html, '{/while}' ) !== FALSE ) {
  326. $WhileOpen--;
  327. $CompiledCode[] = '<?php } ?>';
  328. }
  329. else {
  330. $Html = $this->CompileFunction($Html, true);
  331. $Html = $this->CompileConstant($Html, true);
  332. $CompiledCode[] = $this->CompileVariable($Html, true);
  333. }
  334. //else $CompiledCode[] = '<font color="red">' . $Html . '</font>';
  335. }
  336. file_put_contents($this->CompiledFilePath, $CompiledCode);
  337. }
  338. static function MergeCompiledFile($CompiledData,$MergedFileName) {
  339. $MergedContent = array();
  340. foreach($CompiledData as $D) {
  341. $_Var = var_export($D['var'], true);
  342. $_Content = $D['content'];
  343. $MergedContent[] = '<?php $_Var = ' . $_Var . '; extract($_Var); ?>' . $_Content;
  344. }
  345. file_put_contents(VTE::$MergedDir . $MergedFileName, implode(PHP_EOL, $MergedContent));
  346. }
  347. static function DeleteMergedFiles($Path = '') {
  348. if($Path == '') $Path = VTE::$MergedDir;
  349. $ListFiles = glob($Path . '*');
  350. foreach($ListFiles as $File)
  351. if(is_file($File)) unlink($File);
  352. /*
  353. foreach (new DirectoryIterator($Path) as $fileInfo) {
  354. if(!$fileInfo->isDot()) {
  355. unlink($fileInfo->getPathname());
  356. //unlink($Path . $fileInfo->getPathname());
  357. }
  358. }
  359. */
  360. }
  361. static function DeleteCompiledFiles($Path = '') {
  362. if($Path == '') $Path = VTE::$CompiledDir;
  363. $ListFiles = glob($Path . '*');
  364. foreach($ListFiles as $File)
  365. if(is_file($File)) unlink($File);
  366. }
  367. static function DeleteCachedFiles($Path = '') {
  368. if($Path == '') $Path = VTE::$CacheDir;
  369. $ListFiles = glob($Path . '*');
  370. foreach($ListFiles as $File)
  371. if(is_file($File)) unlink($File);
  372. }
  373. }
  374. class MergedTPL
  375. {
  376. private $MergedFileList = array();
  377. private $MergedData = array();
  378. private $TotalFile = 0;
  379. private $CurrentFile = 0;
  380. static $TPLFileDir = '/';
  381. static $CacheDir = '/';
  382. static $MergedDir = '/';
  383. private $TPLFileExt = '.tpl';
  384. private function Init() {
  385. MergedTPL::$TPLFileDir = VTE::$TPLFileDir;
  386. MergedTPL::$CacheDir = VTE::$CacheDir;
  387. MergedTPL::$MergedDir = VTE::$MergedDir;
  388. }
  389. public function Merge($TPLFileList) {
  390. $this->Init();
  391. $this->TotalFile = count($TPLFileList);
  392. $this->MergedFileList = $TPLFileList;
  393. return $this;
  394. }
  395. public function SavePath($Path = '') {
  396. if($Path != '') MergedTPL::$MergedDir = $Path;
  397. return $this;
  398. }
  399. public function AddFile($TPLFileName, $Vars = array(), $TPLFileDir = '') {
  400. $this->CurrentFile++;
  401. $TPLFileDir = ($TPLFileDir == '') ? MergedTPL::$TPLFileDir : $TPLFileDir;
  402. //$TPLFileName = rtrim($TPLFileName, '.tpl');
  403. $this->MergedData[$this->CurrentFile] = array('file' => $TPLFileName, 'dir' => $TPLFileDir, 'var' . $this->CurrentFile => $Vars);
  404. return $this;
  405. }
  406. public function OutputMerged($Return = false, $ReCompiled = false) {
  407. $MergedVars = array();
  408. $FileName = implode('_', $this->MergedFileList);
  409. $MergedFilePath = MergedTPL::$MergedDir . $FileName . '_' . md5($FileName) . '.php';
  410. $DetectTPLChanged = 0;
  411. $MergedFileTime = filemtime($MergedFilePath);
  412. foreach($this->MergedData as $i => $Data) {
  413. $MergedVars['var' . $i] = $Data['var' . $i];
  414. $_TPLFile = $Data['dir'] . $Data['file'] . $this->TPLFileExt;
  415. if(filemtime($_TPLFile) > $MergedFileTime)
  416. $DetectTPLChanged++;
  417. }
  418. if(file_exists($MergedFilePath) && !$ReCompiled && $DetectTPLChanged == 0) {
  419. }
  420. else {
  421. $MergedContent = '';
  422. foreach($this->MergedData as $i => $Data) {
  423. $MergedVars['var' . $i] = $Data['var' . $i];
  424. $MergedContent .= '<?php extract($MergedVars[\'var' . $i . '\']); ?>';
  425. $_CompiledFile = TPL::File($Data['file'], true)
  426. ->SetDir('TPLFileDir', $Data['dir'])
  427. //->Assign('var' . $i, $Data['var' . $i])
  428. ->Output(false, true);
  429. $MergedContent .= $_CompiledFile['content'];
  430. }
  431. file_put_contents($MergedFilePath, '<?php if(!class_exists(\'MergedTPL\')) die(\'Invalid action!\') ?>' . $MergedContent);
  432. }
  433. if($Return) {
  434. ob_start();
  435. include $MergedFilePath;
  436. $OutputContent = ob_get_clean();
  437. return array('var' => $MergedVars, 'content' => $OutputContent);
  438. }
  439. else include $MergedFilePath;
  440. }
  441. }
  442. class TPL
  443. {
  444. static function File($TPLFile = '', $ReCompile = false, $IsCache = false) {
  445. $TPL = new VTE();
  446. return $TPL->File($TPLFile, $ReCompile, $IsCache);
  447. }
  448. static function Merge() {
  449. $Parameters = func_get_args();
  450. $TPL = new MergedTPL();
  451. return $TPL->Merge($Parameters);
  452. }
  453. }
  454. ?>