25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

729 lines
25 KiB

  1. <?php
  2. namespace Kuxin;
  3. use Kuxin\Helper\Arr;
  4. use Kuxin\Helper\OpenCC;
  5. /**
  6. * Class View
  7. *
  8. * @package Kuxin
  9. * @author Pakey <pakey@qq.com>
  10. */
  11. class View
  12. {
  13. // 模板存储变量
  14. protected static $_vars = [];
  15. // 模版基地址
  16. protected static $_path = '';
  17. // 模版文件名
  18. protected static $_file = null;
  19. // layout 开关
  20. protected static $_layout = false;
  21. // layout 模板
  22. protected static $_layoutFile = '';
  23. // 文件后缀
  24. protected static $suffix = '.phtml';
  25. /**
  26. * 开启layout
  27. */
  28. public static function enableLayout()
  29. {
  30. self::$_layout = true;
  31. }
  32. /**
  33. * 关闭layout
  34. */
  35. public static function disableLayout()
  36. {
  37. self::$_layout = false;
  38. }
  39. /**
  40. * 配置layoutFile
  41. * @param string $file
  42. */
  43. public static function setLayoutFile(string $file)
  44. {
  45. self::$_layoutFile = $file;
  46. }
  47. /**
  48. * @param $file
  49. */
  50. public static function setFile(string $file)
  51. {
  52. self::$_file = $file;
  53. }
  54. /**
  55. * @param string $path
  56. */
  57. public static function setPath(string $path)
  58. {
  59. self::$_path = $path;
  60. }
  61. /**
  62. * @return string
  63. */
  64. public static function getPath()
  65. {
  66. if (empty(self::$_path)) {
  67. self::$_path = KX_ROOT . '/app/view';
  68. }
  69. return self::$_path;
  70. }
  71. /**
  72. * 模板变量赋值
  73. *
  74. * @access public
  75. * @param mixed $var
  76. * @param mixed $value
  77. */
  78. public static function set($var, $value = null)
  79. {
  80. if (is_array($var)) {
  81. self::$_vars = Arr::merge(self::$_vars, $var);
  82. } else {
  83. self::$_vars[$var] = $value;
  84. }
  85. }
  86. /*
  87. * 获取模板变量值
  88. */
  89. public static function get(string $var = '')
  90. {
  91. if ($var == '') {
  92. return self::$_vars;
  93. } elseif (isset(self::$_vars[$var])) {
  94. return self::$_vars[$var];
  95. } elseif (strpos($var, '.') !== false) {
  96. $arr = explode('.', $var);
  97. $tmp = self::$_vars;
  98. foreach ($arr as $v) {
  99. if (substr($v, 0, 1) === '$') {
  100. $v = self::get($v);
  101. }
  102. $tmp = $tmp[$v];
  103. }
  104. if (!empty($tmp)) {
  105. return $tmp;
  106. }
  107. }
  108. return null;
  109. }
  110. /**
  111. * 加载并视图片段文件内容
  112. *
  113. * @access public
  114. * @param string $file 视图片段文件名称
  115. * @param array $data 附加数据
  116. * @return string
  117. */
  118. public static function make(?string $file = null, ?array $data = [])
  119. {
  120. $data['_kxcms_config'] = Config::getAll();
  121. //复制参数
  122. if ($data) {
  123. self::set($data);
  124. }
  125. //获取模板
  126. $tplfilepath = self::getTplFilePath($file);
  127. if(Config::get('template.output_charset')!='utf-8'){
  128. self::recursionHandleValueCharset(self::$_vars, Config::get('template.output_charset'));
  129. }
  130. extract(self::$_vars, EXTR_OVERWRITE);
  131. ob_start();
  132. include self::checkCompile($tplfilepath);
  133. $content = ob_get_contents();
  134. ob_end_clean();
  135. return $content;
  136. }
  137. private static function recursionHandleValueCharset(&$data, $method)
  138. {
  139. foreach ($data as &$datum) {
  140. if (is_string($datum)) {
  141. switch ($method) {
  142. case 'gbk':
  143. $datum = iconv('utf-8', 'gbk', $datum);
  144. break;
  145. case 'big5':
  146. $datum = OpenCC::change($datum);
  147. break;
  148. }
  149. } elseif (is_array($datum)) {
  150. self::recursionHandleValueCharset($datum, $method);
  151. }
  152. }
  153. }
  154. /**
  155. * 获得模版位置
  156. *
  157. * @param string $tpl 视图模板
  158. * @return string
  159. */
  160. protected static function getTplFilePath(string $tpl = null)
  161. {
  162. $tpl = $tpl === null ? self::$_file : $tpl;
  163. if ($tpl === null) {
  164. $filepath = self::getPath() . '/' . str_replace('\\', '/', Router::$controller) . '/' . Router::$action . self::$suffix;
  165. } elseif (substr($tpl, 0, 1) === '/') {
  166. $filepath = self::getPath() . $tpl . self::$suffix;
  167. } elseif (substr($tpl, 0, 1) === '@') {
  168. $filepath = self::getPath() . '/' . substr($tpl, 1) . self::$suffix;
  169. } else {
  170. $filepath = dirname(self::getPath() . '/' . str_replace('\\', '/', Router::$controller)) . '/' . $tpl . self::$suffix;
  171. }
  172. if (is_file($filepath)) {
  173. return realpath($filepath);
  174. } else {
  175. trigger_error("模版{$tpl}不存在[" . $filepath . ']', E_USER_ERROR);
  176. return false;
  177. }
  178. }
  179. /**
  180. * @param $tplfile
  181. * @return string
  182. */
  183. protected static function checkCompile(string $tplfile)
  184. {
  185. $compiledName = ltrim(str_replace([KX_ROOT, '/app/views', '/template/'], '/', $tplfile), '/');
  186. if (!$compiledName) {
  187. trigger_error('生成的模板缓存文件名为空 [' . $tplfile . ']', E_USER_ERROR);
  188. }
  189. $compiledFile = str_replace('/', ',', $compiledName);
  190. $storage = DI::Storage('template');
  191. if (Config::get('app.debug') || !$storage->exist($compiledFile) || $storage->mtime($compiledFile) < filemtime($tplfile)) {
  192. // 获取模版内容
  193. $content = file_get_contents($tplfile);
  194. // 解析模版
  195. $content = self::compile($content);
  196. //判断是否开启layout
  197. if (self::$_layout && self::$_layoutFile) {
  198. $includeFile = self::getTplFilePath(self::$_layoutFile);
  199. $layout = self::compile(file_get_contents($includeFile));
  200. $content = str_replace('__CONTENT__', $content, $layout);
  201. }
  202. $content = '<?php defined(\'KX_ROOT\') || exit(\'Permission denied\');?>' . self::replace($content);
  203. $storage->write($compiledFile, $content);
  204. }
  205. return $storage->getPath($compiledFile);
  206. }
  207. /**
  208. * 模版输出替换
  209. *
  210. * @param $content
  211. * @return string
  212. */
  213. protected static function replace(string $content)
  214. {
  215. $replace = [
  216. '__RUNINFO__' => '<?php echo \Kuxin\Response::runinfo();?>', // 站点公共目录
  217. '__SELF__' => '<?php echo $_SERVER[\'REQUEST_URI\'];?>', // 站点公共目录
  218. ];
  219. $content = strtr($content, $replace);
  220. // 判断是否显示runtime info 信息
  221. return $content;
  222. }
  223. /**
  224. * 编译解析
  225. *
  226. * @param $content
  227. * @return mixed
  228. */
  229. public static function compile(string $content)
  230. {
  231. $left = preg_quote('{', '/');
  232. $right = preg_quote('}', '/');
  233. if (strpos($content, '<?xml') !== false) {
  234. $content = str_replace('<?xml', '<?php echo "<?xml";?>', $content);
  235. }
  236. if (!preg_match('/' . $left . '.*?' . $right . '/s', $content))
  237. return $content;
  238. // 解析载入
  239. $content = preg_replace_callback('/' . $left . 'include\s+file\s*\=\s*(\'|\")([^\}]*?)\1\s*' . $right . '/i', [
  240. 'self',
  241. 'parseInlcude',
  242. ], $content);
  243. // 解析代码
  244. $content = preg_replace_callback('/' . $left . '(code|php)' . $right . '(.*?)' . $left . '\/\1' . $right . '/is', [
  245. 'self',
  246. 'parseEncode',
  247. ], $content);
  248. // 模板注释
  249. $content = preg_replace('/' . $left . '\/\*.*?\*\/' . $right . '/s', '', $content);
  250. $content = preg_replace('/' . $left . '\/\/.*?' . $right . '/', '', $content);
  251. // 解析变量
  252. $content = preg_replace_callback('/' . $left . '(\$\w+(?:(?:\[(?:[^\[\]]+|(?R))*\])*|(?:\.[\w\-]+)*))((?:\s*\|\s*[\w\:]+(?:\s*=\s*(?:@|"[^"]*"|\'[^\']*\'|#[\w\-]+|\$[\w\-]+(?:(?:\[(?:[^\[\]]+|(?R))*\])*|(?:\.[\w\-]+)*)|[^\|\:,"\'\s]*?)(?:\s*,\s*(?:@|"[^"]*"|\'[^\']*\'|#[\w\-]+|\$[\w\-]+(?:(?:\[(?:[^\[\]]+|(?R))*\])*|(?:\.[\w\-]+)*)|[^\|\:,"\'\s]*?))*)?)*)\s*' . $right . '/', [
  253. 'self',
  254. 'parseVariable',
  255. ], $content);
  256. // 解析函数
  257. $content = preg_replace_callback('/' . $left . '(\=|~)\s*(.+?)\s*' . $right . '/', [
  258. 'self',
  259. 'parseFunction',
  260. ], $content);
  261. // 解析判断
  262. $content = preg_replace_callback('/' . $left . '(if|else\s*if)\s+(.+?)\s*' . $right . '/', [
  263. 'self',
  264. 'parseJudgment',
  265. ], $content);
  266. $content = preg_replace('/' . $left . 'else\s*' . $right . '/i', '<?php else:?>', $content);
  267. $content = preg_replace('/' . $left . 'sectionelse\s*' . $right . '/i', '<?php endforeach;else:foreach(array(1) as $__loop):?>', $content);
  268. $content = preg_replace('/' . $left . '\/if\s*' . $right . '/i', '<?php endif;?>', $content);
  269. // 解析链接
  270. $content = preg_replace_callback('/' . $left . 'link\=((?:"[^"]*"|\'[^\']*\'|#\w+|\$\w+(?:(?:\[(?:[^\[\]]+|(?R))*\])*|(?:\.\w+)*)|[^"\'\s]+?)(?:(?:\s+\w+\s*\=\s*(?:"[^"]*"|\'[^\']*\'|#\w+|\$\w+(?:(?:\[(?:[^\[\]]+|(?R))*\])*|(?:\.\w+)*)|[^"\'\s]+?))*?))\s*' . $right . '/i', [
  271. 'self',
  272. 'parseLink',
  273. ], $content);
  274. // 解析微件
  275. $content = preg_replace_callback('/' . $left . 'block((?:\s+\w+\s*\=\s*(?:"[^"]*"|\'[^\']*\'|#\w+|\$\w+(?:(?:\[(?:[^\[\]]+|(?R))*\])*|(?:\.\w+)*)|[^"\'\s]+?))+)\s*' . $right . '/i', [
  276. 'self',
  277. 'parseBlock',
  278. ], $content);
  279. // 解析循环
  280. $content = preg_replace_callback('/' . $left . 'loop\s*=([\'|"]?)(\$?\w+(?:(?:\[(?:[^\[\]]+|(?R))*\])*|(?:\.\w+)*))\1\s*' . $right . '/i', [
  281. 'self',
  282. 'parseLoop',
  283. ], $content);
  284. $content = preg_replace_callback('/' . $left . 'loop' . $right . '/i', ['self', 'parseLoop'], $content);
  285. $content = preg_replace_callback('/' . $left . 'section((?:\s+\w+\s*\=\s*(?:"[^"]*"|\'[^\']*\'|#\w+|\$\w+(?:(?:\[(?:[^\[\]]+|(?R))*\])*|(?:\.\w+)*)|[^"\'\s]+?))+)\s*' . $right . '/i', [
  286. 'self',
  287. 'parseSection',
  288. ], $content);
  289. $content = preg_replace('/' . $left . '\/(?:loop|section)\s*' . $right . '/i', '<?php endforeach; endif;?>', $content);
  290. // 还原代码
  291. $content = preg_replace_callback('/' . chr(2) . '(.*?)' . chr(3) . '/', ['self', 'parseDecode'], $content);
  292. // 内容后续处理
  293. /*if (!APP_DEBUG) {
  294. $content = preg_replace_callback('/<style[^>]*>([^<]*)<\/style>/isU', array('self', 'parseCss'), $content);
  295. $content = preg_replace_callback('/<script[^>]*>([^<]+?)<\/script>/isU', array('self', 'parseJs'), $content);
  296. $content = preg_replace(array("/>\s+</"), array('> <'), $content);
  297. $content = preg_replace('/\?>\s*<\?php/', '', $content);
  298. $content = str_replace(array("\r\n", "\r", "\n", "\t", ' ', ' '), ' ', $content);
  299. $content = strip_whitespace($content);
  300. }*/
  301. // 返回内容
  302. return $content;
  303. }
  304. /**
  305. * css压缩
  306. *
  307. * @param $match
  308. * @return string
  309. */
  310. public static function parseCss(string $match)
  311. {
  312. return '<style type = "text/css">' . self::compressCss($match[1]) . '</style>';
  313. }
  314. /**
  315. * js压缩
  316. *
  317. * @param $march
  318. * @return mixed
  319. */
  320. public static function parseJs(string $march)
  321. {
  322. return str_replace($march[1], self::compressJS($march[1]), $march[0]);
  323. }
  324. /**
  325. * 解析变量名
  326. *
  327. * @param $var
  328. * @return array|mixed|string
  329. */
  330. private static function parseVar($var)
  331. {
  332. $var = is_array($var) ? reset($var) : trim($var);
  333. if (substr($var, 0, 1) !== '$') {
  334. $var = '$' . $var;
  335. }
  336. if (preg_match('/^\$\w+(\.[\w\-]+)+$/', $var)) {
  337. if (substr($var, 0, 4) === '$kx.') {
  338. $vars = array_pad(explode('.', $var, 3), 3, '');
  339. switch ($vars[1]) {
  340. case 'server':
  341. $var = '$_SERVER[\'' . strtoupper($vars[2]) . '\']';
  342. break;
  343. case 'const':
  344. $var = strtoupper($vars[2]);
  345. break;
  346. case 'config':
  347. $var = '\Kuxin\Helper\Arr::getValue($_kxcms_config, "' . $vars[2] . '")';
  348. break;
  349. case 'tplconfig':
  350. $var = 'self::getTplConfig("' . $vars[2] . '")';
  351. break;
  352. case 'get':
  353. $var = '$_GET[\'' . $vars[2] . '\']';
  354. break;
  355. case 'post':
  356. $var = '$_POST[\'' . $vars[2] . '\']';
  357. break;
  358. case 'request':
  359. $var = '$_REQUEST[\'' . $vars[2] . '\']';
  360. break;
  361. case 'cookie':
  362. $var = 'Cookie("' . $vars[2] . '")';
  363. break;
  364. case 'ad':
  365. $var = 'self::getAd("' . $vars[2] . '")';
  366. break;
  367. default:
  368. $var = strtoupper($vars[1]);
  369. break;
  370. }
  371. } else {
  372. $var = preg_replace('/\.(\w+)/', '[\'\1\']', strtolower($var));
  373. }
  374. } else {
  375. $var = strtolower($var);
  376. }
  377. return $var;
  378. }
  379. /**
  380. * @param $string
  381. * @param $format
  382. * @return array
  383. * $format中值true则按照变量解析 其他为默认值
  384. */
  385. private static function parseAttribute(string $string, array $format)
  386. {
  387. $attribute = ['_etc' => []];
  388. preg_match_all('/(?:^|\s+)(\w+)\s*\=\s*(?|(")([^"]*)"|(\')([^\']*)\'|(#)(\w+)|(\$)(\w+(?:(?:\[(?:[^\[\]]+|(?R))*\])*|(?:\.\w+)*))|()([^"\'\s]+?))(?=\s+\w+\s*\=|$)/', $string, $match);
  389. foreach ($match[0] as $key => $value) {
  390. $name = strtolower($match[1][$key]);
  391. $value = strtolower(trim($match[3][$key]));
  392. if (isset($format[$name]) && is_bool($format[$name])) {
  393. $attribute[$name] = $format[$name] ? self::parseVar($value) : $value;
  394. } else {
  395. switch ($match[2][$key]) {
  396. case '#':
  397. $value = strtoupper($value);
  398. break;
  399. case '$':
  400. $value = self::parseVar($value);
  401. break;
  402. case '"':
  403. case '\'':
  404. $value = $match[2][$key] . $value . $match[2][$key];
  405. break;
  406. default:
  407. $value = is_numeric($value) ? $value : var_export($value, true);
  408. }
  409. if (isset($format[$name])) {
  410. $attribute[$name] = $value;
  411. } else {
  412. $attribute['_etc'][$name] = $value;
  413. }
  414. }
  415. }
  416. return array_merge($format, $attribute);
  417. }
  418. /**
  419. * 解析变量
  420. *
  421. * @param $matches
  422. * @return string
  423. */
  424. private static function parseVariable($matches)
  425. {
  426. $variable = self::parseVar($matches[1]);
  427. if ($matches[2]) {
  428. preg_match_all('/\s*\|\s*([\w\:]+)(\s*=\s*(?:@|"[^"]*"|\'[^\']*\'|#\w+|\$\w+(?:(?:\[(?:[^\[\]]+|(?R))*\])*|(?:\.\w+)*)|[^\|\:,"\'\s]*?)(?:\s*,\s*(?:@|"[^"]*"|\'[^\']*\'|#\w+|\$\w+(?:(?:\[(?:[^\[\]]+|(?R))*\])*|(?:\.\w+)*)|[^\|\:,"\'\s]*?))*)?(?=\||$)/', $matches[2], $match);
  429. foreach ($match[0] as $key => $value) {
  430. $function = $match[1][$key];
  431. if (strtolower($function) == 'parsetpl') {
  432. return "<?php include \\Kuxin\\View::parseTpl($variable);?>";
  433. } elseif (in_array($function, ['date', 'default'])) {
  434. $function = "\\Kuxin\\View::{$function}";
  435. } elseif (in_array($function, ['truncate'])) {
  436. $function = "\\Kuxin\\Helper\\Str::{$function}";
  437. }
  438. $param = [$variable];
  439. preg_match_all('/(?:=|,)\s*(?|(@)|(")([^"]*)"|(\')([^\']*)\'|(#)(\w+)|(\$)(\w+(?:(?:\[(?:[^\[\]]+|(?R))*\])*|(?:\.\w+)*))|()([^\|\:,"\'\s]*?))(?=,|$)/', $match[2][$key], $mat);
  440. if (array_search('@', $mat[1]) !== false)
  441. $param = [];
  442. foreach ($mat[0] as $k => $v) {
  443. switch ($mat[1][$k]) {
  444. case '@':
  445. $param[] = $variable;
  446. break;
  447. case '#':
  448. $param[] = strtoupper($mat[2][$k]);
  449. break;
  450. case '$':
  451. $param[] = self::parseVar($mat[2][$k]);
  452. break;
  453. case '"':
  454. case '\'':
  455. $param[] = $mat[1][$k] . $mat[2][$k] . $mat[1][$k];
  456. break;
  457. default:
  458. $param[] = is_numeric($mat[2][$k]) ? $mat[2][$k] : var_export($mat[2][$k], true);
  459. }
  460. }
  461. $variable = $function . '(' . implode(',', $param) . ')';
  462. }
  463. }
  464. return "<?php echo $variable;?>";
  465. }
  466. /**
  467. * 解析载入
  468. *
  469. * @param $matches
  470. * @return mixed|string
  471. */
  472. private static function parseInlcude($matches)
  473. {
  474. //20141215 防止写空导致调用死循环
  475. if ($matches['2']) {
  476. $includeFile = self::getTplFilePath($matches['2']);
  477. $truereturn = realpath($includeFile);
  478. if ($truereturn) {
  479. $content = file_get_contents($truereturn);
  480. return self::compile($content);
  481. }
  482. trigger_error("include参数有误,得不到设置的模版,参数[{$matches['2']}],解析模版路径[{$includeFile}]", E_USER_ERROR);
  483. }
  484. return '';
  485. }
  486. /**
  487. * 解析函数
  488. *
  489. * @param $matches
  490. * @return string
  491. */
  492. private static function parseFunction($matches)
  493. {
  494. $operate = $matches[1] === '=' ? 'echo' : '';
  495. $expression = preg_replace_callback('/\$\w+(?:\.\w+)+/', ['self', 'parseVar'], $matches[2]);
  496. return "<?php $operate $expression;?>";
  497. }
  498. /**
  499. * 解析判断
  500. *
  501. * @param $matches
  502. * @return string
  503. */
  504. private static function parseJudgment($matches)
  505. {
  506. $judge = strtolower($matches[1]) === 'if' ? 'if' : 'elseif';
  507. $condition = preg_replace_callback('/\$\w+(?:\.\w+)+/', ['self', 'parseVar'], $matches[2]);
  508. return "<?php $judge($condition):?>";
  509. }
  510. /**
  511. * @param $matches
  512. * @return string
  513. */
  514. private static function parseLink($matches)
  515. {
  516. $attribute = self::parseAttribute('_type_=' . $matches[1], ['_type_' => false, 'responsetype' => '""']);
  517. if (!is_string($attribute['_type_']))
  518. return $matches[0];
  519. $var = [];
  520. foreach ($attribute['_etc'] as $key => $value) {
  521. $var[] = "'$key'=>$value";
  522. }
  523. return "<?php echo \\Kuxin\\Helper\\Url::build(\"{$attribute['_type_']}\",[" . implode(',', $var) . "],{$attribute['responsetype']});?>";
  524. }
  525. /**
  526. * @param $matches
  527. * @return string
  528. */
  529. private static function parseBlock($matches)
  530. {
  531. $attribute = self::parseAttribute($matches[1], ['method' => false, 'name' => false]);
  532. $var = [];
  533. foreach ($attribute['_etc'] as $key => $value) {
  534. $var[] = "'$key'=>$value";
  535. }
  536. if (empty($attribute['name']) || $attribute['name'] === false) {
  537. return "<?php echo \\Kuxin\\Block::show('{$attribute['method']}', [" . implode(',', $var) . "]);?>";
  538. } else {
  539. $name = '$' . $attribute['name'];
  540. return "<?php $name=\\Kuxin\\Block::show('{$attribute['method']}', [" . implode(',', $var) . "]);?>";
  541. }
  542. }
  543. /**
  544. * 解析循环
  545. *
  546. * @param $matches
  547. * @return string
  548. */
  549. private static function parseLoop($matches)
  550. {
  551. $loop = empty($matches[2]) ? '$list' : (self::parseVar($matches[2]));
  552. return "<?php if(is_array($loop)): foreach($loop as \$key =>\$loop):?>";
  553. }
  554. /**
  555. * @param $matches
  556. * @return string
  557. */
  558. private static function parseSection($matches)
  559. {
  560. $attribute = self::parseAttribute($matches[1], [
  561. 'loop' => true,
  562. 'name' => true,
  563. 'item' => true,
  564. 'cols' => '1',
  565. 'skip' => '0',
  566. 'limit' => 'null',
  567. ]);
  568. if (!is_string($attribute['loop']))
  569. return $matches[0];
  570. $name = is_string($attribute['name']) ? $attribute['name'] : '$i';
  571. $list = is_string($attribute['item']) ? $attribute['item'] : '$loop';
  572. return "<?php if(is_array({$attribute['loop']}) && (array()!={$attribute['loop']})): $name=array(); {$name}['loop']=array_slice({$attribute['loop']},{$attribute['skip']},{$attribute['limit']},true); {$name}['total']=count({$attribute['loop']}); {$name}['count']=count({$name}['loop']); {$name}['cols']={$attribute['cols']}; {$name}['add']={$name}['count']%{$attribute['cols']}?{$attribute['cols']}-{$name}['count']%{$attribute['cols']}:0; {$name}['order']=0; {$name}['row']=1;{$name}['col']=0;foreach(array_pad({$name}['loop'],{$name}['add'],array()) as {$name}['index']=>{$name}['list']): $list={$name}['list']; {$name}['order']++; {$name}['col']++; if({$name}['col']=={$attribute['cols']}): {$name}['col']=0; {$name}['row']++; endif; {$name}['first']={$name}['order']==1; {$name}['last']={$name}['order']=={$name}['count']; {$name}['extra']={$name}['order']>{$name}['count'];?>";
  573. }
  574. /**
  575. * 保护代码
  576. *
  577. * @param $matches
  578. * @return string
  579. */
  580. private static function parseEncode($matches)
  581. {
  582. return chr(2) . base64_encode(strtolower($matches[1]) === 'php' ? "<?php {$matches[2]};?>" : trim($matches[2])) . chr(3);
  583. }
  584. /**
  585. * 还原代码
  586. *
  587. * @param $matches
  588. * @return bool|string
  589. */
  590. private static function parseDecode($matches)
  591. {
  592. return base64_decode($matches[1]);
  593. }
  594. /**
  595. * @param $content
  596. * @return string
  597. */
  598. public static function compressJS($content)
  599. {
  600. $lines = explode("\n", $content);
  601. foreach ($lines as &$line) {
  602. $line = trim($line) . "\n";
  603. }
  604. return implode('', $lines);
  605. }
  606. /**
  607. * @param $content
  608. * @return mixed
  609. */
  610. public static function compressCss($content)
  611. {
  612. $content = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $content); //删除注释
  613. $content = preg_replace('![ ]{2,}!', ' ', $content); //删除注释
  614. $content = str_replace(["\r\n", "\r", "\n", "\t"], '', $content); //删除空白
  615. return $content;
  616. }
  617. /**
  618. * 默认值函数
  619. *
  620. * @return string
  621. */
  622. public static function default()
  623. {
  624. $args = func_get_args();
  625. $value = array_shift($args);
  626. if (is_bool($value)) {
  627. $value = intval($value);
  628. }
  629. if (!is_numeric($value)) {
  630. return $value;
  631. } elseif (isset($args[$value])) {
  632. return $args[$value];
  633. } else {
  634. return '';
  635. }
  636. }
  637. /**
  638. * 时间函数优化
  639. *
  640. * @param $time
  641. * @param $format
  642. * @return mixed
  643. */
  644. public static function date($time, $format)
  645. {
  646. if ($time == '0')
  647. return '';
  648. return date($format, $time);
  649. }
  650. /**
  651. * @param string $content
  652. * @return string
  653. */
  654. public static function parseTpl($content)
  655. {
  656. if ($content == '')
  657. return '';
  658. $storage = DI::Storage('template');
  659. $cachefile = 'parsetpl/' . md5($content . '_parseTpl') . '.php';
  660. if (!$storage->exist($cachefile)) {
  661. $content = self::compile($content);
  662. $storage->write($cachefile, $content);
  663. }
  664. return $storage->getPath($cachefile);
  665. }
  666. public static function getTplConfig($key)
  667. {
  668. return Config::get('template.tplconfig')[basename(self::$_path)][$key]['value'] ?? '';
  669. }
  670. public static function getAd($key)
  671. {
  672. return "<script type=\"text/javascript\" src=\"/" . Config::get('ad.path', 'ad') . "/{$key}.js\"></script>";
  673. }
  674. public static function getSuffix()
  675. {
  676. return self::$suffix;
  677. }
  678. public static function setSuffix($suffix)
  679. {
  680. self::$suffix = $suffix;
  681. }
  682. }