| Total Complexity | 217 |
| Total Lines | 1296 |
| Duplicated Lines | 0 % |
| Changes | 0 | ||
Complex classes like Template often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Template, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 21 | class Template |
||
| 22 | { |
||
| 23 | protected $app; |
||
| 24 | /** |
||
| 25 | * 模板变量 |
||
| 26 | * @var array |
||
| 27 | */ |
||
| 28 | protected $data = []; |
||
| 29 | |||
| 30 | /** |
||
| 31 | * 模板配置参数 |
||
| 32 | * @var array |
||
| 33 | */ |
||
| 34 | protected $config = [ |
||
| 35 | 'view_path' => '', // 模板路径 |
||
| 36 | 'view_base' => '', |
||
| 37 | 'view_suffix' => 'html', // 默认模板文件后缀 |
||
| 38 | 'view_depr' => DIRECTORY_SEPARATOR, |
||
| 39 | 'cache_suffix' => 'php', // 默认模板缓存后缀 |
||
| 40 | 'tpl_deny_func_list' => 'echo,exit', // 模板引擎禁用函数 |
||
| 41 | 'tpl_deny_php' => false, // 默认模板引擎是否禁用PHP原生代码 |
||
| 42 | 'tpl_begin' => '{', // 模板引擎普通标签开始标记 |
||
| 43 | 'tpl_end' => '}', // 模板引擎普通标签结束标记 |
||
| 44 | 'strip_space' => false, // 是否去除模板文件里面的html空格与换行 |
||
| 45 | 'tpl_cache' => true, // 是否开启模板编译缓存,设为false则每次都会重新编译 |
||
| 46 | 'compile_type' => 'file', // 模板编译类型 |
||
| 47 | 'cache_prefix' => '', // 模板缓存前缀标识,可以动态改变 |
||
| 48 | 'cache_time' => 0, // 模板缓存有效期 0 为永久,(以数字为值,单位:秒) |
||
| 49 | 'layout_on' => false, // 布局模板开关 |
||
| 50 | 'layout_name' => 'layout', // 布局模板入口文件 |
||
| 51 | 'layout_item' => '{__CONTENT__}', // 布局模板的内容替换标识 |
||
| 52 | 'taglib_begin' => '{', // 标签库标签开始标记 |
||
| 53 | 'taglib_end' => '}', // 标签库标签结束标记 |
||
| 54 | 'taglib_load' => true, // 是否使用内置标签库之外的其它标签库,默认自动检测 |
||
| 55 | 'taglib_build_in' => 'cx', // 内置标签库名称(标签使用不必指定标签库名称),以逗号分隔 注意解析顺序 |
||
| 56 | 'taglib_pre_load' => '', // 需要额外加载的标签库(须指定标签库名称),多个以逗号分隔 |
||
| 57 | 'display_cache' => false, // 模板渲染缓存 |
||
| 58 | 'cache_id' => '', // 模板缓存ID |
||
| 59 | 'tpl_replace_string' => [], |
||
| 60 | 'tpl_var_identify' => 'array', // .语法变量识别,array|object|'', 为空时自动识别 |
||
| 61 | 'default_filter' => 'htmlentities', // 默认过滤方法 用于普通标签输出 |
||
| 62 | ]; |
||
| 63 | |||
| 64 | /** |
||
| 65 | * 保留内容信息 |
||
| 66 | * @var array |
||
| 67 | */ |
||
| 68 | private $literal = []; |
||
| 69 | |||
| 70 | /** |
||
| 71 | * 模板包含信息 |
||
| 72 | * @var array |
||
| 73 | */ |
||
| 74 | private $includeFile = []; |
||
| 75 | |||
| 76 | /** |
||
| 77 | * 模板存储对象 |
||
| 78 | * @var object |
||
| 79 | */ |
||
| 80 | protected $storage; |
||
| 81 | |||
| 82 | /** |
||
| 83 | * 架构函数 |
||
| 84 | * @access public |
||
| 85 | * @param array $config |
||
| 86 | */ |
||
| 87 | public function __construct(App $app, array $config = []) |
||
| 88 | { |
||
| 89 | $this->app = $app; |
||
| 90 | $this->config['cache_path'] = $app->getRuntimePath() . 'temp/'; |
||
| 91 | $this->config = array_merge($this->config, $config); |
||
| 92 | |||
| 93 | $this->config['taglib_begin_origin'] = $this->config['taglib_begin']; |
||
| 94 | $this->config['taglib_end_origin'] = $this->config['taglib_end']; |
||
| 95 | |||
| 96 | $this->config['taglib_begin'] = preg_quote($this->config['taglib_begin'], '/'); |
||
| 97 | $this->config['taglib_end'] = preg_quote($this->config['taglib_end'], '/'); |
||
| 98 | $this->config['tpl_begin'] = preg_quote($this->config['tpl_begin'], '/'); |
||
| 99 | $this->config['tpl_end'] = preg_quote($this->config['tpl_end'], '/'); |
||
| 100 | |||
| 101 | // 初始化模板编译存储器 |
||
| 102 | $type = $this->config['compile_type'] ? $this->config['compile_type'] : 'File'; |
||
| 103 | |||
| 104 | $this->storage = Loader::factory($type, '\\think\\template\\driver\\', null); |
||
| 105 | } |
||
| 106 | |||
| 107 | public static function __make(Config $config) |
||
|
1 ignored issue
–
show
|
|||
| 108 | { |
||
| 109 | return new static($config->pull('template')); |
||
| 110 | } |
||
| 111 | |||
| 112 | /** |
||
| 113 | * 模板变量赋值 |
||
| 114 | * @access public |
||
| 115 | * @param mixed $name |
||
| 116 | * @param mixed $value |
||
| 117 | * @return void |
||
| 118 | */ |
||
| 119 | public function assign($name, $value = '') |
||
| 120 | { |
||
| 121 | if (is_array($name)) { |
||
| 122 | $this->data = array_merge($this->data, $name); |
||
| 123 | } else { |
||
| 124 | $this->data[$name] = $value; |
||
| 125 | } |
||
| 126 | } |
||
| 127 | |||
| 128 | /** |
||
| 129 | * 模板引擎参数赋值 |
||
| 130 | * @access public |
||
| 131 | * @param mixed $name |
||
| 132 | * @param mixed $value |
||
| 133 | */ |
||
| 134 | public function __set($name, $value) |
||
| 135 | { |
||
| 136 | $this->config[$name] = $value; |
||
| 137 | } |
||
| 138 | |||
| 139 | /** |
||
| 140 | * 模板引擎配置项 |
||
| 141 | * @access public |
||
| 142 | * @param array|string $config |
||
| 143 | * @return void|array |
||
| 144 | */ |
||
| 145 | public function config($config) |
||
| 146 | { |
||
| 147 | if (is_array($config)) { |
||
| 148 | $this->config = array_merge($this->config, $config); |
||
| 149 | } elseif (isset($this->config[$config])) { |
||
| 150 | return $this->config[$config]; |
||
| 151 | } |
||
| 152 | } |
||
| 153 | |||
| 154 | /** |
||
| 155 | * 模板变量获取 |
||
| 156 | * @access public |
||
| 157 | * @param string $name 变量名 |
||
| 158 | * @return mixed |
||
| 159 | */ |
||
| 160 | public function get($name = '') |
||
| 161 | { |
||
| 162 | if ('' == $name) { |
||
| 163 | return $this->data; |
||
| 164 | } |
||
| 165 | |||
| 166 | $data = $this->data; |
||
| 167 | |||
| 168 | foreach (explode('.', $name) as $key => $val) { |
||
| 169 | if (isset($data[$val])) { |
||
| 170 | $data = $data[$val]; |
||
| 171 | } else { |
||
| 172 | $data = null; |
||
| 173 | break; |
||
| 174 | } |
||
| 175 | } |
||
| 176 | |||
| 177 | return $data; |
||
| 178 | } |
||
| 179 | |||
| 180 | /** |
||
| 181 | * 渲染模板文件 |
||
| 182 | * @access public |
||
| 183 | * @param string $template 模板文件 |
||
| 184 | * @param array $vars 模板变量 |
||
| 185 | * @param array $config 模板参数 |
||
| 186 | * @return void |
||
| 187 | */ |
||
| 188 | public function fetch($template, $vars = [], $config = []) |
||
| 189 | { |
||
| 190 | if ($vars) { |
||
| 191 | $this->data = $vars; |
||
| 192 | } |
||
| 193 | |||
| 194 | if ($config) { |
||
| 195 | $this->config($config); |
||
| 196 | } |
||
| 197 | |||
| 198 | $cache = $this->app['cache']; |
||
| 199 | |||
| 200 | if (!empty($this->config['cache_id']) && $this->config['display_cache']) { |
||
| 201 | // 读取渲染缓存 |
||
| 202 | $cacheContent = $cache->get($this->config['cache_id']); |
||
| 203 | |||
| 204 | if (false !== $cacheContent) { |
||
| 205 | echo $cacheContent; |
||
| 206 | return; |
||
| 207 | } |
||
| 208 | } |
||
| 209 | |||
| 210 | $template = $this->parseTemplateFile($template); |
||
| 211 | |||
| 212 | if ($template) { |
||
| 213 | $cacheFile = $this->config['cache_path'] . $this->config['cache_prefix'] . md5($this->config['layout_on'] . $this->config['layout_name'] . $template) . '.' . ltrim($this->config['cache_suffix'], '.'); |
||
| 214 | |||
| 215 | if (!$this->checkCache($cacheFile)) { |
||
| 216 | // 缓存无效 重新模板编译 |
||
| 217 | $content = file_get_contents($template); |
||
| 218 | $this->compiler($content, $cacheFile); |
||
| 219 | } |
||
| 220 | |||
| 221 | // 页面缓存 |
||
| 222 | ob_start(); |
||
| 223 | ob_implicit_flush(0); |
||
| 224 | |||
| 225 | // 读取编译存储 |
||
| 226 | $this->storage->read($cacheFile, $this->data); |
||
| 227 | |||
| 228 | // 获取并清空缓存 |
||
| 229 | $content = ob_get_clean(); |
||
| 230 | |||
| 231 | if (!empty($this->config['cache_id']) && $this->config['display_cache']) { |
||
| 232 | // 缓存页面输出 |
||
| 233 | $cache->set($this->config['cache_id'], $content, $this->config['cache_time']); |
||
| 234 | } |
||
| 235 | |||
| 236 | echo $content; |
||
| 237 | } |
||
| 238 | } |
||
| 239 | |||
| 240 | /** |
||
| 241 | * 渲染模板内容 |
||
| 242 | * @access public |
||
| 243 | * @param string $content 模板内容 |
||
| 244 | * @param array $vars 模板变量 |
||
| 245 | * @param array $config 模板参数 |
||
| 246 | * @return void |
||
| 247 | */ |
||
| 248 | public function display($content, $vars = [], $config = []) |
||
| 249 | { |
||
| 250 | if ($vars) { |
||
| 251 | $this->data = $vars; |
||
| 252 | } |
||
| 253 | |||
| 254 | if ($config) { |
||
| 255 | $this->config($config); |
||
| 256 | } |
||
| 257 | |||
| 258 | $cacheFile = $this->config['cache_path'] . $this->config['cache_prefix'] . md5($content) . '.' . ltrim($this->config['cache_suffix'], '.'); |
||
| 259 | |||
| 260 | if (!$this->checkCache($cacheFile)) { |
||
| 261 | // 缓存无效 模板编译 |
||
| 262 | $this->compiler($content, $cacheFile); |
||
| 263 | } |
||
| 264 | |||
| 265 | // 读取编译存储 |
||
| 266 | $this->storage->read($cacheFile, $this->data); |
||
| 267 | } |
||
| 268 | |||
| 269 | /** |
||
| 270 | * 设置布局 |
||
| 271 | * @access public |
||
| 272 | * @param mixed $name 布局模板名称 false 则关闭布局 |
||
| 273 | * @param string $replace 布局模板内容替换标识 |
||
| 274 | * @return object |
||
| 275 | */ |
||
| 276 | public function layout($name, $replace = '') |
||
| 277 | { |
||
| 278 | if (false === $name) { |
||
| 279 | // 关闭布局 |
||
| 280 | $this->config['layout_on'] = false; |
||
| 281 | } else { |
||
| 282 | // 开启布局 |
||
| 283 | $this->config['layout_on'] = true; |
||
| 284 | |||
| 285 | // 名称必须为字符串 |
||
| 286 | if (is_string($name)) { |
||
| 287 | $this->config['layout_name'] = $name; |
||
| 288 | } |
||
| 289 | |||
| 290 | if (!empty($replace)) { |
||
| 291 | $this->config['layout_item'] = $replace; |
||
| 292 | } |
||
| 293 | } |
||
| 294 | |||
| 295 | return $this; |
||
| 296 | } |
||
| 297 | |||
| 298 | /** |
||
| 299 | * 检查编译缓存是否有效 |
||
| 300 | * 如果无效则需要重新编译 |
||
| 301 | * @access private |
||
| 302 | * @param string $cacheFile 缓存文件名 |
||
| 303 | * @return boolean |
||
| 304 | */ |
||
| 305 | private function checkCache($cacheFile) |
||
| 306 | { |
||
| 307 | if (!$this->config['tpl_cache'] || !is_file($cacheFile) || !$handle = @fopen($cacheFile, "r")) { |
||
| 308 | return false; |
||
| 309 | } |
||
| 310 | |||
| 311 | // 读取第一行 |
||
| 312 | preg_match('/\/\*(.+?)\*\//', fgets($handle), $matches); |
||
| 313 | |||
| 314 | if (!isset($matches[1])) { |
||
| 315 | return false; |
||
| 316 | } |
||
| 317 | |||
| 318 | $includeFile = unserialize($matches[1]); |
||
| 319 | |||
| 320 | if (!is_array($includeFile)) { |
||
| 321 | return false; |
||
| 322 | } |
||
| 323 | |||
| 324 | // 检查模板文件是否有更新 |
||
| 325 | foreach ($includeFile as $path => $time) { |
||
| 326 | if (is_file($path) && filemtime($path) > $time) { |
||
| 327 | // 模板文件如果有更新则缓存需要更新 |
||
| 328 | return false; |
||
| 329 | } |
||
| 330 | } |
||
| 331 | |||
| 332 | // 检查编译存储是否有效 |
||
| 333 | return $this->storage->check($cacheFile, $this->config['cache_time']); |
||
| 334 | } |
||
| 335 | |||
| 336 | /** |
||
| 337 | * 检查编译缓存是否存在 |
||
| 338 | * @access public |
||
| 339 | * @param string $cacheId 缓存的id |
||
| 340 | * @return boolean |
||
| 341 | */ |
||
| 342 | public function isCache($cacheId) |
||
| 343 | { |
||
| 344 | if ($cacheId && $this->config['display_cache']) { |
||
| 345 | // 缓存页面输出 |
||
| 346 | return $this->app['cache']->has($cacheId); |
||
| 347 | } |
||
| 348 | |||
| 349 | return false; |
||
| 350 | } |
||
| 351 | |||
| 352 | /** |
||
| 353 | * 编译模板文件内容 |
||
| 354 | * @access private |
||
| 355 | * @param string $content 模板内容 |
||
| 356 | * @param string $cacheFile 缓存文件名 |
||
| 357 | * @return void |
||
| 358 | */ |
||
| 359 | private function compiler(&$content, $cacheFile) |
||
| 360 | { |
||
| 361 | // 判断是否启用布局 |
||
| 362 | if ($this->config['layout_on']) { |
||
| 363 | if (false !== strpos($content, '{__NOLAYOUT__}')) { |
||
| 364 | // 可以单独定义不使用布局 |
||
| 365 | $content = str_replace('{__NOLAYOUT__}', '', $content); |
||
| 366 | } else { |
||
| 367 | // 读取布局模板 |
||
| 368 | $layoutFile = $this->parseTemplateFile($this->config['layout_name']); |
||
| 369 | |||
| 370 | if ($layoutFile) { |
||
| 371 | // 替换布局的主体内容 |
||
| 372 | $content = str_replace($this->config['layout_item'], $content, file_get_contents($layoutFile)); |
||
| 373 | } |
||
| 374 | } |
||
| 375 | } else { |
||
| 376 | $content = str_replace('{__NOLAYOUT__}', '', $content); |
||
| 377 | } |
||
| 378 | |||
| 379 | // 模板解析 |
||
| 380 | $this->parse($content); |
||
| 381 | |||
| 382 | if ($this->config['strip_space']) { |
||
| 383 | /* 去除html空格与换行 */ |
||
| 384 | $find = ['~>\s+<~', '~>(\s+\n|\r)~']; |
||
| 385 | $replace = ['><', '>']; |
||
| 386 | $content = preg_replace($find, $replace, $content); |
||
| 387 | } |
||
| 388 | |||
| 389 | // 优化生成的php代码 |
||
| 390 | $content = preg_replace('/\?>\s*<\?php\s(?!echo\b|\bend)/s', '', $content); |
||
| 391 | |||
| 392 | // 模板过滤输出 |
||
| 393 | $replace = $this->config['tpl_replace_string']; |
||
| 394 | $content = str_replace(array_keys($replace), array_values($replace), $content); |
||
| 395 | |||
| 396 | // 添加安全代码及模板引用记录 |
||
| 397 | $content = '<?php /*' . serialize($this->includeFile) . '*/ ?>' . "\n" . $content; |
||
| 398 | // 编译存储 |
||
| 399 | $this->storage->write($cacheFile, $content); |
||
| 400 | |||
| 401 | $this->includeFile = []; |
||
| 402 | } |
||
| 403 | |||
| 404 | /** |
||
| 405 | * 模板解析入口 |
||
| 406 | * 支持普通标签和TagLib解析 支持自定义标签库 |
||
| 407 | * @access public |
||
| 408 | * @param string $content 要解析的模板内容 |
||
| 409 | * @return void |
||
| 410 | */ |
||
| 411 | public function parse(&$content) |
||
| 412 | { |
||
| 413 | // 内容为空不解析 |
||
| 414 | if (empty($content)) { |
||
| 415 | return; |
||
| 416 | } |
||
| 417 | |||
| 418 | // 替换literal标签内容 |
||
| 419 | $this->parseLiteral($content); |
||
| 420 | |||
| 421 | // 解析继承 |
||
| 422 | $this->parseExtend($content); |
||
| 423 | |||
| 424 | // 解析布局 |
||
| 425 | $this->parseLayout($content); |
||
| 426 | |||
| 427 | // 检查include语法 |
||
| 428 | $this->parseInclude($content); |
||
| 429 | |||
| 430 | // 替换包含文件中literal标签内容 |
||
| 431 | $this->parseLiteral($content); |
||
| 432 | |||
| 433 | // 检查PHP语法 |
||
| 434 | $this->parsePhp($content); |
||
| 435 | |||
| 436 | // 获取需要引入的标签库列表 |
||
| 437 | // 标签库只需要定义一次,允许引入多个一次 |
||
| 438 | // 一般放在文件的最前面 |
||
| 439 | // 格式:<taglib name="html,mytag..." /> |
||
| 440 | // 当TAGLIB_LOAD配置为true时才会进行检测 |
||
| 441 | if ($this->config['taglib_load']) { |
||
| 442 | $tagLibs = $this->getIncludeTagLib($content); |
||
| 443 | |||
| 444 | if (!empty($tagLibs)) { |
||
| 445 | // 对导入的TagLib进行解析 |
||
| 446 | foreach ($tagLibs as $tagLibName) { |
||
| 447 | $this->parseTagLib($tagLibName, $content); |
||
| 448 | } |
||
| 449 | } |
||
| 450 | } |
||
| 451 | |||
| 452 | // 预先加载的标签库 无需在每个模板中使用taglib标签加载 但必须使用标签库XML前缀 |
||
| 453 | if ($this->config['taglib_pre_load']) { |
||
| 454 | $tagLibs = explode(',', $this->config['taglib_pre_load']); |
||
| 455 | |||
| 456 | foreach ($tagLibs as $tag) { |
||
| 457 | $this->parseTagLib($tag, $content); |
||
| 458 | } |
||
| 459 | } |
||
| 460 | |||
| 461 | // 内置标签库 无需使用taglib标签导入就可以使用 并且不需使用标签库XML前缀 |
||
| 462 | $tagLibs = explode(',', $this->config['taglib_build_in']); |
||
| 463 | |||
| 464 | foreach ($tagLibs as $tag) { |
||
| 465 | $this->parseTagLib($tag, $content, true); |
||
| 466 | } |
||
| 467 | |||
| 468 | // 解析普通模板标签 {$tagName} |
||
| 469 | $this->parseTag($content); |
||
| 470 | |||
| 471 | // 还原被替换的Literal标签 |
||
| 472 | $this->parseLiteral($content, true); |
||
| 473 | } |
||
| 474 | |||
| 475 | /** |
||
| 476 | * 检查PHP语法 |
||
| 477 | * @access private |
||
| 478 | * @param string $content 要解析的模板内容 |
||
| 479 | * @return void |
||
| 480 | * @throws \think\Exception |
||
| 481 | */ |
||
| 482 | private function parsePhp(&$content) |
||
| 483 | { |
||
| 484 | // 短标签的情况要将<?标签用echo方式输出 否则无法正常输出xml标识 |
||
| 485 | $content = preg_replace('/(<\?(?!php|=|$))/i', '<?php echo \'\\1\'; ?>' . "\n", $content); |
||
| 486 | |||
| 487 | // PHP语法检查 |
||
| 488 | if ($this->config['tpl_deny_php'] && false !== strpos($content, '<?php')) { |
||
| 489 | throw new Exception('not allow php tag'); |
||
| 490 | } |
||
| 491 | } |
||
| 492 | |||
| 493 | /** |
||
| 494 | * 解析模板中的布局标签 |
||
| 495 | * @access private |
||
| 496 | * @param string $content 要解析的模板内容 |
||
| 497 | * @return void |
||
| 498 | */ |
||
| 499 | private function parseLayout(&$content) |
||
| 500 | { |
||
| 501 | // 读取模板中的布局标签 |
||
| 502 | if (preg_match($this->getRegex('layout'), $content, $matches)) { |
||
| 503 | // 替换Layout标签 |
||
| 504 | $content = str_replace($matches[0], '', $content); |
||
| 505 | // 解析Layout标签 |
||
| 506 | $array = $this->parseAttr($matches[0]); |
||
| 507 | |||
| 508 | if (!$this->config['layout_on'] || $this->config['layout_name'] != $array['name']) { |
||
| 509 | // 读取布局模板 |
||
| 510 | $layoutFile = $this->parseTemplateFile($array['name']); |
||
| 511 | |||
| 512 | if ($layoutFile) { |
||
| 513 | $replace = isset($array['replace']) ? $array['replace'] : $this->config['layout_item']; |
||
| 514 | // 替换布局的主体内容 |
||
| 515 | $content = str_replace($replace, $content, file_get_contents($layoutFile)); |
||
| 516 | } |
||
| 517 | } |
||
| 518 | } else { |
||
| 519 | $content = str_replace('{__NOLAYOUT__}', '', $content); |
||
| 520 | } |
||
| 521 | } |
||
| 522 | |||
| 523 | /** |
||
| 524 | * 解析模板中的include标签 |
||
| 525 | * @access private |
||
| 526 | * @param string $content 要解析的模板内容 |
||
| 527 | * @return void |
||
| 528 | */ |
||
| 529 | private function parseInclude(&$content) |
||
| 530 | { |
||
| 531 | $regex = $this->getRegex('include'); |
||
| 532 | $func = function ($template) use (&$func, &$regex, &$content) { |
||
| 533 | if (preg_match_all($regex, $template, $matches, PREG_SET_ORDER)) { |
||
| 534 | foreach ($matches as $match) { |
||
| 535 | $array = $this->parseAttr($match[0]); |
||
| 536 | $file = $array['file']; |
||
| 537 | unset($array['file']); |
||
| 538 | |||
| 539 | // 分析模板文件名并读取内容 |
||
| 540 | $parseStr = $this->parseTemplateName($file); |
||
| 541 | |||
| 542 | foreach ($array as $k => $v) { |
||
| 543 | // 以$开头字符串转换成模板变量 |
||
| 544 | if (0 === strpos($v, '$')) { |
||
| 545 | $v = $this->get(substr($v, 1)); |
||
| 546 | } |
||
| 547 | |||
| 548 | $parseStr = str_replace('[' . $k . ']', $v, $parseStr); |
||
| 549 | } |
||
| 550 | |||
| 551 | $content = str_replace($match[0], $parseStr, $content); |
||
| 552 | // 再次对包含文件进行模板分析 |
||
| 553 | $func($parseStr); |
||
| 554 | } |
||
| 555 | unset($matches); |
||
| 556 | } |
||
| 557 | }; |
||
| 558 | |||
| 559 | // 替换模板中的include标签 |
||
| 560 | $func($content); |
||
| 561 | } |
||
| 562 | |||
| 563 | /** |
||
| 564 | * 解析模板中的extend标签 |
||
| 565 | * @access private |
||
| 566 | * @param string $content 要解析的模板内容 |
||
| 567 | * @return void |
||
| 568 | */ |
||
| 569 | private function parseExtend(&$content) |
||
| 570 | { |
||
| 571 | $regex = $this->getRegex('extend'); |
||
| 572 | $array = $blocks = $baseBlocks = []; |
||
| 573 | $extend = ''; |
||
| 574 | |||
| 575 | $func = function ($template) use (&$func, &$regex, &$array, &$extend, &$blocks, &$baseBlocks) { |
||
| 576 | if (preg_match($regex, $template, $matches)) { |
||
| 577 | if (!isset($array[$matches['name']])) { |
||
| 578 | $array[$matches['name']] = 1; |
||
| 579 | // 读取继承模板 |
||
| 580 | $extend = $this->parseTemplateName($matches['name']); |
||
| 581 | |||
| 582 | // 递归检查继承 |
||
| 583 | $func($extend); |
||
| 584 | |||
| 585 | // 取得block标签内容 |
||
| 586 | $blocks = array_merge($blocks, $this->parseBlock($template)); |
||
| 587 | |||
| 588 | return; |
||
| 589 | } |
||
| 590 | } else { |
||
| 591 | // 取得顶层模板block标签内容 |
||
| 592 | $baseBlocks = $this->parseBlock($template, true); |
||
| 593 | |||
| 594 | if (empty($extend)) { |
||
| 595 | // 无extend标签但有block标签的情况 |
||
| 596 | $extend = $template; |
||
| 597 | } |
||
| 598 | } |
||
| 599 | }; |
||
| 600 | |||
| 601 | $func($content); |
||
| 602 | |||
| 603 | if (!empty($extend)) { |
||
| 604 | if ($baseBlocks) { |
||
| 605 | $children = []; |
||
| 606 | foreach ($baseBlocks as $name => $val) { |
||
| 607 | $replace = $val['content']; |
||
| 608 | |||
| 609 | if (!empty($children[$name])) { |
||
| 610 | // 如果包含有子block标签 |
||
| 611 | foreach ($children[$name] as $key) { |
||
| 612 | $replace = str_replace($baseBlocks[$key]['begin'] . $baseBlocks[$key]['content'] . $baseBlocks[$key]['end'], $blocks[$key]['content'], $replace); |
||
| 613 | } |
||
| 614 | } |
||
| 615 | |||
| 616 | if (isset($blocks[$name])) { |
||
| 617 | // 带有{__block__}表示与所继承模板的相应标签合并,而不是覆盖 |
||
| 618 | $replace = str_replace(['{__BLOCK__}', '{__block__}'], $replace, $blocks[$name]['content']); |
||
| 619 | |||
| 620 | if (!empty($val['parent'])) { |
||
| 621 | // 如果不是最顶层的block标签 |
||
| 622 | $parent = $val['parent']; |
||
| 623 | |||
| 624 | if (isset($blocks[$parent])) { |
||
| 625 | $blocks[$parent]['content'] = str_replace($blocks[$name]['begin'] . $blocks[$name]['content'] . $blocks[$name]['end'], $replace, $blocks[$parent]['content']); |
||
| 626 | } |
||
| 627 | |||
| 628 | $blocks[$name]['content'] = $replace; |
||
| 629 | $children[$parent][] = $name; |
||
| 630 | |||
| 631 | continue; |
||
| 632 | } |
||
| 633 | } elseif (!empty($val['parent'])) { |
||
| 634 | // 如果子标签没有被继承则用原值 |
||
| 635 | $children[$val['parent']][] = $name; |
||
| 636 | $blocks[$name] = $val; |
||
| 637 | } |
||
| 638 | |||
| 639 | if (!$val['parent']) { |
||
| 640 | // 替换模板中的顶级block标签 |
||
| 641 | $extend = str_replace($val['begin'] . $val['content'] . $val['end'], $replace, $extend); |
||
| 642 | } |
||
| 643 | } |
||
| 644 | } |
||
| 645 | |||
| 646 | $content = $extend; |
||
| 647 | unset($blocks, $baseBlocks); |
||
| 648 | } |
||
| 649 | } |
||
| 650 | |||
| 651 | /** |
||
| 652 | * 替换页面中的literal标签 |
||
| 653 | * @access private |
||
| 654 | * @param string $content 模板内容 |
||
| 655 | * @param boolean $restore 是否为还原 |
||
| 656 | * @return void |
||
| 657 | */ |
||
| 658 | private function parseLiteral(&$content, $restore = false) |
||
| 659 | { |
||
| 660 | $regex = $this->getRegex($restore ? 'restoreliteral' : 'literal'); |
||
| 661 | |||
| 662 | if (preg_match_all($regex, $content, $matches, PREG_SET_ORDER)) { |
||
| 663 | if (!$restore) { |
||
| 664 | $count = count($this->literal); |
||
| 665 | |||
| 666 | // 替换literal标签 |
||
| 667 | foreach ($matches as $match) { |
||
| 668 | $this->literal[] = substr($match[0], strlen($match[1]), -strlen($match[2])); |
||
| 669 | $content = str_replace($match[0], "<!--###literal{$count}###-->", $content); |
||
| 670 | $count++; |
||
| 671 | } |
||
| 672 | } else { |
||
| 673 | // 还原literal标签 |
||
| 674 | foreach ($matches as $match) { |
||
| 675 | $content = str_replace($match[0], $this->literal[$match[1]], $content); |
||
| 676 | } |
||
| 677 | |||
| 678 | // 清空literal记录 |
||
| 679 | $this->literal = []; |
||
| 680 | } |
||
| 681 | |||
| 682 | unset($matches); |
||
| 683 | } |
||
| 684 | } |
||
| 685 | |||
| 686 | /** |
||
| 687 | * 获取模板中的block标签 |
||
| 688 | * @access private |
||
| 689 | * @param string $content 模板内容 |
||
| 690 | * @param boolean $sort 是否排序 |
||
| 691 | * @return array |
||
| 692 | */ |
||
| 693 | private function parseBlock(&$content, $sort = false) |
||
| 694 | { |
||
| 695 | $regex = $this->getRegex('block'); |
||
| 696 | $result = []; |
||
| 697 | |||
| 698 | if (preg_match_all($regex, $content, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { |
||
| 699 | $right = $keys = []; |
||
| 700 | |||
| 701 | foreach ($matches as $match) { |
||
| 702 | if (empty($match['name'][0])) { |
||
| 703 | if (count($right) > 0) { |
||
| 704 | $tag = array_pop($right); |
||
| 705 | $start = $tag['offset'] + strlen($tag['tag']); |
||
| 706 | $length = $match[0][1] - $start; |
||
| 707 | |||
| 708 | $result[$tag['name']] = [ |
||
| 709 | 'begin' => $tag['tag'], |
||
| 710 | 'content' => substr($content, $start, $length), |
||
| 711 | 'end' => $match[0][0], |
||
| 712 | 'parent' => count($right) ? end($right)['name'] : '', |
||
| 713 | ]; |
||
| 714 | |||
| 715 | $keys[$tag['name']] = $match[0][1]; |
||
| 716 | } |
||
| 717 | } else { |
||
| 718 | // 标签头压入栈 |
||
| 719 | $right[] = [ |
||
| 720 | 'name' => $match[2][0], |
||
| 721 | 'offset' => $match[0][1], |
||
| 722 | 'tag' => $match[0][0], |
||
| 723 | ]; |
||
| 724 | } |
||
| 725 | } |
||
| 726 | |||
| 727 | unset($right, $matches); |
||
| 728 | |||
| 729 | if ($sort) { |
||
| 730 | // 按block标签结束符在模板中的位置排序 |
||
| 731 | array_multisort($keys, $result); |
||
| 732 | } |
||
| 733 | } |
||
| 734 | |||
| 735 | return $result; |
||
| 736 | } |
||
| 737 | |||
| 738 | /** |
||
| 739 | * 搜索模板页面中包含的TagLib库 |
||
| 740 | * 并返回列表 |
||
| 741 | * @access private |
||
| 742 | * @param string $content 模板内容 |
||
| 743 | * @return array|null |
||
| 744 | */ |
||
| 745 | private function getIncludeTagLib(&$content) |
||
| 746 | { |
||
| 747 | // 搜索是否有TagLib标签 |
||
| 748 | if (preg_match($this->getRegex('taglib'), $content, $matches)) { |
||
| 749 | // 替换TagLib标签 |
||
| 750 | $content = str_replace($matches[0], '', $content); |
||
| 751 | |||
| 752 | return explode(',', $matches['name']); |
||
| 753 | } |
||
| 754 | } |
||
| 755 | |||
| 756 | /** |
||
| 757 | * TagLib库解析 |
||
| 758 | * @access public |
||
| 759 | * @param string $tagLib 要解析的标签库 |
||
| 760 | * @param string $content 要解析的模板内容 |
||
| 761 | * @param boolean $hide 是否隐藏标签库前缀 |
||
| 762 | * @return void |
||
| 763 | */ |
||
| 764 | public function parseTagLib($tagLib, &$content, $hide = false) |
||
| 765 | { |
||
| 766 | if (false !== strpos($tagLib, '\\')) { |
||
| 767 | // 支持指定标签库的命名空间 |
||
| 768 | $className = $tagLib; |
||
| 769 | $tagLib = substr($tagLib, strrpos($tagLib, '\\') + 1); |
||
| 770 | } else { |
||
| 771 | $className = '\\think\\template\\taglib\\' . ucwords($tagLib); |
||
| 772 | } |
||
| 773 | |||
| 774 | $tLib = new $className($this); |
||
| 775 | |||
| 776 | $tLib->parseTag($content, $hide ? '' : $tagLib); |
||
| 777 | } |
||
| 778 | |||
| 779 | /** |
||
| 780 | * 分析标签属性 |
||
| 781 | * @access public |
||
| 782 | * @param string $str 属性字符串 |
||
| 783 | * @param string $name 不为空时返回指定的属性名 |
||
| 784 | * @return array |
||
| 785 | */ |
||
| 786 | public function parseAttr($str, $name = null) |
||
| 803 | } |
||
| 804 | |||
| 805 | /** |
||
| 806 | * 模板标签解析 |
||
| 807 | * 格式: {TagName:args [|content] } |
||
| 808 | * @access private |
||
| 809 | * @param string $content 要解析的模板内容 |
||
| 810 | * @return void |
||
| 811 | */ |
||
| 812 | private function parseTag(&$content) |
||
| 813 | { |
||
| 814 | $regex = $this->getRegex('tag'); |
||
| 815 | |||
| 816 | if (preg_match_all($regex, $content, $matches, PREG_SET_ORDER)) { |
||
| 817 | foreach ($matches as $match) { |
||
| 818 | $str = stripslashes($match[1]); |
||
| 819 | $flag = substr($str, 0, 1); |
||
| 820 | |||
| 821 | switch ($flag) { |
||
| 822 | case '$': |
||
|
1 ignored issue
–
show
|
|||
| 823 | // 解析模板变量 格式 {$varName} |
||
| 824 | // 是否带有?号 |
||
| 825 | if (false !== $pos = strpos($str, '?')) { |
||
|
1 ignored issue
–
show
|
|||
| 826 | $array = preg_split('/([!=]={1,2}|(?<!-)[><]={0,1})/', substr($str, 0, $pos), 2, PREG_SPLIT_DELIM_CAPTURE); |
||
| 827 | $name = $array[0]; |
||
| 828 | |||
| 829 | $this->parseVar($name); |
||
| 830 | //$this->parseVarFunction($name); |
||
| 831 | |||
| 832 | $str = trim(substr($str, $pos + 1)); |
||
| 833 | $this->parseVar($str); |
||
| 834 | $first = substr($str, 0, 1); |
||
| 835 | |||
| 836 | if (strpos($name, ')')) { |
||
|
1 ignored issue
–
show
|
|||
| 837 | // $name为对象或是自动识别,或者含有函数 |
||
| 838 | if (isset($array[1])) { |
||
|
1 ignored issue
–
show
|
|||
| 839 | $this->parseVar($array[2]); |
||
| 840 | $name .= $array[1] . $array[2]; |
||
| 841 | } |
||
|
1 ignored issue
–
show
|
|||
| 842 | |||
| 843 | switch ($first) { |
||
| 844 | case '?': |
||
|
1 ignored issue
–
show
|
|||
| 845 | $this->parseVarFunction($name); |
||
| 846 | $str = '<?php echo (' . $name . ') ? ' . $name . ' : ' . substr($str, 1) . '; ?>'; |
||
| 847 | break; |
||
| 848 | case '=': |
||
|
1 ignored issue
–
show
|
|||
| 849 | $str = '<?php if(' . $name . ') echo ' . substr($str, 1) . '; ?>'; |
||
| 850 | break; |
||
| 851 | default: |
||
|
1 ignored issue
–
show
|
|||
| 852 | $str = '<?php echo ' . $name . '?' . $str . '; ?>'; |
||
| 853 | } |
||
|
1 ignored issue
–
show
|
|||
| 854 | } else { |
||
|
1 ignored issue
–
show
|
|||
| 855 | if (isset($array[1])) { |
||
|
1 ignored issue
–
show
|
|||
| 856 | $express = true; |
||
| 857 | $this->parseVar($array[2]); |
||
| 858 | $express = $name . $array[1] . $array[2]; |
||
| 859 | } else { |
||
|
1 ignored issue
–
show
|
|||
| 860 | $express = false; |
||
| 861 | } |
||
|
1 ignored issue
–
show
|
|||
| 862 | |||
| 863 | if (in_array($first, ['?', '=', ':'])) { |
||
|
1 ignored issue
–
show
|
|||
| 864 | $str = trim(substr($str, 1)); |
||
| 865 | if ('$' == substr($str, 0, 1)) { |
||
|
1 ignored issue
–
show
|
|||
| 866 | $str = $this->parseVarFunction($str); |
||
| 867 | } |
||
|
1 ignored issue
–
show
|
|||
| 868 | } |
||
|
1 ignored issue
–
show
|
|||
| 869 | |||
| 870 | // $name为数组 |
||
| 871 | switch ($first) { |
||
| 872 | case '?': |
||
|
1 ignored issue
–
show
|
|||
| 873 | // {$varname??'xxx'} $varname有定义则输出$varname,否则输出xxx |
||
| 874 | $str = '<?php echo ' . ($express ?: 'isset(' . $name . ')') . ' ? ' . $this->parseVarFunction($name) . ' : ' . $str . '; ?>'; |
||
| 875 | break; |
||
| 876 | case '=': |
||
|
1 ignored issue
–
show
|
|||
| 877 | // {$varname?='xxx'} $varname为真时才输出xxx |
||
| 878 | $str = '<?php if(' . ($express ?: '!empty(' . $name . ')') . ') echo ' . $str . '; ?>'; |
||
| 879 | break; |
||
| 880 | case ':': |
||
|
1 ignored issue
–
show
|
|||
| 881 | // {$varname?:'xxx'} $varname为真时输出$varname,否则输出xxx |
||
| 882 | $str = '<?php echo ' . ($express ?: '!empty(' . $name . ')') . ' ? ' . $this->parseVarFunction($name) . ' : ' . $str . '; ?>'; |
||
| 883 | break; |
||
| 884 | default: |
||
|
1 ignored issue
–
show
|
|||
| 885 | if (strpos($str, ':')) { |
||
|
1 ignored issue
–
show
|
|||
| 886 | // {$varname ? 'a' : 'b'} $varname为真时输出a,否则输出b |
||
| 887 | $array = explode(':', $str, 2); |
||
| 888 | |||
| 889 | $array[0] = '$' == substr(trim($array[0]), 0, 1) ? $this->parseVarFunction($array[0]) : $array[0]; |
||
| 890 | $array[1] = '$' == substr(trim($array[1]), 0, 1) ? $this->parseVarFunction($array[1]) : $array[1]; |
||
| 891 | |||
| 892 | $str = implode(' : ', $array); |
||
| 893 | } |
||
|
1 ignored issue
–
show
|
|||
| 894 | $str = '<?php echo ' . ($express ?: '!empty(' . $name . ')') . ' ? ' . $str . '; ?>'; |
||
| 895 | } |
||
|
1 ignored issue
–
show
|
|||
| 896 | } |
||
|
1 ignored issue
–
show
|
|||
| 897 | } else { |
||
|
1 ignored issue
–
show
|
|||
| 898 | $this->parseVar($str); |
||
| 899 | $this->parseVarFunction($str); |
||
| 900 | $str = '<?php echo ' . $str . '; ?>'; |
||
| 901 | } |
||
|
1 ignored issue
–
show
|
|||
| 902 | break; |
||
| 903 | case ':': |
||
|
1 ignored issue
–
show
|
|||
| 904 | // 输出某个函数的结果 |
||
| 905 | $str = substr($str, 1); |
||
| 906 | $this->parseVar($str); |
||
| 907 | $str = '<?php echo ' . $str . '; ?>'; |
||
| 908 | break; |
||
| 909 | case '~': |
||
|
1 ignored issue
–
show
|
|||
| 910 | // 执行某个函数 |
||
| 911 | $str = substr($str, 1); |
||
| 912 | $this->parseVar($str); |
||
| 913 | $str = '<?php ' . $str . '; ?>'; |
||
| 914 | break; |
||
| 915 | case '-': |
||
|
1 ignored issue
–
show
|
|||
| 916 | case '+': |
||
|
1 ignored issue
–
show
|
|||
| 917 | // 输出计算 |
||
| 918 | $this->parseVar($str); |
||
| 919 | $str = '<?php echo ' . $str . '; ?>'; |
||
| 920 | break; |
||
| 921 | case '/': |
||
|
1 ignored issue
–
show
|
|||
| 922 | // 注释标签 |
||
| 923 | $flag2 = substr($str, 1, 1); |
||
| 924 | if ('/' == $flag2 || ('*' == $flag2 && substr(rtrim($str), -2) == '*/')) { |
||
|
1 ignored issue
–
show
|
|||
| 925 | $str = ''; |
||
| 926 | } |
||
|
1 ignored issue
–
show
|
|||
| 927 | break; |
||
| 928 | default: |
||
|
1 ignored issue
–
show
|
|||
| 929 | // 未识别的标签直接返回 |
||
| 930 | $str = $this->config['tpl_begin'] . $str . $this->config['tpl_end']; |
||
| 931 | break; |
||
| 932 | } |
||
| 933 | |||
| 934 | $content = str_replace($match[0], $str, $content); |
||
| 935 | } |
||
| 936 | |||
| 937 | unset($matches); |
||
| 938 | } |
||
| 939 | } |
||
| 940 | |||
| 941 | /** |
||
| 942 | * 模板变量解析,支持使用函数 |
||
| 943 | * 格式: {$varname|function1|function2=arg1,arg2} |
||
| 944 | * @access public |
||
| 945 | * @param string $varStr 变量数据 |
||
| 946 | * @return void |
||
| 947 | */ |
||
| 948 | public function parseVar(&$varStr) |
||
| 949 | { |
||
| 950 | $varStr = trim($varStr); |
||
| 951 | |||
| 952 | if (preg_match_all('/\$[a-zA-Z_](?>\w*)(?:[:\.][0-9a-zA-Z_](?>\w*))+/', $varStr, $matches, PREG_OFFSET_CAPTURE)) { |
||
| 953 | static $_varParseList = []; |
||
| 954 | |||
| 955 | while ($matches[0]) { |
||
| 956 | $match = array_pop($matches[0]); |
||
| 957 | |||
| 958 | //如果已经解析过该变量字串,则直接返回变量值 |
||
| 959 | if (isset($_varParseList[$match[0]])) { |
||
| 960 | $parseStr = $_varParseList[$match[0]]; |
||
| 961 | } else { |
||
| 962 | if (strpos($match[0], '.')) { |
||
| 963 | $vars = explode('.', $match[0]); |
||
| 964 | $first = array_shift($vars); |
||
| 965 | |||
| 966 | if ('$Think' == $first) { |
||
| 967 | // 所有以Think.打头的以特殊变量对待 无需模板赋值就可以输出 |
||
| 968 | $parseStr = $this->parseThinkVar($vars); |
||
| 969 | } elseif ('$Request' == $first) { |
||
| 970 | // 获取Request请求对象参数 |
||
| 971 | $method = array_shift($vars); |
||
| 972 | if (!empty($vars)) { |
||
| 973 | $params = implode('.', $vars); |
||
| 974 | if ('true' != $params) { |
||
| 975 | $params = '\'' . $params . '\''; |
||
| 976 | } |
||
| 977 | } else { |
||
| 978 | $params = ''; |
||
| 979 | } |
||
| 980 | |||
| 981 | $parseStr = 'app(\'request\')->' . $method . '(' . $params . ')'; |
||
| 982 | } else { |
||
| 983 | switch ($this->config['tpl_var_identify']) { |
||
| 984 | case 'array': // 识别为数组 |
||
|
1 ignored issue
–
show
|
|||
| 985 | $parseStr = $first . '[\'' . implode('\'][\'', $vars) . '\']'; |
||
| 986 | break; |
||
| 987 | case 'obj': // 识别为对象 |
||
|
1 ignored issue
–
show
|
|||
| 988 | $parseStr = $first . '->' . implode('->', $vars); |
||
| 989 | break; |
||
| 990 | default: // 自动判断数组或对象 |
||
|
1 ignored issue
–
show
|
|||
| 991 | $parseStr = '(is_array(' . $first . ')?' . $first . '[\'' . implode('\'][\'', $vars) . '\']:' . $first . '->' . implode('->', $vars) . ')'; |
||
| 992 | } |
||
| 993 | } |
||
| 994 | } else { |
||
| 995 | $parseStr = str_replace(':', '->', $match[0]); |
||
| 996 | } |
||
| 997 | |||
| 998 | $_varParseList[$match[0]] = $parseStr; |
||
| 999 | } |
||
| 1000 | |||
| 1001 | $varStr = substr_replace($varStr, $parseStr, $match[1], strlen($match[0])); |
||
| 1002 | } |
||
| 1003 | unset($matches); |
||
| 1004 | } |
||
| 1005 | } |
||
| 1006 | |||
| 1007 | /** |
||
| 1008 | * 对模板中使用了函数的变量进行解析 |
||
| 1009 | * 格式 {$varname|function1|function2=arg1,arg2} |
||
| 1010 | * @access public |
||
| 1011 | * @param string $varStr 变量字符串 |
||
| 1012 | * @param bool $autoescape 自动转义 |
||
| 1013 | * @return void |
||
| 1014 | */ |
||
| 1015 | public function parseVarFunction(&$varStr, $autoescape = true) |
||
| 1016 | { |
||
| 1017 | if (!$autoescape && false === strpos($varStr, '|')) { |
||
| 1018 | return $varStr; |
||
| 1019 | } elseif ($autoescape && !preg_match('/\|(\s)?raw(\||\s)?/i', $varStr)) { |
||
| 1020 | $varStr .= '|' . $this->config['default_filter']; |
||
| 1021 | } |
||
| 1022 | |||
| 1023 | static $_varFunctionList = []; |
||
| 1024 | |||
| 1025 | $_key = md5($varStr); |
||
| 1026 | |||
| 1027 | //如果已经解析过该变量字串,则直接返回变量值 |
||
| 1028 | if (isset($_varFunctionList[$_key])) { |
||
| 1029 | $varStr = $_varFunctionList[$_key]; |
||
| 1030 | } else { |
||
| 1031 | $varArray = explode('|', $varStr); |
||
| 1032 | |||
| 1033 | // 取得变量名称 |
||
| 1034 | $name = trim(array_shift($varArray)); |
||
| 1035 | |||
| 1036 | // 对变量使用函数 |
||
| 1037 | $length = count($varArray); |
||
| 1038 | |||
| 1039 | // 取得模板禁止使用函数列表 |
||
| 1040 | $template_deny_funs = explode(',', $this->config['tpl_deny_func_list']); |
||
| 1041 | |||
| 1042 | for ($i = 0; $i < $length; $i++) { |
||
| 1043 | $args = explode('=', $varArray[$i], 2); |
||
| 1044 | |||
| 1045 | // 模板函数过滤 |
||
| 1046 | $fun = trim($args[0]); |
||
| 1047 | if (in_array($fun, $template_deny_funs)) { |
||
| 1048 | continue; |
||
| 1049 | } |
||
| 1050 | |||
| 1051 | switch (strtolower($fun)) { |
||
| 1052 | case 'raw': |
||
|
1 ignored issue
–
show
|
|||
| 1053 | break; |
||
| 1054 | case 'date': |
||
|
1 ignored issue
–
show
|
|||
| 1055 | $name = 'date(' . $args[1] . ',!is_numeric(' . $name . ')? strtotime(' . $name . ') : ' . $name . ')'; |
||
| 1056 | break; |
||
| 1057 | case 'first': |
||
|
1 ignored issue
–
show
|
|||
| 1058 | $name = 'current(' . $name . ')'; |
||
| 1059 | break; |
||
| 1060 | case 'last': |
||
|
1 ignored issue
–
show
|
|||
| 1061 | $name = 'end(' . $name . ')'; |
||
| 1062 | break; |
||
| 1063 | case 'upper': |
||
|
1 ignored issue
–
show
|
|||
| 1064 | $name = 'strtoupper(' . $name . ')'; |
||
| 1065 | break; |
||
| 1066 | case 'lower': |
||
|
1 ignored issue
–
show
|
|||
| 1067 | $name = 'strtolower(' . $name . ')'; |
||
| 1068 | break; |
||
| 1069 | case 'format': |
||
|
1 ignored issue
–
show
|
|||
| 1070 | $name = 'sprintf(' . $args[1] . ',' . $name . ')'; |
||
| 1071 | break; |
||
| 1072 | case 'default': // 特殊模板函数 |
||
|
1 ignored issue
–
show
|
|||
| 1073 | if (false === strpos($name, '(')) { |
||
|
1 ignored issue
–
show
|
|||
| 1074 | $name = '(isset(' . $name . ') && (' . $name . ' !== \'\')?' . $name . ':' . $args[1] . ')'; |
||
| 1075 | } else { |
||
|
1 ignored issue
–
show
|
|||
| 1076 | $name = '(' . $name . ' ?: ' . $args[1] . ')'; |
||
| 1077 | } |
||
|
1 ignored issue
–
show
|
|||
| 1078 | break; |
||
| 1079 | default: // 通用模板函数 |
||
|
1 ignored issue
–
show
|
|||
| 1080 | if (isset($args[1])) { |
||
|
1 ignored issue
–
show
|
|||
| 1081 | if (strstr($args[1], '###')) { |
||
|
1 ignored issue
–
show
|
|||
| 1082 | $args[1] = str_replace('###', $name, $args[1]); |
||
| 1083 | $name = "$fun($args[1])"; |
||
| 1084 | } else { |
||
|
1 ignored issue
–
show
|
|||
| 1085 | $name = "$fun($name,$args[1])"; |
||
| 1086 | } |
||
|
1 ignored issue
–
show
|
|||
| 1087 | } else { |
||
|
1 ignored issue
–
show
|
|||
| 1088 | if (!empty($args[0])) { |
||
|
1 ignored issue
–
show
|
|||
| 1089 | $name = "$fun($name)"; |
||
| 1090 | } |
||
|
1 ignored issue
–
show
|
|||
| 1091 | } |
||
|
1 ignored issue
–
show
|
|||
| 1092 | } |
||
| 1093 | } |
||
| 1094 | |||
| 1095 | $_varFunctionList[$_key] = $name; |
||
| 1096 | $varStr = $name; |
||
| 1097 | } |
||
| 1098 | return $varStr; |
||
| 1099 | } |
||
| 1100 | |||
| 1101 | /** |
||
| 1102 | * 特殊模板变量解析 |
||
| 1103 | * 格式 以 $Think. 打头的变量属于特殊模板变量 |
||
| 1104 | * @access public |
||
| 1105 | * @param array $vars 变量数组 |
||
| 1106 | * @return string |
||
| 1107 | */ |
||
| 1108 | public function parseThinkVar($vars) |
||
| 1109 | { |
||
| 1110 | $type = strtoupper(trim(array_shift($vars))); |
||
| 1111 | $param = implode('.', $vars); |
||
| 1112 | |||
| 1113 | if ($vars) { |
||
| 1114 | switch ($type) { |
||
| 1115 | case 'SERVER': |
||
|
1 ignored issue
–
show
|
|||
| 1116 | $parseStr = 'app(\'request\')->server(\'' . $param . '\')'; |
||
| 1117 | break; |
||
| 1118 | case 'GET': |
||
|
1 ignored issue
–
show
|
|||
| 1119 | $parseStr = 'app(\'request\')->get(\'' . $param . '\')'; |
||
| 1120 | break; |
||
| 1121 | case 'POST': |
||
|
1 ignored issue
–
show
|
|||
| 1122 | $parseStr = 'app(\'request\')->post(\'' . $param . '\')'; |
||
| 1123 | break; |
||
| 1124 | case 'COOKIE': |
||
|
1 ignored issue
–
show
|
|||
| 1125 | $parseStr = 'app(\'cookie\')->get(\'' . $param . '\')'; |
||
| 1126 | break; |
||
| 1127 | case 'SESSION': |
||
|
1 ignored issue
–
show
|
|||
| 1128 | $parseStr = 'app(\'session\')->get(\'' . $param . '\')'; |
||
| 1129 | break; |
||
| 1130 | case 'ENV': |
||
|
1 ignored issue
–
show
|
|||
| 1131 | $parseStr = 'app(\'request\')->env(\'' . $param . '\')'; |
||
| 1132 | break; |
||
| 1133 | case 'REQUEST': |
||
|
1 ignored issue
–
show
|
|||
| 1134 | $parseStr = 'app(\'request\')->request(\'' . $param . '\')'; |
||
| 1135 | break; |
||
| 1136 | case 'CONST': |
||
|
1 ignored issue
–
show
|
|||
| 1137 | $parseStr = strtoupper($param); |
||
| 1138 | break; |
||
| 1139 | case 'LANG': |
||
|
1 ignored issue
–
show
|
|||
| 1140 | $parseStr = 'app(\'lang\')->get(\'' . $param . '\')'; |
||
| 1141 | break; |
||
| 1142 | case 'CONFIG': |
||
|
1 ignored issue
–
show
|
|||
| 1143 | $parseStr = 'app(\'config\')->get(\'' . $param . '\')'; |
||
| 1144 | break; |
||
| 1145 | default: |
||
|
1 ignored issue
–
show
|
|||
| 1146 | $parseStr = '\'\''; |
||
| 1147 | break; |
||
| 1148 | } |
||
| 1149 | } else { |
||
| 1150 | switch ($type) { |
||
| 1151 | case 'NOW': |
||
|
1 ignored issue
–
show
|
|||
| 1152 | $parseStr = "date('Y-m-d g:i a',time())"; |
||
| 1153 | break; |
||
| 1154 | case 'VERSION': |
||
|
1 ignored issue
–
show
|
|||
| 1155 | $parseStr = 'app()->version()'; |
||
| 1156 | break; |
||
| 1157 | case 'LDELIM': |
||
|
1 ignored issue
–
show
|
|||
| 1158 | $parseStr = '\'' . ltrim($this->config['tpl_begin'], '\\') . '\''; |
||
| 1159 | break; |
||
| 1160 | case 'RDELIM': |
||
|
1 ignored issue
–
show
|
|||
| 1161 | $parseStr = '\'' . ltrim($this->config['tpl_end'], '\\') . '\''; |
||
| 1162 | break; |
||
| 1163 | default: |
||
|
1 ignored issue
–
show
|
|||
| 1164 | if (defined($type)) { |
||
|
1 ignored issue
–
show
|
|||
| 1165 | $parseStr = $type; |
||
| 1166 | } else { |
||
|
1 ignored issue
–
show
|
|||
| 1167 | $parseStr = ''; |
||
| 1168 | } |
||
|
1 ignored issue
–
show
|
|||
| 1169 | } |
||
| 1170 | } |
||
| 1171 | |||
| 1172 | return $parseStr; |
||
| 1173 | } |
||
| 1174 | |||
| 1175 | /** |
||
| 1176 | * 分析加载的模板文件并读取内容 支持多个模板文件读取 |
||
| 1177 | * @access private |
||
| 1178 | * @param string $templateName 模板文件名 |
||
| 1179 | * @return string |
||
| 1180 | */ |
||
| 1181 | private function parseTemplateName($templateName) |
||
| 1182 | { |
||
| 1183 | $array = explode(',', $templateName); |
||
| 1184 | $parseStr = ''; |
||
| 1185 | |||
| 1186 | foreach ($array as $templateName) { |
||
| 1187 | if (empty($templateName)) { |
||
| 1188 | continue; |
||
| 1189 | } |
||
| 1190 | |||
| 1191 | if (0 === strpos($templateName, '$')) { |
||
| 1192 | //支持加载变量文件名 |
||
| 1193 | $templateName = $this->get(substr($templateName, 1)); |
||
| 1194 | } |
||
| 1195 | |||
| 1196 | $template = $this->parseTemplateFile($templateName); |
||
| 1197 | |||
| 1198 | if ($template) { |
||
| 1199 | // 获取模板文件内容 |
||
| 1200 | $parseStr .= file_get_contents($template); |
||
| 1201 | } |
||
| 1202 | } |
||
| 1203 | |||
| 1204 | return $parseStr; |
||
| 1205 | } |
||
| 1206 | |||
| 1207 | /** |
||
| 1208 | * 解析模板文件名 |
||
| 1209 | * @access private |
||
| 1210 | * @param string $template 文件名 |
||
| 1211 | * @return string|false |
||
| 1212 | */ |
||
| 1213 | private function parseTemplateFile($template) |
||
| 1244 | } |
||
| 1245 | |||
| 1246 | /** |
||
| 1247 | * 按标签生成正则 |
||
| 1248 | * @access private |
||
| 1249 | * @param string $tagName 标签名 |
||
| 1250 | * @return string |
||
| 1251 | */ |
||
| 1252 | private function getRegex($tagName) |
||
| 1309 | } |
||
| 1310 | |||
| 1311 | public function __debugInfo() |
||
| 1317 | } |
||
| 1318 | } |
||
| 1319 |