IndexController.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. <?php
  2. /**
  3. * @copyright (C)2016-2099 Hnaoyun Inc.
  4. * @author XingMeng
  5. * @email hnxsh@foxmail.com
  6. * @date 2018年2月14日
  7. * 首页控制器
  8. */
  9. namespace app\home\controller;
  10. use core\basic\Controller;
  11. use app\home\model\ParserModel;
  12. use core\basic\Config;
  13. use core\basic\Url;
  14. class IndexController extends Controller
  15. {
  16. protected $parser;
  17. protected $model;
  18. protected $htmldir;
  19. public function __construct()
  20. {
  21. $this->parser = new ParserController();
  22. $this->model = new ParserModel();
  23. $this->htmldir = $this->config('tpl_html_dir') ? $this->config('tpl_html_dir') . '/' : '';
  24. }
  25. // 空拦截器, 实现文章路由转发
  26. public function _empty()
  27. {
  28. // 地址类型
  29. $url_rule_type = $this->config('url_rule_type') ?: 3;
  30. if (P) { // 采用pathinfo模式及p参数伪静态模式
  31. if ($url_rule_type == 2 && stripos(URL, $_SERVER['SCRIPT_NAME']) !== false) { // 禁止伪静态时带index.php访问
  32. _404('您访问的内容不存在,请核对后重试!');
  33. }
  34. $path = P;
  35. } elseif ($url_rule_type == 3 && isset($_SERVER["QUERY_STRING"]) && $qs = $_SERVER["QUERY_STRING"]) { // 采用简短传参模式
  36. parse_str($qs, $output);
  37. unset($output['page']); // 去除分页
  38. if ($output && ! current($output)) { // 第一个路径参数不能有值,否则非标准路径参数
  39. $path = key($output); // 第一个参数为路径信息,注意PHP数组会自动将key点符号转换下划线
  40. } elseif (get('tag')) { // 对于兼容模式tag需要自动跳转tag独立页面
  41. $tag = new TagController();
  42. $tag->index();
  43. } elseif (get('keyword')) { // 兼容模式搜索处理
  44. $search = new SearchController();
  45. $search->index();
  46. }
  47. }
  48. // 判断是否存在后缀
  49. $url_rule_suffix = substr($this->config('url_rule_suffix'), 1);
  50. $suffix = false;
  51. $slash = false;
  52. if (preg_match('/(.*)(_|\.)' . $url_rule_suffix . '$/', $path, $matchs)) {
  53. $path = $matchs[1];
  54. $suffix = true;
  55. } elseif (preg_match('/^[\w\-\/]+\/$/', $path)) {
  56. $slash = true;
  57. $path = trim($path, '/');
  58. }
  59. $path = escape_string($path);
  60. $path_arr = $path ? explode('/', $path) : array();
  61. // 开始路由
  62. if (isset($path_arr) && count($path_arr) > 0 && preg_match('/^[\w\-\/]+$/', $path)) {
  63. switch (strtolower($path_arr[0])) {
  64. case 'search':
  65. case 'keyword':
  66. $search = new SearchController();
  67. $search->index();
  68. break;
  69. case 'message':
  70. $msg = new MessageController();
  71. $msg->index();
  72. break;
  73. case 'form':
  74. $_GET['fcode'] = $path_arr[1];
  75. $form = new FormController();
  76. $form->index();
  77. break;
  78. case 'sitemap':
  79. case 'sitemap_xml':
  80. $sitemap = new SitemapController();
  81. $sitemap->index();
  82. break;
  83. case 'sitemap_txt':
  84. $sitemap = new SitemapController();
  85. $sitemap->linkTxt();
  86. break;
  87. case 'tag':
  88. $tag = new TagController();
  89. $tag->index();
  90. break;
  91. case 'member':
  92. $member = new MemberController();
  93. $member->{$path_arr[1]}();
  94. break;
  95. case 'comment':
  96. $comment = new CommentController();
  97. $comment->{$path_arr[1]}();
  98. break;
  99. case 'spider':
  100. $spider = new SpiderController();
  101. $spider->index();
  102. break;
  103. default:
  104. $url_break_char = $this->config('url_break_char') ?: '_';
  105. $url_rule_content_path = $this->config('url_rule_content_path') ? true : false;
  106. $err = '';
  107. $iscontent = false;
  108. // 开始进行地址匹配
  109. if (! $suffix && ! ! $sort = $this->model->getSort($path)) {
  110. // 栏目名称,即栏目全路径匹配
  111. } elseif (preg_match('/^([a-zA-Z0-9\-\/]+)' . $url_break_char . '([0-9]+)$/i', $path, $matchs) && ! ! $sort = $this->model->getSort($matchs[1])) {
  112. // 栏目名称_分页,栏目分页的情况
  113. define('CMS_PAGE_CUSTOM', true); // 设置走自定义CMS分页
  114. $_GET['page'] = $matchs[2]; // 设置分页参数
  115. } else {
  116. if ($url_rule_content_path && ! ! $data = $this->model->getContent($path)) {
  117. $iscontent = true; // 短路径情况
  118. } elseif (! $url_rule_content_path) {
  119. // 详情页至少是2级,对地址进行栏目和内容路径拆分,访问详情页
  120. $part1 = dirname($path);
  121. $part2 = basename($path);
  122. while ($part1 != '.') {
  123. if ((! ! $sort = $this->model->getSort($part1)) && ! ! $data = $this->model->getContent($part2)) {
  124. // 栏目名称/内容名称或ID
  125. $iscontent = true;
  126. $scode = $sort->scode;
  127. break;
  128. } elseif (preg_match('/^([a-zA-Z0-9\-\/]+)' . $url_break_char . '([0-9]+)$/i', $part1, $matchs) && ! ! $model = $this->model->checkModelUrlname($matchs[1])) {
  129. // 模型名称_栏目ID/内容名称或ID
  130. $data = $this->model->getContent($part2);
  131. $iscontent = true;
  132. $scode = $matchs[2];
  133. // 限制串模型多路径
  134. if (! ! $data->urlname && $matchs[1] != $data->urlname) {
  135. $err = true;
  136. }
  137. break;
  138. } else {
  139. $part2 = basename($part1) . '/' . $part2;
  140. $part1 = dirname($part1);
  141. }
  142. }
  143. // 限制串栏目多路径
  144. if ($scode != $data->scode) {
  145. $err = true;
  146. }
  147. // 限制串内容ID及名称多路径
  148. if (! ! $data->filename && $part2 != $data->filename) {
  149. $err = true;
  150. }
  151. }
  152. // 执行未配置栏目名称但是配置了模型路径的情况路径匹配
  153. if (! $iscontent) {
  154. preg_match('/^([a-zA-Z0-9\-\/]+)(' . $url_break_char . '([0-9]+))?' . $url_break_char . '([0-9]+)$/i', $path, $matchs);
  155. if ($matchs[2] && $model = $this->model->checkModelUrlname($matchs[1])) {
  156. // 模型名称_栏目ID_分页
  157. define('CMS_PAGE_CUSTOM', false);
  158. $sort = $this->model->getSort($matchs[3]);
  159. $_GET['page'] = $matchs[4]; // 分页
  160. } elseif (! ! $model = $this->model->checkModelUrlname($matchs[1])) {
  161. // 模型名称_栏目ID
  162. $sort = $this->model->getSort($matchs[4]);
  163. }
  164. // 限制串模型和栏目名称多路径,当栏目名称不为空时不允许使用模型路径
  165. if ($sort->filename != '') {
  166. $err = true;
  167. }
  168. // 限制串模型多路径
  169. if (! ! $sort->urlname && $matchs[1] != $sort->urlname) {
  170. $err = true;
  171. }
  172. }
  173. }
  174. if ($iscontent) {
  175. define('CMS_PAGE', false); // 使用普通分页处理模型
  176. if (! ! $data && $suffix && ! $err) {
  177. $this->getContentPage($data);
  178. } else {
  179. _404('您访问的内容不存在,请核对后重试!');
  180. }
  181. } else {
  182. define('CMS_PAGE', true); // 使用cms分页处理模型
  183. if (! ! $sort && ! $suffix && ! $err) {
  184. if ($sort->type == 1) {
  185. $this->getAboutPage($sort);
  186. } else {
  187. $this->getListPage($sort);
  188. }
  189. } else {
  190. _404('您访问的页面不存在,请核对后重试!');
  191. }
  192. }
  193. }
  194. } else {
  195. $this->getIndexPage();
  196. }
  197. }
  198. // 首页
  199. private function getIndexPage()
  200. {
  201. $content = parent::parser($this->htmldir . 'index.html'); // 框架标签解析
  202. $content = $this->parser->parserBefore($content); // CMS公共标签前置解析
  203. $content = str_replace('{pboot:pagetitle}', $this->config('index_title') ?: '{pboot:sitetitle}-{pboot:sitesubtitle}', $content);
  204. $content = $this->parser->parserPositionLabel($content, - 1, '首页', SITE_INDEX_DIR . '/'); // CMS当前位置标签解析
  205. $content = $this->parser->parserSpecialPageSortLabel($content, 0, '', SITE_INDEX_DIR . '/'); // 解析分类标签
  206. $content = $this->parser->parserAfter($content); // CMS公共标签后置解析
  207. $this->cache($content, true);
  208. }
  209. // 列表
  210. private function getListPage($sort)
  211. {
  212. // 调用栏目语言与当前语言不一致时,自动切换语言
  213. if ($sort->acode != get_lg() && Config::get('lgautosw') !== '0') {
  214. cookie('lg', $sort->acode);
  215. }
  216. if ($sort->listtpl) {
  217. $this->checkPageLevel($sort->gcode, $sort->gtype, $sort->gnote);
  218. $content = parent::parser($this->htmldir . $sort->listtpl); // 框架标签解析
  219. $content = $this->parser->parserBefore($content); // CMS公共标签前置解析
  220. $pagetitle = $sort->title ? "{sort:title}" : "{sort:name}"; // 页面标题
  221. $content = str_replace('{pboot:pagetitle}', $this->config('list_title') ?: ($pagetitle . '-{pboot:sitetitle}-{pboot:sitesubtitle}'), $content);
  222. $content = str_replace('{pboot:pagekeywords}', '{sort:keywords}', $content);
  223. $content = str_replace('{pboot:pagedescription}', '{sort:description}', $content);
  224. $content = $this->parser->parserPositionLabel($content, $sort->scode); // CMS当前位置标签解析
  225. $content = $this->parser->parserSortLabel($content, $sort); // CMS分类信息标签解析
  226. $content = $this->parser->parserListLabel($content, $sort->scode); // CMS分类列表标签解析
  227. $content = $this->parser->parserAfter($content); // CMS公共标签后置解析
  228. } else {
  229. error('请到后台设置分类栏目列表页模板!');
  230. }
  231. $this->cache($content, true);
  232. }
  233. // 详情页
  234. private function getContentPage($data)
  235. {
  236. // 调用内容语言与当前语言不一致时,自动切换语言
  237. if ($data->acode != get_lg() && Config::get('lgautosw') !== '0') {
  238. cookie('lg', $data->acode);
  239. }
  240. // 读取模板
  241. if (! ! $sort = $this->model->getSort($data->scode)) {
  242. if ($sort->contenttpl) {
  243. $this->checkPageLevel($sort->gcode, $sort->gtype, $sort->gnote); // 检查栏目权限
  244. $this->checkPageLevel($data->gcode, $data->gtype, $data->gnote); // 检查内容权限
  245. $content = parent::parser($this->htmldir . $sort->contenttpl); // 框架标签解析
  246. $content = $this->parser->parserBefore($content); // CMS公共标签前置解析
  247. $content = str_replace('{pboot:pagetitle}', $this->config('content_title') ?: '{content:title}-{sort:name}-{pboot:sitetitle}-{pboot:sitesubtitle}', $content);
  248. $content = str_replace('{pboot:pagekeywords}', '{content:keywords}', $content);
  249. $content = str_replace('{pboot:pagedescription}', '{content:description}', $content);
  250. $content = $this->parser->parserPositionLabel($content, $sort->scode); // CMS当前位置标签解析
  251. $content = $this->parser->parserSortLabel($content, $sort); // CMS分类信息标签解析
  252. $content = $this->parser->parserCurrentContentLabel($content, $sort, $data); // CMS内容标签解析
  253. $content = $this->parser->parserCommentLabel($content); // 文章评论
  254. $content = $this->parser->parserAfter($content); // CMS公共标签后置解析
  255. } else {
  256. error('请到后台设置分类栏目内容页模板!');
  257. }
  258. } else {
  259. _404('您访问内容的分类已经不存在,请核对后再试!');
  260. }
  261. $this->cache($content, true);
  262. }
  263. // 单页
  264. private function getAboutPage($sort)
  265. {
  266. // 调用栏目语言与当前语言不一致时,自动切换语言
  267. if ($sort->acode != get_lg() && Config::get('lgautosw') !== '0') {
  268. cookie('lg', $sort->acode);
  269. }
  270. // 读取数据
  271. if (! $data = $this->model->getAbout($sort->scode)) {
  272. _404('您访问的内容不存在,请核对后重试!');
  273. }
  274. if ($sort->contenttpl) {
  275. $this->checkPageLevel($sort->gcode, $sort->gtype, $sort->gnote);
  276. $content = parent::parser($this->htmldir . $sort->contenttpl); // 框架标签解析
  277. $content = $this->parser->parserBefore($content); // CMS公共标签前置解析
  278. $pagetitle = $sort->title ? "{sort:title}" : "{content:title}"; // 页面标题
  279. $content = str_replace('{pboot:pagetitle}', $this->config('about_title') ?: ($pagetitle . '-{pboot:sitetitle}-{pboot:sitesubtitle}'), $content);
  280. $content = str_replace('{pboot:pagekeywords}', '{content:keywords}', $content);
  281. $content = str_replace('{pboot:pagedescription}', '{content:description}', $content);
  282. $content = $this->parser->parserPositionLabel($content, $sort->scode); // CMS当前位置标签解析
  283. $content = $this->parser->parserSortLabel($content, $sort); // CMS分类信息标签解析
  284. $content = $this->parser->parserCurrentContentLabel($content, $sort, $data); // CMS内容标签解析
  285. $content = $this->parser->parserCommentLabel($content); // 文章评论
  286. $content = $this->parser->parserAfter($content); // CMS公共标签后置解析
  287. } else {
  288. error('请到后台设置分类栏目内容页模板!');
  289. }
  290. $this->cache($content, true);
  291. }
  292. // 检查页面权限
  293. private function checkPageLevel($gcode, $gtype, $gnote)
  294. {
  295. if ($gcode) {
  296. $deny = false;
  297. $gtype = $gtype ?: 4;
  298. switch ($gtype) {
  299. case 1:
  300. if ($gcode <= session('pboot_gcode')) {
  301. $deny = true;
  302. }
  303. break;
  304. case 2:
  305. if ($gcode < session('pboot_gcode')) {
  306. $deny = true;
  307. }
  308. break;
  309. case 3:
  310. if ($gcode != session('pboot_gcode')) {
  311. $deny = true;
  312. }
  313. break;
  314. case 4:
  315. if ($gcode > session('pboot_gcode')) {
  316. $deny = true;
  317. }
  318. break;
  319. case 5:
  320. if ($gcode >= session('pboot_gcode')) {
  321. $deny = true;
  322. }
  323. break;
  324. }
  325. if ($deny) {
  326. $gnote = $gnote ?: '您的权限不足,无法浏览本页面!';
  327. if (session('pboot_uid')) { // 已经登录
  328. error($gnote);
  329. } else {
  330. if ($this->config('login_no_wait')) {
  331. location(Url::home('member/login', null, "backurl=" . urlencode(get_current_url())));
  332. } else {
  333. error($gnote, Url::home('member/login', null, "backurl=" . urlencode(get_current_url())));
  334. }
  335. }
  336. }
  337. }
  338. }
  339. }