| 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 |