IndexController.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  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) { // 禁止伪静态时带index.php 和动态地址访问
  32. if(stripos(URL, 'index.php') !== false){
  33. _404('您访问的内容不存在,请核对后重试!');
  34. }
  35. if(stripos(URL,'?') !== false && stripos(URL,'/?tag=') == false && stripos(URL,'/?page=') == false && stripos(URL,'/?ext_') == false){
  36. _404('您访问的内容不存在,请核对后重试!');
  37. }
  38. }
  39. $path = P;
  40. } elseif ($url_rule_type == 3 && isset($_SERVER["QUERY_STRING"]) && $qs = $_SERVER["QUERY_STRING"]) { // 采用简短传参模式
  41. parse_str($qs, $output);
  42. unset($output['page']); // 去除分页
  43. if ($output && ! current($output)) { // 第一个路径参数不能有值,否则非标准路径参数
  44. $path = key($output); // 第一个参数为路径信息,注意PHP数组会自动将key点符号转换下划线
  45. } elseif (get('tag')) { // 对于兼容模式tag需要自动跳转tag独立页面
  46. $tag = new TagController();
  47. $tag->index();
  48. } elseif (get('keyword')) { // 兼容模式搜索处理
  49. $search = new SearchController();
  50. $search->index();
  51. }
  52. }
  53. // 判断是否存在后缀
  54. $url_rule_suffix = substr($this->config('url_rule_suffix'), 1);
  55. $suffix = false;
  56. $slash = false;
  57. if (preg_match('/(.*)(_|\.)' . $url_rule_suffix . '$/', $path, $matchs)) {
  58. $path = $matchs[1];
  59. $suffix = true;
  60. } elseif (preg_match('/^[\w\-\/]+\/$/', $path)) {
  61. $slash = true;
  62. $path = trim($path, '/');
  63. }
  64. $path = escape_string($path);
  65. $path_arr = $path ? explode('/', $path) : array();
  66. // 开始路由
  67. if (isset($path_arr) && count($path_arr) > 0 && preg_match('/^[\w\-\/]+$/', $path)) {
  68. switch (strtolower($path_arr[0])) {
  69. case 'search':
  70. case 'keyword':
  71. $search = new SearchController();
  72. $search->index();
  73. break;
  74. case 'message':
  75. $msg = new MessageController();
  76. $msg->index();
  77. break;
  78. case 'form':
  79. $_GET['fcode'] = $path_arr[1];
  80. $form = new FormController();
  81. $form->index();
  82. break;
  83. case 'sitemap':
  84. case 'sitemap_xml':
  85. $sitemap = new SitemapController();
  86. $sitemap->index();
  87. break;
  88. case 'sitemap_txt':
  89. $sitemap = new SitemapController();
  90. $sitemap->linkTxt();
  91. break;
  92. case 'tag':
  93. $tag = new TagController();
  94. $tag->index();
  95. break;
  96. case 'member':
  97. $member = new MemberController();
  98. $member->{$path_arr[1]}();
  99. break;
  100. case 'comment':
  101. $comment = new CommentController();
  102. $comment->{$path_arr[1]}();
  103. break;
  104. case 'spider':
  105. $spider = new SpiderController();
  106. $spider->index();
  107. break;
  108. default:
  109. $url_break_char = $this->config('url_break_char') ?: '_';
  110. $url_rule_content_path = $this->config('url_rule_content_path') ? true : false;
  111. $err = '';
  112. $iscontent = false;
  113. // 开始进行地址匹配
  114. if (! $suffix && ! ! $sort = $this->model->getSort($path)) {
  115. // 栏目名称,即栏目全路径匹配
  116. } elseif (preg_match('/^([a-zA-Z0-9\-\/]+)' . $url_break_char . '([0-9]+)$/i', $path, $matchs) && ! ! $sort = $this->model->getSort($matchs[1])) {
  117. // 栏目名称_分页,栏目分页的情况
  118. define('CMS_PAGE_CUSTOM', true); // 设置走自定义CMS分页
  119. $_GET['page'] = $matchs[2]; // 设置分页参数
  120. } else {
  121. if ($url_rule_content_path && ! ! $data = $this->model->getContent($path)) {
  122. $iscontent = true; // 短路径情况
  123. } elseif (! $url_rule_content_path) {
  124. // 详情页至少是2级,对地址进行栏目和内容路径拆分,访问详情页
  125. $part1 = dirname($path);
  126. $part2 = basename($path);
  127. while ($part1 != '.') {
  128. if ((! ! $sort = $this->model->getSort($part1)) && ! ! $data = $this->model->getContent($part2)) {
  129. // 栏目名称/内容名称或ID
  130. $iscontent = true;
  131. $scode = $sort->scode;
  132. break;
  133. } elseif (preg_match('/^([a-zA-Z0-9\-\/]+)' . $url_break_char . '([0-9]+)$/i', $part1, $matchs) && ! ! $model = $this->model->checkModelUrlname($matchs[1])) {
  134. // 模型名称_栏目ID/内容名称或ID
  135. $data = $this->model->getContent($part2);
  136. $iscontent = true;
  137. $scode = $matchs[2];
  138. // 限制串模型多路径
  139. if (! ! $data->urlname && $matchs[1] != $data->urlname) {
  140. $err = true;
  141. }
  142. break;
  143. } else {
  144. $part2 = basename($part1) . '/' . $part2;
  145. $part1 = dirname($part1);
  146. }
  147. }
  148. // 限制串栏目多路径
  149. if ($scode != $data->scode) {
  150. $err = true;
  151. }
  152. // 限制串内容ID及名称多路径
  153. if (! ! $data->filename && $part2 != $data->filename) {
  154. $err = true;
  155. }
  156. }
  157. // 执行未配置栏目名称但是配置了模型路径的情况路径匹配
  158. if (! $iscontent) {
  159. preg_match('/^([a-zA-Z0-9\-\/]+)(' . $url_break_char . '([0-9]+))?' . $url_break_char . '([0-9]+)$/i', $path, $matchs);
  160. if ($matchs[2] && $model = $this->model->checkModelUrlname($matchs[1])) {
  161. // 模型名称_栏目ID_分页
  162. define('CMS_PAGE_CUSTOM', false);
  163. $sort = $this->model->getSort($matchs[3]);
  164. $_GET['page'] = $matchs[4]; // 分页
  165. } elseif (! ! $model = $this->model->checkModelUrlname($matchs[1])) {
  166. // 模型名称_栏目ID
  167. $sort = $this->model->getSort($matchs[4]);
  168. }
  169. // 限制串模型和栏目名称多路径,当栏目名称不为空时不允许使用模型路径
  170. if ($sort->filename != '') {
  171. $err = true;
  172. }
  173. // 限制串模型多路径
  174. if (! ! $sort->urlname && $matchs[1] != $sort->urlname) {
  175. $err = true;
  176. }
  177. }
  178. }
  179. if ($iscontent) {
  180. define('CMS_PAGE', false); // 使用普通分页处理模型
  181. if (! ! $data && $suffix && ! $err) {
  182. $this->getContentPage($data);
  183. } else {
  184. _404('您访问的内容不存在,请核对后重试!');
  185. }
  186. } else {
  187. define('CMS_PAGE', true); // 使用cms分页处理模型
  188. if (! ! $sort && ! $suffix && ! $err) {
  189. if ($sort->type == 1) {
  190. $this->getAboutPage($sort);
  191. } else {
  192. $this->getListPage($sort);
  193. }
  194. } else {
  195. _404('您访问的页面不存在,请核对后重试!');
  196. }
  197. }
  198. }
  199. } else {
  200. if(SITE_DIR == ''){
  201. //一级目录
  202. $this->urlJump($url_rule_type,false);
  203. } else {
  204. //二级目录
  205. $this->urlJump($url_rule_type,true);
  206. }
  207. }
  208. }
  209. // 首页
  210. private function getIndexPage()
  211. {
  212. $content = parent::parser($this->htmldir . 'index.html'); // 框架标签解析
  213. $content = $this->parser->parserBefore($content); // CMS公共标签前置解析
  214. $content = str_replace('{pboot:pagetitle}', $this->config('index_title') ?: '{pboot:sitetitle}-{pboot:sitesubtitle}', $content);
  215. $content = $this->parser->parserPositionLabel($content, - 1, '首页', SITE_INDEX_DIR . '/'); // CMS当前位置标签解析
  216. $content = $this->parser->parserSpecialPageSortLabel($content, 0, '', SITE_INDEX_DIR . '/'); // 解析分类标签
  217. $content = $this->parser->parserAfter($content); // CMS公共标签后置解析
  218. $this->cache($content, true);
  219. }
  220. // 列表
  221. private function getListPage($sort)
  222. {
  223. // 调用栏目语言与当前语言不一致时,自动切换语言
  224. if ($sort->acode != get_lg() && Config::get('lgautosw') !== '0') {
  225. cookie('lg', $sort->acode);
  226. }
  227. if ($sort->listtpl) {
  228. $this->checkPageLevel($sort->gcode, $sort->gtype, $sort->gnote);
  229. $content = parent::parser($this->htmldir . $sort->listtpl); // 框架标签解析
  230. $content = $this->parser->parserBefore($content); // CMS公共标签前置解析
  231. $pagetitle = $sort->title ? "{sort:title}" : "{sort:name}"; // 页面标题
  232. $content = str_replace('{pboot:pagetitle}', $this->config('list_title') ?: ($pagetitle . '-{pboot:sitetitle}-{pboot:sitesubtitle}'), $content);
  233. $content = str_replace('{pboot:pagekeywords}', '{sort:keywords}', $content);
  234. $content = str_replace('{pboot:pagedescription}', '{sort:description}', $content);
  235. $content = $this->parser->parserPositionLabel($content, $sort->scode); // CMS当前位置标签解析
  236. $content = $this->parser->parserSortLabel($content, $sort); // CMS分类信息标签解析
  237. $content = $this->parser->parserListLabel($content, $sort->scode); // CMS分类列表标签解析
  238. $content = $this->parser->parserAfter($content); // CMS公共标签后置解析
  239. } else {
  240. error('请到后台设置分类栏目列表页模板!');
  241. }
  242. $this->cache($content, true);
  243. }
  244. // 详情页
  245. private function getContentPage($data)
  246. {
  247. // 调用内容语言与当前语言不一致时,自动切换语言
  248. if ($data->acode != get_lg() && Config::get('lgautosw') !== '0') {
  249. cookie('lg', $data->acode);
  250. }
  251. // 读取模板
  252. if (! ! $sort = $this->model->getSort($data->scode)) {
  253. if ($sort->contenttpl) {
  254. $this->checkPageLevel($sort->gcode, $sort->gtype, $sort->gnote); // 检查栏目权限
  255. $this->checkPageLevel($data->gcode, $data->gtype, $data->gnote); // 检查内容权限
  256. $content = parent::parser($this->htmldir . $sort->contenttpl); // 框架标签解析
  257. $content = $this->parser->parserBefore($content); // CMS公共标签前置解析
  258. $content = str_replace('{pboot:pagetitle}', $this->config('content_title') ?: '{content:title}-{sort:name}-{pboot:sitetitle}-{pboot:sitesubtitle}', $content);
  259. $content = str_replace('{pboot:pagekeywords}', '{content:keywords}', $content);
  260. $content = str_replace('{pboot:pagedescription}', '{content:description}', $content);
  261. $content = $this->parser->parserPositionLabel($content, $sort->scode); // CMS当前位置标签解析
  262. $content = $this->parser->parserSortLabel($content, $sort); // CMS分类信息标签解析
  263. $content = $this->parser->parserCurrentContentLabel($content, $sort, $data); // CMS内容标签解析
  264. $content = $this->parser->parserCommentLabel($content); // 文章评论
  265. $content = $this->parser->parserAfter($content); // CMS公共标签后置解析
  266. } else {
  267. error('请到后台设置分类栏目内容页模板!');
  268. }
  269. } else {
  270. _404('您访问内容的分类已经不存在,请核对后再试!');
  271. }
  272. $this->cache($content, true);
  273. }
  274. // 单页
  275. private function getAboutPage($sort)
  276. {
  277. // 调用栏目语言与当前语言不一致时,自动切换语言
  278. if ($sort->acode != get_lg() && Config::get('lgautosw') !== '0') {
  279. cookie('lg', $sort->acode);
  280. }
  281. // 读取数据
  282. if (! $data = $this->model->getAbout($sort->scode)) {
  283. _404('您访问的内容不存在,请核对后重试!');
  284. }
  285. if ($sort->contenttpl) {
  286. $this->checkPageLevel($sort->gcode, $sort->gtype, $sort->gnote);
  287. $content = parent::parser($this->htmldir . $sort->contenttpl); // 框架标签解析
  288. $content = $this->parser->parserBefore($content); // CMS公共标签前置解析
  289. $pagetitle = $sort->title ? "{sort:title}" : "{content:title}"; // 页面标题
  290. $content = str_replace('{pboot:pagetitle}', $this->config('about_title') ?: ($pagetitle . '-{pboot:sitetitle}-{pboot:sitesubtitle}'), $content);
  291. $content = str_replace('{pboot:pagekeywords}', '{content:keywords}', $content);
  292. $content = str_replace('{pboot:pagedescription}', '{content:description}', $content);
  293. $content = $this->parser->parserPositionLabel($content, $sort->scode); // CMS当前位置标签解析
  294. $content = $this->parser->parserSortLabel($content, $sort); // CMS分类信息标签解析
  295. $content = $this->parser->parserCurrentContentLabel($content, $sort, $data); // CMS内容标签解析
  296. $content = $this->parser->parserCommentLabel($content); // 文章评论
  297. $content = $this->parser->parserAfter($content); // CMS公共标签后置解析
  298. } else {
  299. error('请到后台设置分类栏目内容页模板!');
  300. }
  301. $this->cache($content, true);
  302. }
  303. // 检查页面权限
  304. private function checkPageLevel($gcode, $gtype, $gnote)
  305. {
  306. if ($gcode) {
  307. $deny = false;
  308. $gtype = $gtype ?: 4;
  309. switch ($gtype) {
  310. case 1:
  311. if ($gcode <= session('pboot_gcode')) {
  312. $deny = true;
  313. }
  314. break;
  315. case 2:
  316. if ($gcode < session('pboot_gcode')) {
  317. $deny = true;
  318. }
  319. break;
  320. case 3:
  321. if ($gcode != session('pboot_gcode')) {
  322. $deny = true;
  323. }
  324. break;
  325. case 4:
  326. if ($gcode > session('pboot_gcode')) {
  327. $deny = true;
  328. }
  329. break;
  330. case 5:
  331. if ($gcode >= session('pboot_gcode')) {
  332. $deny = true;
  333. }
  334. break;
  335. }
  336. if ($deny) {
  337. $gnote = $gnote ?: '您的权限不足,无法浏览本页面!';
  338. if (session('pboot_uid')) { // 已经登录
  339. error($gnote);
  340. } else {
  341. if ($this->config('login_no_wait')) {
  342. location(Url::home('member/login', null, "backurl=" . urlencode(get_current_url())));
  343. } else {
  344. error($gnote, Url::home('member/login', null, "backurl=" . urlencode(get_current_url())));
  345. }
  346. }
  347. }
  348. }
  349. }
  350. //首页跳转并过滤注入字符
  351. /*
  352. * @param $type url模式
  353. * @param $isSecSiteDir 是否为二级目录 boolean
  354. * */
  355. private function urlJump($type, $isSecSiteDir){
  356. //首页开启了分页直接跳转
  357. if(strpos($_SERVER['REQUEST_URI'],'/?page=') === 0){
  358. $this->getIndexPage();
  359. }
  360. $http = is_https() ? 'https://' : 'http://';
  361. $matches1 = '';
  362. switch ($type){
  363. //普通模式
  364. case 1:
  365. $preg1 = '';
  366. if($isSecSiteDir === true){
  367. if($_SERVER['REQUEST_URI'] == SITE_DIR . '/index.php'){
  368. $preg1 = '/^\/.*?\/index.php/';
  369. } elseif($_SERVER['REQUEST_URI'] == '/index.php'){
  370. $preg1 = '/^\/index.php/';
  371. }
  372. } else {
  373. $preg1 = '/^\/index.php/';
  374. }
  375. preg_match($preg1,$_SERVER['REQUEST_URI'],$matches1);
  376. break;
  377. //伪静态
  378. case 2:
  379. $preg2 = '';
  380. if($isSecSiteDir === true){
  381. if($_SERVER['REQUEST_URI'] == SITE_DIR . '/'){
  382. $preg2 = '/^\/.*/';
  383. } elseif($_SERVER['REQUEST_URI'] == '/'){
  384. $preg2 = '/^\/$/';
  385. }
  386. } else {
  387. $preg2 = '/^\//';
  388. }
  389. preg_match($preg2,$_SERVER['REQUEST_URI'],$matches1);
  390. break;
  391. //兼容模式
  392. case 3:
  393. $preg3 = '';
  394. if($isSecSiteDir === true){
  395. if(strpos($_SERVER['REQUEST_URI'], SITE_DIR) === 0){
  396. $preg3 = '/(^\/.*?\/index.php)|(^\/.*)/';
  397. } elseif(strpos($_SERVER['REQUEST_URI'], '/') === 0){
  398. $preg3 = '/(^\/index.php)|(^\/)/';
  399. }
  400. } else {
  401. $preg3 = '/(^\/index.php)|(^\/)/';
  402. }
  403. preg_match($preg3,$_SERVER['REQUEST_URI'],$matches1);
  404. break;
  405. }
  406. // if(strpos($matches1[0],'/?page=') !== 0 || $matches1[0]){
  407. // $this->getIndexPage();
  408. // }
  409. // if(strpos($_SERVER['REQUEST_URI'],'?page') !== 0){
  410. // $this->getIndexPage();
  411. // }
  412. if($matches1[0]){
  413. if($_SERVER['REQUEST_URI'] == $matches1[0]){
  414. $this->getIndexPage();
  415. } elseif(strpos($matches1[0],'/?page=') !== false) {
  416. $this->getIndexPage();
  417. }else{
  418. //读取后台首页404访问配置
  419. if($this->config('url_index_404') == 1){
  420. _404('您访问的页面不存在,请核对后重试!');
  421. }
  422. header("Location: " . $http . $_SERVER['HTTP_HOST'] . $matches1[0], true, 301);
  423. }
  424. } else {
  425. _404('您访问的页面不存在,请核对后重试!');
  426. }
  427. }
  428. }