Lists.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. <?php
  2. /**
  3. * 易优CMS
  4. * ============================================================================
  5. * 版权所有 2016-2028 海南赞赞网络科技有限公司,并保留所有权利。
  6. * 网站地址: http://www.eyoucms.com
  7. * ----------------------------------------------------------------------------
  8. * 如果商业用途务必到官方购买正版授权, 以免引起不必要的法律纠纷.
  9. * ============================================================================
  10. * Author: 小虎哥 <1105415366@qq.com>
  11. * Date: 2018-4-3
  12. */
  13. namespace app\home\controller;
  14. use think\Db;
  15. use think\Verify;
  16. class Lists extends Base
  17. {
  18. // 模型标识
  19. public $nid = '';
  20. // 模型ID
  21. public $channel = '';
  22. public function _initialize()
  23. {
  24. parent::_initialize();
  25. }
  26. /**
  27. * 栏目列表
  28. */
  29. public function index($tid = '')
  30. {
  31. $param = input('param.');
  32. /*获取当前栏目ID以及模型ID*/
  33. $page_tmp = input('param.page/s', 0);
  34. if (empty($tid) || !is_numeric($page_tmp)) {
  35. abort(404, '页面不存在');
  36. }
  37. $map = [];
  38. /*URL上参数的校验*/
  39. /* $seo_pseudo = config('ey_config.seo_pseudo');
  40. $url_screen_var = config('global.url_screen_var');
  41. if (!isset($param[$url_screen_var]) && 3 == $seo_pseudo)
  42. {
  43. if (stristr($this->request->url(), '&c=Lists&a=index&')) {
  44. abort(404,'页面不存在');
  45. }
  46. $map = array('a.dirname'=>$tid);
  47. }
  48. else if (isset($param[$url_screen_var]) || 1 == $seo_pseudo || (2 == $seo_pseudo && isMobile()))
  49. {
  50. $seo_dynamic_format = config('ey_config.seo_dynamic_format');
  51. if (1 == $seo_pseudo && 2 == $seo_dynamic_format && stristr($this->request->url(), '&c=Lists&a=index&')) {
  52. abort(404,'页面不存在');
  53. } else if (!is_numeric($tid) || strval(intval($tid)) !== strval($tid)) {
  54. abort(404,'页面不存在');
  55. }
  56. $map = array('a.id'=>$tid);
  57. }else if (2 == $seo_pseudo){ // 生成静态页面代码
  58. $map = array('a.id'=>$tid);
  59. }*/
  60. /*--end*/
  61. if (!is_numeric($tid) || strval(intval($tid)) !== strval($tid)) {
  62. $map = array('a.dirname' => $tid);
  63. } else {
  64. $map = array('a.id' => $tid);
  65. }
  66. $map['a.is_del'] = 0; // 回收站功能
  67. $map['a.lang'] = $this->home_lang; // 多语言
  68. $row = M('arctype')->field('a.id, a.current_channel, b.nid')
  69. ->alias('a')
  70. ->join('__CHANNELTYPE__ b', 'a.current_channel = b.id', 'LEFT')
  71. ->where($map)
  72. ->find();
  73. if (empty($row)) {
  74. abort(404, '页面不存在');
  75. }
  76. $tid = $row['id'];
  77. $this->nid = $row['nid'];
  78. $this->channel = intval($row['current_channel']);
  79. /*--end*/
  80. $result = $this->logic($tid); // 模型对应逻辑
  81. $eyou = array(
  82. 'field' => $result,
  83. );
  84. $this->eyou = array_merge($this->eyou, $eyou);
  85. $this->assign('eyou', $this->eyou);
  86. /*模板文件*/
  87. $viewfile = !empty($result['templist'])
  88. ? str_replace('.' . $this->view_suffix, '', $result['templist'])
  89. : 'lists_' . $this->nid;
  90. /*--end*/
  91. /*多语言内置模板文件名*/
  92. if (!empty($this->home_lang)) {
  93. $viewfilepath = TEMPLATE_PATH . $this->theme_style . DS . $viewfile . "_{$this->home_lang}." . $this->view_suffix;
  94. if (file_exists($viewfilepath)) {
  95. $viewfile .= "_{$this->home_lang}";
  96. }
  97. }
  98. /*--end*/
  99. // /*模板文件*/
  100. // $viewfile = $filename = !empty($result['templist'])
  101. // ? str_replace('.'.$this->view_suffix, '',$result['templist'])
  102. // : 'lists_'.$this->nid;
  103. // /*--end*/
  104. // /*每个栏目内置模板文件名*/
  105. // $viewfilepath = TEMPLATE_PATH.$this->theme_style.DS.$filename."_{$result['id']}.".$this->view_suffix;
  106. // if (file_exists($viewfilepath)) {
  107. // $viewfile = $filename."_{$result['id']}";
  108. // }
  109. // /*--end*/
  110. // /*多语言内置模板文件名*/
  111. // if (!empty($this->home_lang)) {
  112. // $viewfilepath = TEMPLATE_PATH.$this->theme_style.DS.$filename."_{$this->home_lang}.".$this->view_suffix;
  113. // if (file_exists($viewfilepath)) {
  114. // $viewfile = $filename."_{$this->home_lang}";
  115. // }
  116. // /*每个栏目内置模板文件名*/
  117. // $viewfilepath = TEMPLATE_PATH.$this->theme_style.DS.$filename."_{$result['id']}_{$this->home_lang}.".$this->view_suffix;
  118. // if (file_exists($viewfilepath)) {
  119. // $viewfile = $filename."_{$result['id']}_{$this->home_lang}";
  120. // }
  121. // /*--end*/
  122. // }
  123. // /*--end*/
  124. return $this->fetch(":{$viewfile}");
  125. }
  126. /**
  127. * 模型对应逻辑
  128. * @param intval $tid 栏目ID
  129. * @return array
  130. */
  131. private function logic($tid = '')
  132. {
  133. $result = array();
  134. if (empty($tid)) {
  135. return $result;
  136. }
  137. switch ($this->channel) {
  138. case '6': // 单页模型
  139. {
  140. $arctype_info = model('Arctype')->getInfo($tid);
  141. if ($arctype_info) {
  142. // 读取当前栏目的内容,否则读取每一级第一个子栏目的内容,直到有内容或者最后一级栏目为止。
  143. $result_new = $this->readContentFirst($tid);
  144. // 阅读权限
  145. if ($result_new['arcrank'] == -1) {
  146. $this->success('待审核稿件,你没有权限阅读!');
  147. exit;
  148. }
  149. // 外部链接跳转
  150. if ($result_new['is_part'] == 1) {
  151. $result_new['typelink'] = htmlspecialchars_decode($result_new['typelink']);
  152. if (!is_http_url($result_new['typelink'])) {
  153. $typeurl = '//'.$this->request->host();
  154. if (!preg_match('#^'.ROOT_DIR.'(.*)$#i', $result_new['typelink'])) {
  155. $typeurl .= ROOT_DIR;
  156. }
  157. $typeurl .= '/'.trim($result_new['typelink'], '/');
  158. $result_new['typelink'] = $typeurl;
  159. }
  160. $this->redirect($result_new['typelink']);
  161. exit;
  162. }
  163. /*自定义字段的数据格式处理*/
  164. $result_new = $this->fieldLogic->getChannelFieldList($result_new, $this->channel);
  165. /*--end*/
  166. $result = array_merge($arctype_info, $result_new);
  167. $result['templist'] = !empty($arctype_info['templist']) ? $arctype_info['templist'] : 'lists_'. $arctype_info['nid'];
  168. $result['dirpath'] = $arctype_info['dirpath'];
  169. $result['typeid'] = $arctype_info['typeid'];
  170. }
  171. break;
  172. }
  173. default:
  174. {
  175. $result = model('Arctype')->getInfo($tid);
  176. /*外部链接跳转*/
  177. if ($result['is_part'] == 1) {
  178. $result['typelink'] = htmlspecialchars_decode($result['typelink']);
  179. if (!is_http_url($result['typelink'])) {
  180. $result['typelink'] = '//'.$this->request->host().ROOT_DIR.'/'.trim($result['typelink'], '/');
  181. }
  182. $this->redirect($result['typelink']);
  183. exit;
  184. }
  185. /*end*/
  186. break;
  187. }
  188. }
  189. if (!empty($result)) {
  190. /*自定义字段的数据格式处理*/
  191. $result = $this->fieldLogic->getTableFieldList($result, config('global.arctype_channel_id'));
  192. /*--end*/
  193. }
  194. /*是否有子栏目,用于标记【全部】选中状态*/
  195. $result['has_children'] = model('Arctype')->hasChildren($tid);
  196. /*--end*/
  197. // seo
  198. $result['seo_title'] = set_typeseotitle($result['typename'], $result['seo_title']);
  199. /*获取当前页面URL*/
  200. $result['pageurl'] = $this->request->url(true);
  201. /*--end*/
  202. /*给没有type前缀的字段新增一个带前缀的字段,并赋予相同的值*/
  203. foreach ($result as $key => $val) {
  204. if (!preg_match('/^type/i', $key)) {
  205. $key_new = 'type' . $key;
  206. !array_key_exists($key_new, $result) && $result[$key_new] = $val;
  207. }
  208. }
  209. /*--end*/
  210. return $result;
  211. }
  212. /**
  213. * 读取指定栏目ID下有内容的栏目信息,只读取每一级的第一个栏目
  214. * @param intval $typeid 栏目ID
  215. * @return array
  216. */
  217. private function readContentFirst($typeid)
  218. {
  219. $result = false;
  220. while (true)
  221. {
  222. $result = model('Single')->getInfoByTypeid($typeid);
  223. if (empty($result['content']) && preg_match('/^lists_single(_(.*))?\.htm$/i', $result['templist'])) {
  224. $map = array(
  225. 'parent_id' => $result['typeid'],
  226. 'current_channel' => 6,
  227. 'is_hidden' => 0,
  228. 'status' => 1,
  229. );
  230. $row = M('arctype')->where($map)->field('*')->order('sort_order asc')->find(); // 查找下一级的单页模型栏目
  231. if (empty($row)) { // 不存在并返回当前栏目信息
  232. break;
  233. } elseif (6 == $row['current_channel']) { // 存在且是单页模型,则进行继续往下查找,直到有内容为止
  234. $typeid = $row['id'];
  235. }
  236. } else {
  237. break;
  238. }
  239. }
  240. return $result;
  241. }
  242. /**
  243. * 留言提交
  244. */
  245. public function gbook_submit()
  246. {
  247. $typeid = input('post.typeid/d');
  248. if (IS_POST && !empty($typeid)) {
  249. $post = input('post.');
  250. $token = '__token__';
  251. foreach ($post as $key => $val) {
  252. if (preg_match('/^__token__/i', $key)) {
  253. $token = $key;
  254. continue;
  255. }
  256. }
  257. $ip = clientIP();
  258. /*留言间隔限制*/
  259. $channel_guestbook_interval = tpSetting('channel_guestbook.channel_guestbook_interval');
  260. $channel_guestbook_interval = is_numeric($channel_guestbook_interval) ? intval($channel_guestbook_interval) : 60;
  261. if (0 < $channel_guestbook_interval) {
  262. $map = array(
  263. 'ip' => $ip,
  264. 'typeid' => $typeid,
  265. 'lang' => $this->home_lang,
  266. 'add_time' => array('gt', getTime() - $channel_guestbook_interval),
  267. );
  268. $count = M('guestbook')->where($map)->count('aid');
  269. if ($count > 0) {
  270. $this->error('同一个IP在'.$channel_guestbook_interval.'秒之内不能重复提交!');
  271. }
  272. }
  273. /*end*/
  274. //判断必填项
  275. foreach ($post as $key => $value) {
  276. if (stripos($key, "attr_") !== false) {
  277. //处理得到自定义属性id
  278. $attr_id = substr($key, 5);
  279. $attr_id = intval($attr_id);
  280. $ga_data = Db::name('guestbook_attribute')->where([
  281. 'attr_id' => $attr_id,
  282. 'lang' => $this->home_lang,
  283. ])->find();
  284. if ($ga_data['required'] == 1 && empty($value)) {
  285. $this->error($ga_data['attr_name'] . '不能为空!');
  286. }
  287. if ($ga_data['validate_type'] == 1) {
  288. $pattern = "/^1\d{10}$/";
  289. if (!preg_match($pattern, $value)) {
  290. $this->error($ga_data['attr_name'] . '格式不正确!');
  291. }
  292. } elseif ($ga_data['validate_type'] == 2) {
  293. $pattern = "/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$/i";
  294. if (preg_match($pattern, $value) == false) {
  295. $this->error($ga_data['attr_name'] . '格式不正确!');
  296. }
  297. }
  298. }
  299. }
  300. /* 处理判断验证码 */
  301. $is_vertify = 1; // 默认开启验证码
  302. $guestbook_captcha = config('captcha.guestbook');
  303. if (!function_exists('imagettftext') || empty($guestbook_captcha['is_on'])) {
  304. $is_vertify = 0; // 函数不存在,不符合开启的条件
  305. }
  306. if (1 == $is_vertify) {
  307. if (empty($post['vertify'])) {
  308. $this->error('图片验证码不能为空!');
  309. }
  310. $verify = new Verify();
  311. if (!$verify->check($post['vertify'], $token)) {
  312. $this->error('图片验证码不正确!');
  313. }
  314. }
  315. /* END */
  316. $channeltype_list = config('global.channeltype_list');
  317. $this->channel = !empty($channeltype_list['guestbook']) ? $channeltype_list['guestbook'] : 8;
  318. $newData = array(
  319. 'typeid' => $typeid,
  320. 'channel' => $this->channel,
  321. 'ip' => $ip,
  322. 'lang' => $this->home_lang,
  323. 'add_time' => getTime(),
  324. 'update_time' => getTime(),
  325. );
  326. $data = array_merge($post, $newData);
  327. // 数据验证
  328. $rule = [
  329. 'typeid' => 'require|token:' . $token,
  330. ];
  331. $message = [
  332. 'typeid.require' => '表单缺少标签属性{$field.hidden}',
  333. ];
  334. $validate = new \think\Validate($rule, $message);
  335. if (!$validate->batch()->check($data)) {
  336. $error = $validate->getError();
  337. $error_msg = array_values($error);
  338. $this->error($error_msg[0]);
  339. } else {
  340. $guestbookRow = [];
  341. /*处理是否重复表单数据的提交*/
  342. $formdata = $data;
  343. foreach ($formdata as $key => $val) {
  344. if (in_array($key, ['typeid', 'lang']) || preg_match('/^attr_(\d+)$/i', $key)) {
  345. continue;
  346. }
  347. unset($formdata[$key]);
  348. }
  349. $md5data = md5(serialize($formdata));
  350. $data['md5data'] = $md5data;
  351. $guestbookRow = M('guestbook')->field('aid')->where(['md5data' => $md5data])->find();
  352. /*--end*/
  353. $dataStr = '';
  354. if (empty($guestbookRow)) { // 非重复表单的才能写入数据库
  355. $aid = M('guestbook')->insertGetId($data);
  356. if ($aid > 0) {
  357. $res = $this->saveGuestbookAttr($aid, $typeid);
  358. if ($res){
  359. $this->error($res);
  360. }
  361. }
  362. /*插件 - 邮箱发送*/
  363. $data = [
  364. 'gbook_submit',
  365. $typeid,
  366. $aid,
  367. ];
  368. $dataStr = implode('|', $data);
  369. /*--end*/
  370. } else {
  371. // 存在重复数据的表单,将在后台显示在最前面
  372. Db::name('guestbook')->where('aid', $guestbookRow['aid'])->update([
  373. 'add_time' => getTime(),
  374. 'update_time' => getTime(),
  375. ]);
  376. }
  377. $this->success('操作成功!', null, $dataStr, 5);
  378. }
  379. }
  380. $this->error('表单缺少标签属性{$field.hidden}');
  381. }
  382. /**
  383. * 给指定留言添加表单值到 guestbook_attr
  384. * @param int $aid 留言id
  385. * @param int $typeid 留言栏目id
  386. */
  387. private function saveGuestbookAttr($aid, $typeid)
  388. {
  389. // post 提交的属性 以 attr_id _ 和值的 组合为键名
  390. $post = input("post.");
  391. $arr = explode('|',tpCache('basic.image_type'));
  392. /*上传图片或附件*/
  393. foreach ($_FILES as $fileElementId => $file) {
  394. try {
  395. if (!empty($file['name']) && !is_array($file['name'])) {
  396. $ext = pathinfo($file['name'], PATHINFO_EXTENSION);
  397. if (in_array($ext,$arr)){
  398. $uplaod_data = func_common($fileElementId, 'allimg');
  399. }else{
  400. $uplaod_data = func_common_doc($fileElementId, 'files');
  401. }
  402. if (0 == $uplaod_data['errcode']) {
  403. $post[$fileElementId] = $uplaod_data['img_url'];
  404. } else {
  405. return $uplaod_data['errmsg'];
  406. // $post[$fileElementId] = '';
  407. }
  408. }
  409. } catch (\Exception $e) {}
  410. }
  411. /*end*/
  412. $attrArr = [];
  413. /*多语言*/
  414. if (is_language()) {
  415. foreach ($post as $key => $val) {
  416. if (preg_match_all('/^attr_(\d+)$/i', $key, $matchs)) {
  417. $attr_value = intval($matchs[1][0]);
  418. $attrArr[$attr_value] = [
  419. 'attr_id' => $attr_value,
  420. ];
  421. }
  422. }
  423. $attrArr = model('LanguageAttr')->getBindValue($attrArr, 'guestbook_attribute'); // 多语言
  424. }
  425. /*--end*/
  426. foreach ($post as $k => $v) {
  427. if (!strstr($k, 'attr_'))
  428. continue;
  429. $attr_id = str_replace('attr_', '', $k);
  430. is_array($v) && $v = implode(PHP_EOL, $v);
  431. /*多语言*/
  432. if (!empty($attrArr)) {
  433. $attr_id = $attrArr[$attr_id]['attr_id'];
  434. }
  435. /*--end*/
  436. //$v = str_replace('_', '', $v); // 替换特殊字符
  437. //$v = str_replace('@', '', $v); // 替换特殊字符
  438. $v = trim($v);
  439. $adddata = array(
  440. 'aid' => $aid,
  441. 'attr_id' => $attr_id,
  442. 'attr_value' => $v,
  443. 'lang' => $this->home_lang,
  444. 'add_time' => getTime(),
  445. 'update_time' => getTime(),
  446. );
  447. M('GuestbookAttr')->add($adddata);
  448. }
  449. }
  450. }