View.class.php 10 KB

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