View.class.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. namespace Think;
  12. /**
  13. * ThinkPHP 视图类
  14. */
  15. class View
  16. {
  17. /**
  18. * 模板输出变量
  19. * @var tVar
  20. * @access protected
  21. */
  22. protected $tVar = array();
  23. /**
  24. * 模板主题
  25. * @var theme
  26. * @access protected
  27. */
  28. protected $theme = '';
  29. /**
  30. * 模板变量赋值
  31. * @access public
  32. * @param mixed $name
  33. * @param mixed $value
  34. */
  35. public function assign($name, $value = '')
  36. {
  37. if (is_array($name)) {
  38. $this->tVar = array_merge($this->tVar, $name);
  39. } else {
  40. $this->tVar[$name] = $value;
  41. }
  42. }
  43. /**
  44. * 取得模板变量的值
  45. * @access public
  46. * @param string $name
  47. * @return mixed
  48. */
  49. public function get($name = '')
  50. {
  51. if ('' === $name) {
  52. return $this->tVar;
  53. }
  54. return isset($this->tVar[$name]) ? $this->tVar[$name] : false;
  55. }
  56. /**
  57. * 加载模板和页面输出 可以返回输出内容
  58. * @access public
  59. * @param string $templateFile 模板文件名
  60. * @param string $charset 模板输出字符集
  61. * @param string $contentType 输出类型
  62. * @param string $content 模板输出内容
  63. * @param string $prefix 模板缓存前缀
  64. * @return mixed
  65. */
  66. public function display($templateFile = '', $charset = '', $contentType = '', $content = '', $prefix = '')
  67. {
  68. G('viewStartTime');
  69. // 解析并获取模板内容
  70. $content = $this->fetch($templateFile, $content, $prefix);
  71. // 输出模板内容
  72. $this->render($content, $charset, $contentType);
  73. }
  74. /**
  75. * 输出内容文本可以包括Html
  76. * @access private
  77. * @param string $content 输出内容
  78. * @param string $charset 模板输出字符集
  79. * @param string $contentType 输出类型
  80. * @return mixed
  81. */
  82. private function render($content, $charset = '', $contentType = '')
  83. {
  84. if (empty($charset)) {
  85. $charset = C('DEFAULT_CHARSET');
  86. }
  87. if (empty($contentType)) {
  88. $contentType = C('TMPL_CONTENT_TYPE');
  89. }
  90. // 网页字符编码
  91. header('Content-Type:' . $contentType . '; charset=' . $charset);
  92. header('Cache-control: ' . C('HTTP_CACHE_CONTROL')); // 页面缓存控制
  93. header('X-Powered-By:OpenCMF');
  94. // 输出模板文件
  95. echo $content;
  96. }
  97. /**
  98. * 解析和获取模板内容 用于输出
  99. * @access public
  100. * @param string $templateFile 模板文件名
  101. * @param string $content 模板输出内容
  102. * @param string $prefix 模板缓存前缀
  103. * @return string
  104. */
  105. public function fetch($templateFile = '', $content = '', $prefix = '')
  106. {
  107. if (empty($content)) {
  108. $templateFile = $this->parseTemplate($templateFile);
  109. // 模板文件不存在直接返回
  110. if (!is_file($templateFile)) {
  111. E(L('_TEMPLATE_NOT_EXIST_') . ':' . $templateFile);
  112. }
  113. } else {
  114. defined('THEME_PATH') or define('THEME_PATH', $this->getThemePath());
  115. }
  116. // 页面缓存
  117. ob_start();
  118. ob_implicit_flush(0);
  119. if ('php' == strtolower(C('TMPL_ENGINE_TYPE'))) {
  120. // 使用PHP原生模板
  121. $_content = $content;
  122. // 模板阵列变量分解成为独立变量
  123. extract($this->tVar, EXTR_OVERWRITE);
  124. // 直接载入PHP模板
  125. empty($_content) ? include $templateFile : eval('?>' . $_content);
  126. } else {
  127. // 视图解析标签
  128. $params = array('var' => $this->tVar, 'file' => $templateFile, 'content' => $content, 'prefix' => $prefix);
  129. $_content = !empty($content) ?: $templateFile;
  130. if ((!empty($content) && $this->checkContentCache($content, $prefix)) || $this->checkCache($templateFile, $prefix)) {
  131. // 缓存有效
  132. //载入模版缓存文件
  133. Storage::load(C('CACHE_PATH') . $prefix . md5($_content) . C('TMPL_CACHFILE_SUFFIX'), $this->tVar);
  134. } else {
  135. $tpl = Think::instance('Think\\Template');
  136. // 编译并加载模板文件
  137. $tpl->fetch($_content, $this->tVar, $prefix);
  138. }
  139. }
  140. // 获取并清空缓存
  141. $content = ob_get_clean();
  142. // 内容过滤标签
  143. // 系统默认的特殊变量替换
  144. $replace = array(
  145. '__ROOT__' => __ROOT__, // 当前网站地址
  146. '__APP__' => __APP__, // 当前应用地址
  147. '__MODULE__' => __MODULE__,
  148. '__ACTION__' => __ACTION__, // 当前操作地址
  149. '__SELF__' => __SELF__, // 当前页面地址
  150. '__CONTROLLER__' => __CONTROLLER__,
  151. '__URL__' => __CONTROLLER__,
  152. '__PUBLIC__' => __ROOT__ . '/Public', // 站点公共目录
  153. );
  154. // 允许用户自定义模板的字符串替换
  155. if (is_array(C('TMPL_PARSE_STRING'))) {
  156. $replace = array_merge($replace, C('TMPL_PARSE_STRING'));
  157. }
  158. $content = str_replace(array_keys($replace), array_values($replace), $content);
  159. // 输出模板文件
  160. return $content;
  161. }
  162. /**
  163. * 检查缓存文件是否有效
  164. * 如果无效则需要重新编译
  165. * @access public
  166. * @param string $tmplTemplateFile 模板文件名
  167. * @return boolean
  168. */
  169. protected function checkCache($tmplTemplateFile, $prefix = '')
  170. {
  171. if (!C('TMPL_CACHE_ON')) // 优先对配置设定检测
  172. {
  173. return false;
  174. }
  175. $tmplCacheFile = C('CACHE_PATH') . $prefix . md5($tmplTemplateFile) . C('TMPL_CACHFILE_SUFFIX');
  176. if (!Storage::has($tmplCacheFile)) {
  177. return false;
  178. } elseif (filemtime($tmplTemplateFile) > Storage::get($tmplCacheFile, 'mtime')) {
  179. // 模板文件如果有更新则缓存需要更新
  180. return false;
  181. } elseif (C('TMPL_CACHE_TIME') != 0 && time() > Storage::get($tmplCacheFile, 'mtime') + C('TMPL_CACHE_TIME')) {
  182. // 缓存是否在有效期
  183. return false;
  184. }
  185. // 开启布局模板
  186. if (C('LAYOUT_ON')) {
  187. $layoutFile = THEME_PATH . C('LAYOUT_NAME') . C('TMPL_TEMPLATE_SUFFIX');
  188. if (filemtime($layoutFile) > Storage::get($tmplCacheFile, 'mtime')) {
  189. return false;
  190. }
  191. }
  192. // 缓存有效
  193. return true;
  194. }
  195. /**
  196. * 检查缓存内容是否有效
  197. * 如果无效则需要重新编译
  198. * @access public
  199. * @param string $tmplContent 模板内容
  200. * @return boolean
  201. */
  202. protected function checkContentCache($tmplContent, $prefix = '')
  203. {
  204. if (Storage::has(C('CACHE_PATH') . $prefix . md5($tmplContent) . C('TMPL_CACHFILE_SUFFIX'))) {
  205. return true;
  206. } else {
  207. return false;
  208. }
  209. }
  210. /**
  211. * 自动定位模板文件
  212. * @access protected
  213. * @param string $template 模板文件规则
  214. * @return string
  215. */
  216. public function parseTemplate($template = '')
  217. {
  218. if (is_file($template)) {
  219. return $template;
  220. }
  221. $depr = C('TMPL_FILE_DEPR');
  222. $template = str_replace(':', $depr, $template);
  223. // 获取当前模块
  224. $module = MODULE_NAME;
  225. if (strpos($template, '@')) {
  226. // 跨模块调用模版文件
  227. list($module, $template) = explode('@', $template);
  228. }
  229. // 获取当前主题的模版路径
  230. defined('THEME_PATH') or define('THEME_PATH', $this->getThemePath($module));
  231. // 分析模板文件规则
  232. if ('' == $template) {
  233. // 如果模板文件名为空 按照默认规则定位
  234. $template = CONTROLLER_NAME . $depr . ACTION_NAME;
  235. } elseif (false === strpos($template, $depr)) {
  236. $template = CONTROLLER_NAME . $depr . $template;
  237. }
  238. $file = THEME_PATH . $template . C('TMPL_TEMPLATE_SUFFIX');
  239. if (C('TMPL_LOAD_DEFAULTTHEME') && THEME_NAME != C('DEFAULT_THEME') && !is_file($file)) {
  240. // 找不到当前主题模板的时候定位默认主题中的模板
  241. $file = dirname(THEME_PATH) . '/' . C('DEFAULT_THEME') . '/' . $template . C('TMPL_TEMPLATE_SUFFIX');
  242. }
  243. return $file;
  244. }
  245. /**
  246. * 获取当前的模板路径
  247. * @access protected
  248. * @param string $module 模块名
  249. * @return string
  250. */
  251. protected function getThemePath($module = MODULE_NAME)
  252. {
  253. // 获取当前主题名称
  254. $theme = $this->getTemplateTheme();
  255. // 获取当前主题的模版路径
  256. $tmplPath = C('VIEW_PATH'); // 模块设置独立的视图目录
  257. if (!$tmplPath) {
  258. // 定义TMPL_PATH 则改变全局的视图目录到模块之外
  259. $tmplPath = defined('TMPL_PATH') ? TMPL_PATH . $module . '/' : APP_PATH . $module . '/' . C('DEFAULT_V_LAYER') . '/';
  260. }
  261. return $tmplPath . $theme;
  262. }
  263. /**
  264. * 设置当前输出的模板主题
  265. * @access public
  266. * @param mixed $theme 主题名称
  267. * @return View
  268. */
  269. public function theme($theme)
  270. {
  271. $this->theme = $theme;
  272. return $this;
  273. }
  274. /**
  275. * 获取当前的模板主题
  276. * @access private
  277. * @return string
  278. */
  279. private function getTemplateTheme()
  280. {
  281. if ($this->theme) {
  282. // 指定模板主题
  283. $theme = $this->theme;
  284. } else {
  285. /* 获取模板主题名称 */
  286. $theme = C('DEFAULT_THEME');
  287. if (C('TMPL_DETECT_THEME')) {
  288. // 自动侦测模板主题
  289. $t = C('VAR_TEMPLATE');
  290. if (isset($_GET[$t])) {
  291. $theme = $_GET[$t];
  292. } elseif (cookie('think_template')) {
  293. $theme = cookie('think_template');
  294. }
  295. if (!in_array($theme, explode(',', C('THEME_LIST')))) {
  296. $theme = C('DEFAULT_THEME');
  297. }
  298. cookie('think_template', $theme, 864000);
  299. }
  300. }
  301. defined('THEME_NAME') || define('THEME_NAME', $theme); // 当前模板主题名称
  302. return $theme ? $theme . '/' : '';
  303. }
  304. }