You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1403 lines
61 KiB

6 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. <?php
  2. /*********************************************************************************************************
  3. * Class Boardlib
  4. * ======================================================================================================
  5. *
  6. * 게시판용 라이브러리
  7. *********************************************************************************************************/
  8. class Boardlib {
  9. protected $CI;
  10. function __construct()
  11. {
  12. $this->CI =& get_instance();
  13. $this->CI->load->driver('cache', array('adapter' => 'apc', 'backup' => 'file', 'key_prefix' => PROJECT));
  14. }
  15. /******************************************************************************************************
  16. * 새글이 올라온 게시글 목록을 보여줍니다.
  17. *****************************************************************************************************/
  18. function getNewPostBoards ()
  19. {
  20. $cnt_query =
  21. $this->CI->db
  22. ->select('brd_key, COUNT(brd_key) AS new_cnt')
  23. ->from('board_post')
  24. ->where('reg_datetime >=', date('Y-m-d H:i:s', strtotime('-1 days')))
  25. ->where('post_status','Y')
  26. ->group_by('brd_key')
  27. ->get_compiled_select();
  28. $board_list =
  29. $this->CI->db
  30. ->select('B.*, IF(ISNULL(BC.new_cnt), 0, new_cnt) AS new_cnt')
  31. ->from('board AS B')
  32. ->join("($cnt_query) AS BC", 'BC.brd_key=B.brd_key','left')
  33. ->get()
  34. ->result_array();
  35. return $board_list;
  36. }
  37. /******************************************************************************************************
  38. * 게시판의 정보를 가져옵니다.
  39. *****************************************************************************************************/
  40. function get($brd_key, $get_raw_data = FALSE) {
  41. return $get_raw_data ? $this->_get_board_raw($brd_key) : $this->_get_board_mixed($brd_key);
  42. }
  43. /******************************************************************************************************
  44. * 가공되지 않은 게시판 정보를 가져옵니다.
  45. *****************************************************************************************************/
  46. private function _get_board_raw($brd_key = "")
  47. {
  48. if(empty($brd_key)) return array();
  49. // 캐시된 데이타가 없으면 DB에서 새로 가져옴
  50. if( ! $board = $this->CI->cache->get('board_raw_'.$brd_key) )
  51. {
  52. $result =
  53. $this->CI->db
  54. ->from('board')
  55. ->where('brd_key', $brd_key)
  56. ->limit(1)
  57. ->get();
  58. $board = $result->row_array();
  59. // 개발환경에선 테스트를 위해 CACHE 저장을 하지 않는다.
  60. if( ENVIRONMENT !== 'development') {
  61. $this->CI->cache->save('board_raw_'.$brd_key, $board, 60*5);
  62. }
  63. }
  64. return $board;
  65. }
  66. /******************************************************************************************************
  67. * 가공된 게시판 정보를 가져옵니다.
  68. *****************************************************************************************************/
  69. private function _get_board_mixed($brd_key ="")
  70. {
  71. if( empty($brd_key) ) return array();
  72. // 캐시된 데이타가 없으면 DB에서 새로 가져옴
  73. if( ! $board = $this->CI->cache->get('board_'.$brd_key) ) {
  74. $board = $this->_get_board_raw($brd_key);
  75. $board['category'] = explode(";", rtrim($board['brd_category'],';'));
  76. if(count($board['category']) > 0) {
  77. foreach($board['category'] as &$row)
  78. {
  79. $row = trim($row);
  80. }
  81. }
  82. // 개발환경에선 테스트를 위해 CACHE 저장을 하지 않는다.
  83. if( ENVIRONMENT !== 'development') {
  84. $this->CI->cache->save('board_'.$brd_key, $board, 60*5);
  85. }
  86. }
  87. return $board;
  88. }
  89. /******************************************************************************************************
  90. * 특정 게시판의 캐시 데이타를 삭제한다.
  91. *****************************************************************************************************/
  92. function delete_cache($brd_key)
  93. {
  94. $this->CI->cache->delete('board_raw_'.$brd_key);
  95. $this->CI->cache->delete('board_'.$brd_key);
  96. }
  97. /******************************************************************************************************
  98. * 특정 게시판의 캐시 데이타를 삭제한다.
  99. *****************************************************************************************************/
  100. function common_data($brd_key)
  101. {
  102. $this->CI->data['board'] = $this->get($brd_key, FALSE);
  103. if( empty($this->CI->data['board']) OR ! isset($this->CI->data['board']))
  104. {
  105. alert('존재하지 않는 게시판 또는 삭제된 게시판입니다.');
  106. exit;
  107. }
  108. $this->CI->data['use_secret'] = ($this->CI->data['board']['brd_use_secret'] == 'Y' OR $this->CI->data['board']['brd_use_secret'] == 'A');
  109. $this->CI->data['use_notice'] = PAGE_ADMIN OR $this->CI->member->is_super();
  110. $this->CI->data['use_category'] = (($this->CI->data['board']['brd_use_category'] == 'Y') && (count($this->CI->data['board']['category']) > 0));
  111. $this->CI->data['board']['brd_skin_l'] = ($this->CI->site->viewmode == DEVICE_MOBILE) ? $this->CI->data['board']['brd_skin_l_m'] : $this->CI->data['board']['brd_skin_l'];
  112. $this->CI->data['board']['brd_skin_w'] = ($this->CI->site->viewmode == DEVICE_MOBILE) ? $this->CI->data['board']['brd_skin_w_m'] : $this->CI->data['board']['brd_skin_w'];
  113. $this->CI->data['board']['brd_skin_c'] = ($this->CI->site->viewmode == DEVICE_MOBILE) ? $this->CI->data['board']['brd_skin_c_m'] : $this->CI->data['board']['brd_skin_c'];
  114. $this->CI->data['board']['brd_skin_v'] = ($this->CI->site->viewmode == DEVICE_MOBILE) ? $this->CI->data['board']['brd_skin_v_m'] : $this->CI->data['board']['brd_skin_v'];
  115. $this->CI->data['board']['brd_page_rows'] = ($this->CI->site->viewmode == DEVICE_MOBILE) ? $this->CI->data['board']['brd_page_rows_m'] : $this->CI->data['board']['brd_page_rows'];
  116. $this->CI->data['board']['brd_fixed_num'] = ($this->CI->site->viewmode == DEVICE_MOBILE) ? $this->CI->data['board']['brd_fixed_num_m'] : $this->CI->data['board']['brd_fixed_num'];
  117. unset($this->CI->data['board']['brd_skin_m'], $this->CI->data['board']['brd_page_rows_m'], $this->CI->data['board']['brd_fixed_num_m']);
  118. // 카테고리 목록
  119. $this->CI->data['category_list'] = ( $this->CI->data['use_category'] && count($this->CI->data['board']['category']) > 0 ) ? $this->CI->data['board']['category'] : NULL;
  120. // GET 데이타 정리
  121. $this->CI->param['page'] = $this->CI->data['page'] = (int)$this->CI->input->get('page', TRUE, 1) >= 1 ? $this->CI->input->get('page', TRUE, 1) : 1;
  122. $this->CI->param['scol'] = $this->CI->data['scol'] = $this->CI->input->get('scol', TRUE, '');
  123. $this->CI->param['stxt'] = $this->CI->data['stxt'] = $this->CI->input->get('stxt', TRUE, '');
  124. $this->CI->param['category'] = $this->CI->data['category'] = $this->CI->input->get('category', TRUE, '');
  125. // 링크 주소 정리
  126. $queryParam = array();
  127. foreach($this->CI->param as $key=>$val) if(! empty($val)) $queryParam[$key] = $val;
  128. $param = ( $queryParam && is_array($queryParam) ) ? '?'.http_build_query($queryParam): '';
  129. $this->CI->data['board']['link']['base_url'] = PAGE_ADMIN ? base_url("admin/board/posts/{$brd_key}") : base_url("board/{$brd_key}");
  130. $this->CI->data['board']['link']['list'] = PAGE_ADMIN ? base_url("admin/board/posts/{$brd_key}{$param}") : base_url("board/{$brd_key}$param");
  131. $this->CI->data['board']['link']['write'] = PAGE_ADMIN ? base_url("admin/board/write/{$brd_key}/{$param}") : base_url( "board/{$brd_key}/write{$param}");
  132. $this->CI->data['board']['link']['rss'] = base_url("rss/{$brd_key}");
  133. if(! empty($post_idx))
  134. {
  135. $this->CI->data['board']['link']['modify'] = PAGE_ADMIN ? base_url( "admin/board/write/{$brd_key}/{$post_idx}{$param}" ) : base_url( "board/{$brd_key}/write/{$post_idx}{$param}");
  136. $this->CI->data['board']['link']['delete'] = base_url( "board/{$brd_key}/delete/{$post_idx}".$param );
  137. $this->CI->data['board']['link']['reply'] = base_url( "board/{$brd_key}/reply/{$post_idx}". $param );
  138. }
  139. $this->CI->data['board']['auth']['admin'] = $this->CI->member->is_super();
  140. $this->CI->data['board']['auth']['read'] = ( $this->CI->data['board']['auth']['admin'] OR ($this->CI->member->level() >= $this->CI->data['board']['brd_lv_read']) );
  141. $this->CI->data['board']['auth']['list'] = ( $this->CI->data['board']['auth']['admin'] OR ($this->CI->member->level() >= $this->CI->data['board']['brd_lv_list']) );
  142. $this->CI->data['board']['auth']['write'] = ( $this->CI->data['board']['auth']['admin'] OR ($this->CI->member->level() >= $this->CI->data['board']['brd_lv_write']) );
  143. $this->CI->data['board']['auth']['download'] = ( $this->CI->data['board']['auth']['admin'] OR ($this->CI->member->level() >= $this->CI->data['board']['brd_lv_download']) );
  144. $this->CI->data['board']['auth']['comment'] = ( $this->CI->data['board']['auth']['admin'] OR ($this->CI->member->level() >= $this->CI->data['board']['brd_lv_comment']) );
  145. $this->CI->data['board']['auth']['reply'] = ( $this->CI->data['board']['auth']['admin'] OR ($this->CI->member->level() >= $this->CI->data['board']['brd_lv_reply']) );
  146. }
  147. /**
  148. * 게시글 목록을 가져온다.
  149. * @param $board
  150. * @param array $param
  151. * @return mixed
  152. */
  153. function post_list($board, $param)
  154. {
  155. $this->CI->db
  156. ->select('SQL_CALC_FOUND_ROWS P.*, IF(ISNULL(M.mem_nickname), P.post_nickname, M.mem_nickname) AS post_nickname', FALSE)
  157. ->from('board_post AS P')
  158. ->join("member AS M", "M.mem_idx=P.upd_user","left")
  159. ->where('brd_key', $board['brd_key'])
  160. ->where_in('post_status', array('Y'))
  161. ->where('post_notice', 'Y')
  162. ->order_by("post_num DESC, post_reply ASC, post_idx ASC");
  163. $result= $this->CI->db->get();
  164. $notice_list['list'] = $result->result_array();
  165. $this->CI->db
  166. ->select('SQL_CALC_FOUND_ROWS P.*, IF(ISNULL(M.mem_nickname), P.post_nickname, M.mem_nickname) AS post_nickname', FALSE)
  167. ->from('board_post AS P')
  168. ->join("member AS M", "M.mem_idx=P.upd_user","left")
  169. ->where('brd_key', $board['brd_key'])
  170. ->where_in('post_status', array('Y','B'))
  171. ->where('post_notice', 'N')
  172. ->order_by("post_num DESC, post_reply ASC, post_idx ASC");
  173. $start = 0;
  174. if( $board['brd_page_limit'] == 'Y' ) {
  175. $page_rows = $board['brd_page_rows'];
  176. $page = element('page', $param, 1);
  177. $start = ($page - 1) * $page_rows;
  178. $this->CI->db->limit($page_rows, $start);
  179. }
  180. if( element('category', $param) ) {
  181. $this->CI->db->where('post_category', $param['category']);
  182. }
  183. if( element('scol', $param) && element('stxt', $param) )
  184. {
  185. if( $param['scol'] == 'title' ) {
  186. $this->CI->db->like('post_title', $param['stxt']);
  187. }
  188. else if ( $param['scol'] == 'nickname' )
  189. {
  190. $this->CI->db->like('post_nickname', $param['stxt']);
  191. }
  192. }
  193. $list['list'] = $this->CI->db->get()->result_array();
  194. $list['total_count'] = (int)$this->CI->db->query("SELECT FOUND_ROWS() AS cnt")->row(0)->cnt;
  195. foreach($list['list'] as $i=>&$row)
  196. {
  197. $row['nums'] = $list['total_count'] - $i - $start;
  198. }
  199. $list['list'] = array_merge($notice_list['list'], $list['list']);
  200. $query_param = $this->get_param();
  201. foreach($list['list'] as &$row)
  202. {
  203. $row = $this->post_process($board, $row, $query_param);
  204. }
  205. return $list;
  206. }
  207. /**
  208. * 게시글 하나를 가져온다.
  209. * @param $brd_key
  210. * @param $post_idx
  211. * @param bool $get_raw_data
  212. * @return mixed
  213. */
  214. function get_post($brd_key, $post_idx, $get_raw_data=FALSE)
  215. {
  216. $this->CI->db
  217. ->select('P.*, IF(ISNULL(M.mem_nickname), P.post_nickname, M.mem_nickname) AS post_nickname')
  218. ->from('board_post AS P')
  219. ->join("member AS M", "M.mem_idx=P.upd_user","left")
  220. ->where('post_idx', $post_idx)
  221. ->where_in('post_status', array('Y','N'))
  222. ->where('brd_key', $brd_key);
  223. $result =$this->CI->db->get();
  224. if(! $post = $result->row_array() )
  225. {
  226. return NULL;
  227. }
  228. if( ! $get_raw_data ) {
  229. $board = $this->get($brd_key, FALSE);
  230. $post = $this->post_process($board, $post, $this->CI->param, TRUE);
  231. $np = $this->get_np($brd_key, $post_idx, $post['post_num'], $post['post_reply']);
  232. $post['prev'] = ( isset($np['prev']) && isset($np['prev']['post_idx']) )? $np['prev'] : NULL;
  233. $post['next'] = ( isset($np['next']) && isset($np['next']['post_idx']) )? $np['next'] : NULL;
  234. }
  235. return $post;
  236. }
  237. /**
  238. * 패러미터 정보를 정리해서 가져옴
  239. * @return string
  240. */
  241. function get_param()
  242. {
  243. // 링크를 위한 자료정리
  244. $queryParam = array();
  245. if( $this->CI->input->get('category', TRUE) ) $queryParam['category'] = $this->CI->input->get('category', TRUE);
  246. if( $this->CI->input->get('page', TRUE) ) $queryParam['page'] = $this->CI->input->get('page', TRUE);
  247. if( $this->CI->input->get('scol', TRUE) ) $queryParam['scol'] = $this->CI->input->get('scol', TRUE);
  248. if( $this->CI->input->get('stxt', TRUE) ) $queryParam['stxt'] = $this->CI->input->get('stxt', TRUE);
  249. $param = "";
  250. if( $queryParam && is_array($queryParam) )
  251. {
  252. $param = http_build_query($queryParam);
  253. $param = "?". $param;
  254. }
  255. return $param;
  256. }
  257. /**
  258. * 게시글의 내용을 정리한다.
  259. * @param $board
  260. * @param $post
  261. * @param $param
  262. * @param bool $extra
  263. * @param bool $files
  264. * @return mixed
  265. */
  266. function post_process($board, $post, $param, $files=FALSE)
  267. {
  268. if(is_array($param))
  269. {
  270. $param = '?' . http_build_query($param);
  271. }
  272. $post['post_notice'] = ($post['post_notice']=='Y');
  273. $post['link'] = PAGE_ADMIN ? base_url("admin/board/read/{$board['brd_key']}/{$post['post_idx']}{$param}") : base_url("board/{$board['brd_key']}/{$post['post_idx']}{$param}");
  274. $post['link_modify'] = PAGE_ADMIN ? base_url("admin/board/write/{$board['brd_key']}/{$post['post_idx']}") : base_url("board/{$board['brd_key']}/write/{$post['post_idx']}");
  275. $post['link_delete'] = base_url("board/{$board['brd_key']}/delete/{$post['post_idx']}");
  276. $post['is_new'] = ((time() - strtotime($post['reg_datetime']) ) <= (24 * 60 * 60));
  277. $post['is_hot'] = ($post['post_hit'] >= 300) ;
  278. $post['is_secret'] = ($post['post_secret'] == 'Y');
  279. $post['post_datetime'] = display_datetime($post['reg_datetime'], $board['brd_display_time']);
  280. if( $files) {
  281. $post['file'] = $this->get_attach_list($board['brd_key'], $post['post_idx']);
  282. }
  283. return $post;
  284. }
  285. /**
  286. * 해당 게시글의 이전글과 다음글을 가져온다.
  287. * @param $brd_key
  288. * @param $post_idx
  289. * @param $post_num
  290. * @param $post_depth
  291. * @return mixed
  292. */
  293. function get_np($brd_key, $post_idx,$post_num,$post_reply)
  294. {
  295. $param = $this->get_param();
  296. $this->CI->db->group_start();
  297. $this->CI->db->or_group_start();
  298. $this->CI->db->where("post_num =", (int)$post_num);
  299. $this->CI->db->where('post_reply >', $post_reply);
  300. $this->CI->db->where('post_idx >', $post_idx);
  301. $this->CI->db->group_end();
  302. $this->CI->db->or_group_start();
  303. $this->CI->db->where('post_num <', $post_num);
  304. $this->CI->db->group_end();
  305. $this->CI->db->group_end();
  306. // 이전글 가져오기
  307. $return['prev'] = $this->CI->db->where_in("post_status", array("Y","B"))
  308. ->where('post_notice', "N")
  309. ->where("brd_key", $brd_key)
  310. ->where('post_idx !=', $post_idx)
  311. ->limit(1)
  312. ->order_by("post_num DESC, post_reply ASC, post_idx ASC")
  313. ->get("board_post")
  314. ->row_array();
  315. if(isset($return['prev']['post_idx']))
  316. {
  317. $return['prev']['link'] = PAGE_ADMIN ? base_url("admin/board/read/{$brd_key}/{$return['prev']['post_idx']}{$param}") : base_url("board/{$brd_key}/{$return['prev']['post_idx']}{$param}");
  318. }
  319. $this->CI->db->group_start();
  320. $this->CI->db->or_group_start();
  321. $this->CI->db->where("post_num =", (int)$post_num);
  322. $this->CI->db->where('post_reply <', $post_reply);
  323. $this->CI->db->where('post_idx <', $post_idx);
  324. $this->CI->db->group_end();
  325. $this->CI->db->or_group_start();
  326. $this->CI->db->where('post_num >', $post_num);
  327. $this->CI->db->group_end();
  328. $this->CI->db->group_end();
  329. // 다음글 가져오기
  330. $return['next'] =
  331. $this->CI->db->where_in("post_status", array("Y","B"))
  332. ->where('post_notice', "N")
  333. ->where("brd_key", $brd_key)
  334. ->where('post_idx !=', $post_idx)
  335. ->limit(1)
  336. ->order_by("post_num ASC, post_reply DESC, post_idx DESC")
  337. ->get("board_post")->row_array();
  338. if(isset($return['next']['post_idx']))
  339. {
  340. $return['next']['link'] = PAGE_ADMIN ? base_url("admin/board/read/{$brd_key}/{$return['next']['post_idx']}{$param}") : base_url("board/{$brd_key}/{$return['next']['post_idx']}{$param}");
  341. }
  342. return $return;
  343. }
  344. /**
  345. * 게시글에 포함된 첨부파일 목록을 가져온다.
  346. * @param $brd_key
  347. * @param $post_idx
  348. * @return array
  349. */
  350. function get_attach_list($brd_key, $post_idx)
  351. {
  352. if(empty($brd_key) OR empty($post_idx)) return array();
  353. $file_list = $this->CI->db->where('att_target_type', 'BOARD')->where('att_target', $post_idx)->get('attach')->result_array();
  354. foreach($file_list as &$f)
  355. {
  356. $f['link'] = base_url("board/{$brd_key}/download/{$post_idx}/{$f['att_idx']}");
  357. }
  358. return $file_list;
  359. }
  360. /**
  361. * 댓글 목록 가져오기
  362. * @param $brd_key
  363. * @param $post_idx
  364. */
  365. function comment_list($brd_key, $post_idx, $board_admin=FALSE, $mem_useridx="")
  366. {
  367. $board = $this->get($brd_key, TRUE);
  368. $this->CI->db
  369. ->select('SQL_CALC_FOUND_ROWS C.*, IF(ISNULL(C.cmt_nickname), M.mem_nickname, C.cmt_nickname) AS cmt_nickname', FALSE)
  370. ->from('board_comment AS C')
  371. ->join('member AS M','M.mem_idx=C.reg_user','left')
  372. ->where('brd_key', $brd_key)
  373. ->where('post_idx', $post_idx)
  374. ->where_in('cmt_status', array('Y','B'))
  375. ->order_by("cmt_num DESC,cmt_reply ASC, cmt_idx ASC");
  376. $list['list'] = $this->CI->db->get()->result_array();
  377. $list['total_count'] = (int)$this->CI->db->query('SELECT FOUND_ROWS() AS cnt')->row(0)->cnt;
  378. foreach($list['list'] as &$row)
  379. {
  380. $row['cmt_datetime'] = display_datetime( $row['reg_datetime'], $board['brd_display_time']);
  381. $row['link']['delete'] = base_url("board/{$brd_key}/comment/{$post_idx}/{$row['cmt_idx']}/delete");
  382. $row['link']['blind'] = base_url("board/{$brd_key}/comment/{$post_idx}/{$row['cmt_idx']}/blind");
  383. $row['auth'] = $board_admin || ( $row['reg_user'] >0 && $mem_useridx == $row['reg_user'] ) || $row['reg_user']==0;
  384. $row['ip'] = display_ipaddress(long2ip($row['cmt_ip']), '1001');
  385. }
  386. return $list;
  387. }
  388. /**
  389. * 게시글 작성 처리
  390. */
  391. function write_process($brd_key, $post_idx="")
  392. {
  393. // 수정이나 삭제할경우 권한을 확인한다.
  394. if(! empty($post_idx)) $this->_check_modify_auth($brd_key, $post_idx);
  395. $this->CI->load->library('form_validation');
  396. $this->CI->form_validation->set_rules('post_title', langs('게시판/form/post_title') ,'required|trim');
  397. $this->CI->form_validation->set_rules('post_content', langs('게시판/form/post_content'),'required|trim');
  398. if( ! $this->CI->member->is_login() )
  399. {
  400. $this->CI->form_validation->set_rules('post_nickname', langs('게시판/form/mem_nickname') ,'required|trim');
  401. $this->CI->form_validation->set_rules('post_password', langs('게시판/form/password') ,'required|trim|min_length[4]|max_length[16]');
  402. }
  403. if( $this->CI->form_validation->run() != FALSE )
  404. {
  405. // 수정글이면 기존 글의 정보를 가져온다.
  406. $post = array();
  407. if( $post_idx ) {
  408. $post = $this->get_post($brd_key, $post_idx, FALSE);
  409. }
  410. // 비회원이로 리캡쳐 설정이 되있을 경우 구글 리캡챠 확인
  411. if( ! $this->CI->member->is_login() )
  412. {
  413. // 비회원이고 리캡쳐 설정이 되있을 경우 경우 구글 리캡챠확인
  414. if( $this->CI->site->config('google_recaptcha_site_key') && $this->CI->site->config('google_recaptcha_secret_key') )
  415. {
  416. $this->CI->load->library('google_recaptcha');
  417. $response = $this->CI->input->post('g-recaptcha-response', TRUE);
  418. if( empty($response) OR ! $this->CI->google_recaptcha->check_response( $response ) )
  419. {
  420. alert('자동등록 방지 인증에 실패하였습니다.');
  421. exit;
  422. }
  423. }
  424. // 비회원일이고 수정일 경우 입력한 패스워드와 기존 패스워드 확인
  425. if( $post_idx )
  426. {
  427. if( get_password_hash( $this->CI->input->post('post_password', TRUE) ) != $post['post_password'] )
  428. {
  429. alert('잘못된 비밀번호 입니다.');
  430. exit;
  431. }
  432. }
  433. }
  434. // 받아온 값을 정리한다.
  435. $data['post_title'] = $this->CI->input->post('post_title', TRUE);
  436. $data['post_category'] = $this->CI->input->post('post_category', TRUE, '');
  437. $data['post_parent'] = $this->CI->input->post('post_parent', TRUE, 0);
  438. $data['post_secret'] = $this->CI->input->post('post_secret', TRUE, 'N') == 'Y' ? "Y":'N';
  439. $data['post_content'] = $this->CI->input->post('post_content', FALSE);
  440. $data['brd_key'] = $brd_key;
  441. $data['upd_datetime'] = date('Y-m-d H:i:s');
  442. $data['upd_user'] = $this->CI->member->is_login();
  443. $data['post_notice'] = $this->CI->input->post('post_notice', TRUE) == 'Y' ? 'Y' : 'N';
  444. $data['post_ip'] = ip2long( $this->CI->input->ip_address() );
  445. $data['post_mobile'] = $this->CI->site->viewmode == DEVICE_MOBILE ? 'Y' : 'N';
  446. $data['post_keywords'] = $this->CI->input->post('post_keywords', TRUE);
  447. for($i=1; $i<=9; $i++) $data['post_ext'.$i] = $this->CI->input->post('post_ext'.$i, TRUE,'');
  448. $parent = array();
  449. if(! empty( $data['post_parent'] ) )
  450. {
  451. $parent = $this->get_post($brd_key, $data['post_parent'], FALSE);
  452. }
  453. // 관리자가 아니라면 사용할수 없는 옵션 끄기
  454. if( ! PAGE_ADMIN && ! $this->CI->member->is_super() )
  455. {
  456. $data['post_notice'] = 'N';
  457. }
  458. // 익명전용 게시판이라면 게시글도 익명처리
  459. if($this->CI->input->post('post_annonymous', TRUE) == 'Y' OR $this->CI->data['board']['brd_use_anonymous'] == 'A')
  460. {
  461. $data['post_nickname'] = "익명";
  462. }
  463. // 로그인 상태에 따라 값을 수정
  464. if( $this->CI->member->is_login() )
  465. {
  466. $data['post_nickname'] = $this->CI->member->info('nickname');
  467. $data['post_password'] = $this->CI->member->info('password');
  468. }
  469. else
  470. {
  471. $data['upd_user'] = 0;
  472. $data['post_nickname'] = $this->CI->input->post('post_nickname', TRUE);
  473. $data['post_password'] = get_password_hash( $this->CI->input->post('post_password', TRUE) );
  474. }
  475. // 게시판 설정을 이용해서 값 정리
  476. if( $this->CI->data['board']['brd_use_secret'] == 'N' ) $data['post_secret'] = 'N';
  477. else if ( $this->CI->data['board']['brd_use_secret'] == 'A' ) $data['post_secret'] = 'Y';
  478. // 답글인경우 원글이 비밀글이면 답글도 비밀글
  479. else if ( ! empty($data['post_parent']) && $parent['post_secret'] == 'Y' ) $data['post_secret'] = 'Y';
  480. // 파일 업로드가 있다면
  481. $upload_array = array();
  482. if( isset($_FILES) && isset($_FILES['userfile']) && count($_FILES['userfile']) > 0 )
  483. {
  484. $dir_path = DIR_UPLOAD . "/board/{$brd_key}/".date('Y')."/".date('m');
  485. make_dir($dir_path,FALSE);
  486. $upload_config['upload_path'] = "./".$dir_path;
  487. $upload_config['file_ext_tolower'] = TRUE;
  488. $upload_config['allowed_types'] = FILE_UPLOAD_ALLOW;
  489. $upload_config['encrypt_name'] = TRUE;
  490. $this->CI->load->library("upload", $upload_config);
  491. // FOR문으로 업로드하기 위해 돌리기
  492. $files = NULL;
  493. foreach ($_FILES['userfile'] as $key => $value) {
  494. foreach ($value as $noKey => $noValue) {
  495. $files[$noKey][$key] = $noValue;
  496. }
  497. }
  498. unset($_FILES);
  499. // FOR 문 돌면서 정리
  500. foreach ($files as $file) {
  501. $_FILES['userfile'] = $file;
  502. $this->CI->upload->initialize($upload_config);
  503. if( ! isset($_FILES['userfile']['tmp_name']) OR ! $_FILES['userfile']['tmp_name']) continue;
  504. if (! $this->CI->upload->do_upload('userfile') )
  505. {
  506. alert('파일 업로드에 실패하였습니다.\\n'.$this->CI->upload->display_errors(' ',' '));
  507. exit;
  508. }
  509. else
  510. {
  511. $filedata = $this->CI->upload->data();
  512. $upload_array[] = array(
  513. "att_target_type" => 'BOARD',
  514. "att_origin" => $filedata['orig_name'],
  515. "att_filepath" => $dir_path . "/" . $filedata['file_name'],
  516. "att_downloads" => 0,
  517. "att_filesize" => $filedata['file_size'] * 1024,
  518. "att_width" => $filedata['image_width'] ? $filedata['image_width'] : 0,
  519. "att_height" => $filedata['image_height'] ? $filedata['image_height'] : 0,
  520. "att_ext" => $filedata['file_ext'],
  521. "att_is_image" => ($filedata['is_image'] == 1) ? 'Y' : 'N',
  522. "reg_user" => $this->CI->member->is_login(),
  523. "reg_datetime" => date('Y-m-d H:i:s')
  524. );
  525. }
  526. }
  527. }
  528. // 첨부파일 삭제가 있다면 삭제한다.
  529. $del_file = $this->CI->input->post("del_file", TRUE);
  530. if( $del_file && count($del_file) > 0 ) {
  531. foreach($del_file as $att_idx) {
  532. $this->attach_remove($att_idx);
  533. }
  534. }
  535. // 수정이냐 신규냐에 따른 값 결정
  536. if( empty($post_idx) ) {
  537. $data['reg_user'] = $data['upd_user'];
  538. $data['reg_datetime'] = $data['upd_datetime'];
  539. $data['post_status'] = 'Y';
  540. $data['post_count_comment'] = 0;
  541. $data['post_hit'] = 0;
  542. // 답글일경우
  543. if(! empty( $data['post_parent'] ) ) {
  544. if( strlen($parent['post_reply']) >= 10 )
  545. {
  546. alert('더 이상 답변하실 수 없습니다.\\n답변은 10단계 까지만 가능합니다.');
  547. exit;
  548. }
  549. $reply_len = strlen($parent['post_reply']) + 1;
  550. $begin_reply_char = 'A';
  551. $end_reply_char = 'Z';
  552. $reply_number = +1;
  553. $reply_char = "";
  554. $this->CI->db->select("MAX(SUBSTRING(post_reply, {$reply_len}, 1)) AS reply")->from('board_post')->where('post_num', $parent['post_num'])->where('brd_key', $brd_key)->where("SUBSTRING(post_reply, {$reply_len}, 1) <>", '');
  555. if($parent['post_reply']) $this->CI->db->like('post_reply', $parent['post_reply'],'after');
  556. $row = $this->CI->db->get()->row_array();
  557. if(! $row['reply']) {
  558. $reply_char = $begin_reply_char;
  559. }
  560. else if ($row['reply'] == $end_reply_char) {
  561. alert("더 이상 답변하실 수 없습니다.\\n답변은 26개 까지만 가능합니다.");
  562. exit;
  563. }
  564. else {
  565. $reply_char = chr(ord($row['reply']) + $reply_number);
  566. }
  567. $data['post_reply'] = $parent['post_reply'] . $reply_char;
  568. // 답변의 원글이 비밀글이라면, 비밀번호는 원글과 동일하게 넣는다.
  569. if( $parent['post_secret'] == 'Y' ) {
  570. $data['post_password'] = $parent['post_password'];
  571. }
  572. $data['post_num'] = $parent['post_num'];
  573. }
  574. else {
  575. $tmp = (int)$this->CI->db->select_max('post_num','max')->from('board_post')->where('brd_key',$brd_key)->get()->row(0)->max;
  576. $data['post_reply'] = "";
  577. $data['post_num'] = $tmp+1;
  578. }
  579. if(! $this->CI->db->insert('board_post', $data) ) {
  580. alert(langs('게시판/msg/write_failed'));
  581. exit;
  582. }
  583. $post_idx = $this->CI->db->insert_id();
  584. }
  585. else {
  586. $this->CI->db->where('brd_key', $brd_key)->where('post_idx', $post_idx);
  587. if(! $this->CI->db->update('board_post', $data))
  588. {
  589. alert(langs('게시판/msg/write_failed'));
  590. exit;
  591. }
  592. }
  593. // 업로드된 데이타가 있을경우에 DB에 기록
  594. if(isset($upload_array) && count($upload_array) >0 )
  595. {
  596. foreach($upload_array as &$arr) {
  597. $arr['att_target'] = $post_idx;
  598. }
  599. $this->CI->db->insert_batch("attach", $upload_array);
  600. }
  601. // 게시글의 대표 이미지를 가져온다.
  602. $attach_list = $this->get_attach_list($data['brd_key'], $post_idx);
  603. if ( count($attach_list) > 0 ) {
  604. foreach($attach_list as $row) {
  605. if($row['att_is_image'] == 'Y') {
  606. $data['post_thumbnail'] = base_url($row['att_filepath']);
  607. break;
  608. }
  609. }
  610. }
  611. // 첨부파일중에 없다면 HTML 코드에서 이미지를 찾아낸다.
  612. if( empty($data['post_thumbnail']) ) {
  613. $matches = get_editor_image($data['post_content']);
  614. if(! empty($matches)) {
  615. $img = element(0, element(1, $matches));
  616. if(! empty($img)) {
  617. preg_match("/src=[\'\"]?([^>\'\"]+[^>\'\"]+)/i", $img, $m);
  618. $src = isset($m[1]) ? $m[1] : '';
  619. if(! empty($src)) {
  620. $data['post_thumbnail'] = str_replace(base_url()."/", "", $src);
  621. }
  622. }
  623. }
  624. }
  625. $matches = null;
  626. // 거기서도 없으면 본문내용에 포함된 iframe 동영상에서..
  627. if( empty($data['post_thumbnail']) ) {
  628. preg_match_all("/<iframe[^>]*src=[\'\"]?([^>\'\"]+[^>\'\"]+)[\'\"]?[^>]*>/i", $data['post_content'], $matches);
  629. for ($i = 0; $i < count($matches[1]); $i++) {
  630. if (!isset($matches[1][$i])) continue;
  631. $video = get_video_info($matches[1][$i]);
  632. // 비디오 타입이 아니거나, 알려지지 않은 비디오 일경우 건너뛴다.
  633. if (!$video['type'] OR !$video['thumb']) continue;
  634. if ($video['thumb']) {
  635. $data['post_thumbnail'] = $video['thumb'];
  636. }
  637. }
  638. }
  639. // 그래도 없으면 embed 태그 포함여부 확인해서..
  640. $matches = null;
  641. if( empty($data['post_thumbnail']) ) {
  642. preg_match_all("/<embed[^>]*src=[\'\"]?([^>\'\"]+[^>\'\"]+)[\'\"]?[^>]*>/i", $data['post_content'], $matches);
  643. for($i=0; $i<count($matches[1]); $i++) {
  644. if(! isset($matches[1][$i]) ) continue;
  645. $video = get_video_info( $matches[1][$i] );
  646. // 비디오 타입이 아니거나, 알려지지 않은 비디오 일경우 건너뛴다.
  647. if(! $video['type'] OR ! $video['thumb']) continue;
  648. if($video['thumb']) {
  649. $data['post_thumbnail'] = $video['thumb'];
  650. }
  651. }
  652. }
  653. $this->CI->db->where('post_idx', $post_idx)->set('post_thumbnail', $data['post_thumbnail'])->update('board_post');
  654. // 자신의 글은 비밀글이더라도 바로 보거나, 아니면 수정/삭제를 할수 있도록 세션처리
  655. if($this->CI->member->is_login() ) {
  656. if( ! PAGE_ADMIN && ! $this->CI->member->is_super() )
  657. {
  658. $this->point_process('brd_point_write', "POST_WRITE", "게시글 등록", $post_idx, FALSE);
  659. }
  660. } else {
  661. $this->CI->session->set_userdata('post_password_'.$post_idx, TRUE);
  662. }
  663. // 이동할 페이지 정의
  664. $reurl = PAGE_ADMIN ? base_url("admin/board/read/{$brd_key}/{$post_idx}") : base_url("board/{$brd_key}/{$post_idx}");
  665. alert(langs('게시판/msg/write_success'), $reurl);
  666. exit;
  667. }
  668. else
  669. {
  670. $this->CI->data['post_idx'] = (int)$post_idx;
  671. $this->CI->data['post_parent'] = $this->CI->input->get('post_parent', TRUE);
  672. $this->CI->data['view'] = empty($post_idx) ? array() : $this->get_post($brd_key, $post_idx, FALSE);
  673. $this->CI->data['parent'] = empty($this->CI->data['post_parent']) ? array() : $this->get_post($brd_key, $this->CI->data['post_parent'], FALSE);
  674. if( $this->CI->data['post_idx'] && (! $this->CI->data['view'] OR ! isset($this->CI->data['view']['post_idx']) OR !$this->CI->data['view']['post_idx'] ) )
  675. {
  676. alert(langs('게시판/msg/invalid_access'));
  677. exit;
  678. }
  679. $hidden = array();
  680. // 답글작성일경우 부모 번호 넘겨주기
  681. // 카테고리도 같은 카테고리로
  682. if($this->CI->data['post_parent']) {
  683. $hidden['post_parent'] = $this->CI->data['post_parent'];
  684. $this->CI->data['view']['post_title'] = "RE : ". $this->CI->data['parent']['post_title'];
  685. $this->CI->data['view']['post_category'] = $this->CI->data['parent']['post_category'];
  686. }
  687. $write_url = PAGE_ADMIN ? base_url("admin/board/write/{$brd_key}/{$post_idx}") : base_url("board/{$brd_key}/write/{$post_idx}");
  688. $this->CI->data['form_open'] = form_open_multipart($write_url, array("autocomplete"=>"off","data-form"=>"post","id"=>"form-post"), $hidden);
  689. $this->CI->data['form_close'] = form_close();
  690. $this->CI->view = PAGE_ADMIN ? "board/write" : "write";
  691. $this->CI->theme = PAGE_ADMIN ? "admin" : $this->CI->site->get_layout();
  692. $this->CI->active = "board/{$brd_key}";
  693. if(! PAGE_ADMIN) {
  694. $this->CI->site->meta_title = $this->CI->data['board']['brd_title'] . ' - '. ((empty($post_idx)) ? '새 글 작성' : '글 수정'); // 이 페이지의 타이틀
  695. $this->CI->site->meta_description = $this->CI->data['board']['brd_description']; // 이 페이지의 요약 설명
  696. $this->CI->site->meta_keywords = $this->CI->data['board']['brd_keywords']; // 이 페이지에서 추가할 키워드 메타 태그
  697. $this->CI->site->meta_image = ""; // 이 페이지에서 표시할 대표이미지
  698. $this->CI->skin_type = "board/write";
  699. $this->CI->skin = $this->CI->data['board']['brd_skin_w'];
  700. }
  701. }
  702. }
  703. /**
  704. * 게시글 읽기 처리
  705. */
  706. function read_process($brd_key, $post_idx)
  707. {
  708. $this->CI->data['view'] = $this->get_post($brd_key, $post_idx, FALSE);
  709. if(! in_array( $this->CI->data['view']['post_status'], array("Y","B")))
  710. {
  711. alert(langs('게시판/msg/invalid_post'));
  712. exit;
  713. }
  714. // 비밀글일 경우 처리
  715. if( $this->CI->data['view']['post_secret'] == 'Y' )
  716. {
  717. $is_auth = FALSE;
  718. if( PAGE_ADMIN OR $this->CI->member->is_super() )
  719. {
  720. $is_auth = TRUE;
  721. }
  722. if( !empty($this->CI->data['view']['reg_user']) && $this->CI->data['view']['reg_user'] == $this->CI->member->info('idx') )
  723. {
  724. $is_auth = TRUE;
  725. }
  726. // 해당 글이 답글일 경우
  727. if( strlen($this->CI->data['view']['post_reply']) > 0 && $this->CI->member->is_login())
  728. {
  729. // 원글중에 작성자가 있는경우 글을 볼 권한이 있다!
  730. $tmp = $this->CI->db->where('post_num', $this->CI->data['view']['post_num'])->where('brd_key', $brd_key)->get('board_post')->result_array();
  731. foreach($tmp as $t)
  732. {
  733. if( $t['reg_user'] && $t['reg_user'] == $this->CI->member->info('idx') )
  734. {
  735. $is_auth = TRUE;
  736. break;
  737. }
  738. }
  739. }
  740. // 이 과정을 전부했는데도 권한이 없으면 비밀번호 확인
  741. if(! $is_auth)
  742. {
  743. if( ! $this->CI->session->userdata('post_password_'.$post_idx) )
  744. {
  745. redirect(base_url("board/{$brd_key}/password/{$post_idx}?w=s&reurl=".current_full_url()));
  746. }
  747. }
  748. }
  749. // 게시판 조회수 상승
  750. if( ! PAGE_ADMIN ) {
  751. if( ! $this->CI->session->userdata('post_hit_'.$post_idx) OR (int)$this->CI->session->userdata('post_hit_'.$post_idx) + 60*60*24 < time() )
  752. {
  753. $this->CI->db->where('post_idx', $post_idx)->set('post_hit', 'post_hit+1', FALSE)->update('board_post');
  754. $this->CI->data['view']['post_hit'] += 1;
  755. $this->CI->session->set_userdata('post_hit_'.$post_idx, time());
  756. }
  757. // 포인트 관련 프로세스
  758. $this->point_process('brd_point_read', 'POST_READ', '게시글 읽기', $post_idx, ($this->CI->data['view']['reg_user'] == $this->CI->member->info('idx')) );
  759. // 메타태그 설정
  760. $this->CI->site->meta_title = $this->CI->data['view']['post_title'] . ' - ' . $this->CI->data['board']['brd_title']; // 이 페이지의 타이틀
  761. $this->CI->site->meta_description = cut_str(get_summary($this->CI->data['view']['post_content'],FALSE),80); // 이 페이지의 요약 설명
  762. $this->CI->site->meta_keywords = $this->CI->data['view']['post_keywords']; // 이 페이지에서 추가할 키워드 메타 태그
  763. $this->CI->site->meta_image = $this->CI->data['view']['post_thumbnail']; // 이 페이지에서 표시할 대표이미지
  764. }
  765. // 링크 만들기
  766. $this->CI->data['board']['link']['reply'] = PAGE_ADMIN ? base_url("admin/board/write/{$brd_key}/?post_parent={$post_idx}") : base_url("board/{$brd_key}/write/?post_parent={$post_idx}");
  767. $this->CI->data['board']['link']['modify'] = PAGE_ADMIN ? base_url("admin/board/write/{$brd_key}/{$post_idx}") : base_url("board/{$brd_key}/write/{$post_idx}");
  768. $this->CI->data['board']['link']['delete'] = PAGE_ADMIN ? '': base_url("board/{$brd_key}/delete/{$post_idx}");
  769. // 댓글 입력폼
  770. $write_skin_path = DIR_SKIN . "/board/comment/" . $this->CI->data['board']['brd_skin_c'] . "/c_write";
  771. $comment_hidden = array("reurl"=>current_full_url(),"cmt_idx"=>"","cmt_parent"=>"");
  772. $comment_action_url = PAGE_ADMIN ? base_url("admin/board/comment/{$brd_key}/{$post_idx}") : base_url( "board/{$brd_key}/comment/{$post_idx}");
  773. $tmp['comment_view'] = array();
  774. $tmp['comment_form_open'] = form_open($comment_action_url,array("id"=>"form-board-comment","data-form"=>"board-comment"), $comment_hidden);
  775. $tmp['comment_form_close'] = form_close();
  776. $this->CI->data['comment_write'] = $this->CI->data['board']['brd_use_comment'] == 'Y' && $this->CI->data['board']['auth']['comment'] ? $this->CI->load->view($write_skin_path, $tmp, TRUE) : NULL;
  777. // 댓글 목록
  778. $list_skin_path = DIR_SKIN . "/board/comment/" . $this->CI->data['board']['brd_skin_c'] . "/c_list";
  779. $this->CI->data['comment_list'] = array();
  780. if( $this->CI->data['board']['brd_use_comment'] == 'Y' )
  781. {
  782. $mem_useridx = $this->CI->member->is_login();
  783. $this->CI->data['comment_list'] = $this->comment_list($brd_key, $post_idx, $this->CI->data['board']['auth']['admin'], $mem_useridx);
  784. // 각 댓글마다 대댓글 폼을 만든다.
  785. foreach($this->CI->data['comment_list']['list'] as &$row)
  786. {
  787. unset($tmp);
  788. $row['comment_form'] = "";
  789. if(strlen($row['cmt_reply']) < 5)
  790. {
  791. $comment_hidden = array("reurl"=>current_full_url(),"cmt_idx"=>"","cmt_parent"=>$row['cmt_idx']);
  792. $tmp['comment_view'] = array();
  793. $tmp['comment_form_open'] = form_open($comment_action_url, array("data-form"=>"board-comment"), $comment_hidden);
  794. $tmp['comment_form_close'] = form_close();
  795. $row['comment_form'] = $this->CI->data['board']['brd_use_comment'] == 'Y' && $this->CI->data['board']['auth']['comment'] ? $this->CI->load->view($write_skin_path, $tmp, TRUE) : NULL;
  796. }
  797. }
  798. }
  799. $tmp2['board'] = $this->CI->data['board'];
  800. $this->CI->data['comments'] = $this->CI->data['comment_list'];
  801. $tmp2['comment_list'] = $this->CI->data['comment_list'];
  802. $this->CI->data['comment_list'] = $this->CI->data['board']['brd_use_comment'] == 'Y' ? $this->CI->load->view($list_skin_path, $tmp2, TRUE) : NULL;
  803. $this->CI->view = PAGE_ADMIN ? "board/read" : "view";
  804. $this->CI->active = "board/" . $brd_key;
  805. $this->CI->theme = PAGE_ADMIN ? "admin" : $this->CI->site->get_layout();
  806. if(! PAGE_ADMIN) {
  807. $this->CI->skin_type = "board/view";
  808. $this->CI->skin = $this->CI->data['board']['brd_skin_v'];
  809. }
  810. }
  811. /**
  812. * 댓글 입력 처리
  813. */
  814. function comment_process($brd_key, $post_idx)
  815. {
  816. $this->CI->load->library('form_validation');
  817. $this->CI->form_validation->set_rules('cmt_content', langs('게시판/comment/form_content'), 'trim|required');
  818. if( empty($brd_key) OR empty($post_idx) )
  819. {
  820. alert(langs('게시판/msg/invalid_access'));
  821. exit;
  822. }
  823. $data['brd_key'] = $brd_key;
  824. $data['post_idx'] = $post_idx;
  825. $data['cmt_idx'] = $this->CI->input->post('cmt_idx', TRUE);
  826. $data['cmt_parent'] = $this->CI->input->post('cmt_parent', TRUE, 0);
  827. $data['cmt_content'] = $this->CI->input->post('cmt_content', FALSE);
  828. $data['upd_user'] = $this->CI->member->is_login();
  829. $data['cmt_password'] = ( $this->CI->member->is_login() ) ? $this->CI->member->info('password') : get_password_hash( $this->CI->input->post('cmt_password', FALSE) );
  830. $data['cmt_nickname'] = ( $this->CI->member->is_login() ) ? $this->CI->member->info('nickname') : $this->CI->input->post('cmt_nickname');
  831. $data['upd_datetime'] = date('Y-m-d H:i:s');
  832. $data['cmt_ip'] = ip2long( $this->CI->input->ip_address() );
  833. $data['cmt_status'] = 'Y';
  834. $data['cmt_mobile'] = $this->CI->site->viewmode == DEVICE_MOBILE ? 'Y' : 'N';
  835. $base_reurl = PAGE_ADMIN ? base_url("admin/board/read/{$brd_key}/{$post_idx}") : base_url("board/{$brd_key}/{$post_idx}");
  836. $reurl = $this->CI->input->post('reurl', TRUE, $base_reurl );
  837. // 값 유효성 체크
  838. if( empty($data['cmt_content']) )
  839. {
  840. alert(langs('게시판/comment/content_required'));
  841. exit;
  842. }
  843. if( empty($data['cmt_nickname']) )
  844. {
  845. alert(langs('게시판/comment/nickname_required'));
  846. exit;
  847. }
  848. if( empty($data['cmt_password']) )
  849. {
  850. alert(langs('게시판/comment/password_required'));
  851. exit;
  852. }
  853. // 신규 등록일 경우
  854. if( empty($data['cmt_idx']) ) {
  855. $data['reg_datetime'] = $data['upd_datetime'];
  856. $data['reg_user'] = $data['upd_user'];
  857. if(! empty($data['cmt_parent'])) {
  858. $parent = $this->CI->db->where('cmt_idx', $data['cmt_parent'])->where_in('cmt_status', array('Y','B'))->where('post_idx', $data['post_idx'])->get('board_comment')->row_array();
  859. if(! $parent OR !isset($parent['cmt_idx']) OR ! $parent['cmt_idx']) {
  860. alert('답변할 댓글이 없습니다.\\n답변하는 동안 댓글이 삭제되었을 수 있습니다.');
  861. exit;
  862. }
  863. if($parent['post_idx'] != $data['post_idx']) {
  864. alert('댓글을 등록할 수 없습니다.\\n잘못된 방법으로 등록을 요청하였습니다.');
  865. exit;
  866. }
  867. if(strlen($parent['cmt_reply']) >= 5) {
  868. alert('더이상 답변을 달수 없습니다.\\n\\n답변은 5단계 까지만 가능합니다.');
  869. exit;
  870. }
  871. $reply_len = strlen($parent['cmt_reply']) + 1;
  872. $begin_reply_char = 'A';
  873. $end_reply_char = 'Z';
  874. $reply_number = +1;
  875. $this->CI->db->select("MAX(SUBSTRING(cmt_reply, {$reply_len}, 1)) AS reply")->from('board_comment')->where('cmt_num', $parent['cmt_num'])->where('post_idx', $data['post_idx'])->where("SUBSTRING(cmt_reply, {$reply_len}, 1) <>", '');
  876. if($parent['cmt_reply']) $this->CI->db->like('cmt_reply', $parent['cmt_reply'],'after');
  877. $row = $this->CI->db->get()->row_array();
  878. $reply_char ="";
  879. if(!$row['reply']) $reply_char = $begin_reply_char;
  880. else if ($row['reply'] == $end_reply_char) {
  881. alert('더이상 답변을 달수 없습니다.\\n\\n답변은 26개까지만 가능합니다.');
  882. exit;
  883. }
  884. else $reply_char = chr(ord($row['reply']) + $reply_number);
  885. $data['cmt_reply'] = $parent['cmt_reply'] . $reply_char;
  886. $data['cmt_num'] = $parent['cmt_num'];
  887. } else {
  888. $tmp = (int)$this->CI->db->select_max('cmt_num','max')->from('board_comment')->where('post_idx',$data['post_idx'])->get()->row(0)->max;
  889. $data['cmt_reply'] = "";
  890. $data['cmt_num'] = $tmp+1;
  891. }
  892. if( $this->CI->db->insert('board_comment', $data) )
  893. {
  894. // 대댓글을 위한 정보입력
  895. $cmt_idx = $this->CI->db->insert_id();
  896. // 포인트 입력처리
  897. $this->point_process('brd_point_comment', "CMT_WRITE", "댓글 등록", $cmt_idx, FALSE);
  898. $this->update_post_comment_count($brd_key, $post_idx);
  899. alert('댓글 작성이 완료되었습니다.', $reurl);
  900. } else {
  901. alert(langs('게시판/msg/comment_failed'));
  902. exit;
  903. }
  904. } else {
  905. // 기존 댓글 정보를 가져온다
  906. $comment = $this->CI->db->where("cmt_idx", $data['cmt_idx'])->where('brd_key', $brd_key)->where('post_idx', $post_idx)->get('board_comment')->row_array();
  907. if( ! $comment || ! isset($comment['cmt_idx']) || $comment['cmt_idx'] != $data['cmt_idx'] )
  908. {
  909. alert(langs('게시판/msg/invalid_comment'));
  910. exit;
  911. }
  912. if( ! PAGE_ADMIN && ! $this->CI->member->is_super() )
  913. {
  914. // 기존 댓글과 수정권한이 있는지 확인한다.
  915. if( ! empty( $comment['reg_user']) )
  916. {
  917. if( $this->CI->member->is_login() )
  918. {
  919. if( $this->CI->member->is_login() != $comment['reg_user'] )
  920. {
  921. alert(langs('게시판/msg/comment_modify_unauthorize'));
  922. exit;
  923. }
  924. }
  925. else
  926. {
  927. alert_login();
  928. exit;
  929. }
  930. }
  931. else
  932. {
  933. if( $data['cmt_password'] != $comment['cmt_password'] )
  934. {
  935. alert(langs('게시판/msg/invalid_password'));
  936. exit;
  937. }
  938. }
  939. }
  940. // 수정일 경우는 바뀌어선 안되는 정보들은 unset
  941. unset($data['brd_key'], $data['post_idx']);
  942. $this->CI->db->where('brd_key', $brd_key)->where('post_idx', $post_idx)->where('cmt_idx', $data['cmt_idx']);
  943. if( $this->CI->db->update('board_comment', $data) )
  944. {
  945. $this->update_post_comment_count($brd_key, $post_idx);
  946. alert_close(langs('게시판/msg/comment_modify_success'), TRUE);
  947. exit;
  948. } else {
  949. alert(langs('게시판/msg/comment_failed'));
  950. exit;
  951. }
  952. }
  953. }
  954. /**
  955. * 댓글 입력폼
  956. */
  957. function comment_modify_form($cmt_idx="", $comment)
  958. {
  959. if( ($result = $this->_check_comment_modify($comment)) !== TRUE )
  960. {
  961. alert_close($result);
  962. exit;
  963. }
  964. $this->CI->site->meta_title = "댓글 수정";
  965. $hidden=array("cmt_nickname"=>$comment['cmt_nickname'],"cmt_idx"=>$comment['cmt_idx'],"cmt_parent"=>$comment['cmt_parent']);
  966. $action_url = PAGE_ADMIN ? base_url("admin/board/comment/{$comment['brd_key']}/{$comment['post_idx']}/{$cmt_idx}"): base_url('board/'.$comment['brd_key'].'/comment/'.$comment['post_idx'].'/'.$cmt_idx);
  967. $this->CI->data['comment_form_open'] = form_open($action_url, array("id"=>"form-board-comment","data-form"=>"board-comment"), $hidden);
  968. $this->CI->data['comment_form_close'] = form_close();
  969. $this->CI->data['comment_view'] = $comment;
  970. $this->CI->data['is_reply'] = FALSE;
  971. $this->CI->theme = $this->CI->site->get_layout();
  972. $this->CI->theme_file = "popup";
  973. $this->CI->skin_type = "board/comment";
  974. $this->CI->skin = $this->CI->data['board']['brd_skin_c'];
  975. $this->CI->view = "c_write";
  976. }
  977. /**
  978. * 댓글 삭제 처리
  979. */
  980. public function comment_delete_process($brd_key, $post_idx, $cmt_idx)
  981. {
  982. if( ! $comment = $this->CI->db->where('cmt_idx', $cmt_idx)->where('cmt_status', 'Y')->get('board_comment')->row_array() )
  983. {
  984. alert(langs('게시판/msg/invalid_comment'));
  985. exit;
  986. }
  987. // 권한 확인
  988. if( ! PAGE_ADMIN && ! $this->CI->member->is_super() )
  989. {
  990. if( ($result = $this->_check_comment_modify($comment)) !== TRUE )
  991. {
  992. alert($result);
  993. exit;
  994. }
  995. if( empty($comment['reg_user']) )
  996. {
  997. alert(langs('게시판/msg/cannot_delete_guest_comment'));
  998. exit;
  999. }
  1000. }
  1001. // 원본 가져오기
  1002. $original = $this->CI->db->where('cmt_idx', $cmt_idx)->get('board_comment')->row_array();
  1003. if(!$original OR !isset($original['cmt_idx']))
  1004. alert('삭제할 원본 댓글이 없습니다.\\ 이미 삭제되엇거나 존재하지 않는 댓글입니다.');
  1005. // 이 댓글의 하위 댓글이 있는지 확인
  1006. $len = strlen($original['cmt_reply']);
  1007. if ($len < 0) $len = 0;
  1008. $comment_reply = substr($original['cmt_reply'], 0, $len);
  1009. $cnt =
  1010. $this->CI->db
  1011. ->select('COUNT(*) AS cnt')
  1012. ->from('board_comment')
  1013. ->like('cmt_reply', $comment_reply,'after')
  1014. ->where('cmt_idx <>', $cmt_idx)
  1015. ->where('cmt_num', $original['cmt_num'])
  1016. ->where('post_idx', $original['post_idx'])
  1017. ->where('cmt_status', 'Y')
  1018. ->where('cmt_parent', $cmt_idx)
  1019. ->get()->row(0)->cnt;
  1020. if($cnt > 0)
  1021. alert('삭제하려는 댓글에 답변이 달려있어 삭제할 수 없습니다.');
  1022. if( $this->CI->db->where('brd_key', $brd_key)->where('post_idx', $post_idx)->where('cmt_idx', $cmt_idx)->set('cmt_status', 'N')->update('board_comment') )
  1023. {
  1024. $this->update_post_comment_count($brd_key, $post_idx);
  1025. // 댓글등록으로 증가한 포인트가 있다면 다시 감소
  1026. $this->point_cancel("CMT_WRITE",$cmt_idx, "댓글삭제");
  1027. alert(langs('게시판/msg/comment_delete_success'));
  1028. exit;
  1029. }
  1030. }
  1031. /**
  1032. * 코멘트 수정/삭제 권한 확인
  1033. * @param $comment
  1034. * @return bool
  1035. */
  1036. public function _check_comment_modify($comment)
  1037. {
  1038. if( PAGE_ADMIN OR $this->CI->member->is_super() ) return TRUE;
  1039. // 댓글 수정/삭제 권한 확인
  1040. if( $comment['reg_user'] && ! $this->CI->member->is_login() )
  1041. {
  1042. return langs('게시판/msg/comment_modify_unauthorize');
  1043. }
  1044. else if ( $comment['reg_user'] && $this->CI->member->is_login() && $this->CI->member->is_login() != $comment['reg_user'])
  1045. {
  1046. return langs('게시판/msg/comment_modify_unauthorize');
  1047. }
  1048. return TRUE;
  1049. }
  1050. /**
  1051. * 수정이나 삭제 권한을 확인한다.
  1052. */
  1053. private function _check_modify_auth($brd_key, $post_idx="")
  1054. {
  1055. if(empty($post_idx)) return;
  1056. if(PAGE_ADMIN) return; // 관리자 페이지일 경우도 리턴
  1057. $post = $this->get_post($brd_key, $post_idx, FALSE);
  1058. if( $this->CI->member->is_super()) return; // 관리자일경우 체크하지 않는다.
  1059. if(! empty($post['reg_user']) )
  1060. {
  1061. if( ! $this->CI->member->is_login() )
  1062. {
  1063. alert_login( langs('게시판/msg/modify_require_login') );
  1064. exit;
  1065. }
  1066. else if ( $post['reg_user'] != $this->CI->member->info('idx') )
  1067. {
  1068. alert(langs('게시판/msg/modify_unauthorize'));
  1069. exit;
  1070. }
  1071. }
  1072. else
  1073. {
  1074. if(! $this->CI->session->userdata('post_password_'.$post_idx))
  1075. {
  1076. redirect(base_url("board/{$brd_key}/password/{$post_idx}?reurl=".current_full_url()));
  1077. }
  1078. }
  1079. }
  1080. /**********************************************************
  1081. * 첨부파일 삭제
  1082. * @param $bfi_idx
  1083. * @return mixed
  1084. *********************************************************/
  1085. function attach_remove($att_idx)
  1086. {
  1087. if(empty($att_idx)) return false;
  1088. $this->CI->db->where("att_idx", $att_idx);
  1089. $result = $this->CI->db->get('attach');
  1090. $attach = $result->row_array();
  1091. if(! $attach) return false;
  1092. if( file_exists(FCPATH. $attach['att_filepath']) )
  1093. {
  1094. @unlink(FCPATH.$attach['att_filepath']);
  1095. }
  1096. $this->CI->db->where("att_idx", $att_idx);
  1097. $this->CI->db->delete("attach");
  1098. }
  1099. /**
  1100. * 게시판에 관련된 포인트를 처리합니다.
  1101. * @param $type
  1102. * @param $mpo_type
  1103. * @param $msg
  1104. * @param $target_idx
  1105. */
  1106. public function point_process($type, $mpo_type, $msg, $target_idx, $check_writer=FALSE)
  1107. {
  1108. // 첨부파일 다운시 필요한 포인트가 있다면 확인
  1109. if( $this->CI->data['board'][$type] != 0 )
  1110. {
  1111. // 회원일 경우만 실행한다.
  1112. if( $this->CI->member->is_login() )
  1113. {
  1114. // 본인의 것은 실행하지 않는다.
  1115. if( ! $check_writer )
  1116. {
  1117. // 이미 처리된 포인트 내역이 있는지 확인한다. (포인트는 한번만 차감/등록한다.)
  1118. $res = (int) $this->CI->db->select('COUNT(*) as cnt')->where('target_type', $mpo_type)->where('target_idx', $target_idx)->where('mem_idx', $this->CI->member->is_login())->get('member_point')->row(0)->cnt;
  1119. if( $res <= 0)
  1120. {
  1121. // 포인트 차감일 경우, 해당 포인트가 있는지 확인한다
  1122. if( (int)$this->CI->data['board'][$type] != 0)
  1123. {
  1124. if( $this->CI->data['board'][$type."_flag"] > 0) {
  1125. // 포인트 상승일 경우 처리
  1126. } else {
  1127. // 포인트 감소일 경우 회원에게 남은 포인트가 있는지 확인한다.
  1128. if( (int)$this->CI->member->info('point') < (int)$this->CI->data['board'][$type] )
  1129. {
  1130. alert(langs('회원/point/not_enough') . "({$this->CI->data['board'][$type]})");
  1131. exit;
  1132. }
  1133. }
  1134. }
  1135. // 포인트 실제 처리
  1136. $this->CI->member->add_point($this->CI->member->is_login(),$this->CI->data['board'][$type."_flag"], $this->CI->data['board'][$type], FALSE, $mpo_type, $msg, $target_idx);
  1137. }
  1138. }
  1139. }
  1140. // 비회원일 경우 아예 실행이 불가능하다.
  1141. else
  1142. {
  1143. alert(langs('공통/msg/login_required'));
  1144. exit;
  1145. }
  1146. }
  1147. }
  1148. /**
  1149. * 게시판에 관련된 포인트를 삭제등의 행동시 취소합니다.
  1150. * @param $target_type
  1151. * @param $target_idx
  1152. * @param $msg
  1153. */
  1154. public function point_cancel($target_type, $target_idx, $msg)
  1155. {
  1156. // 댓글등록으로 증가한 포인트가 있다면 다시 감소
  1157. // 포인트 입력처리
  1158. if( $this->CI->member->is_login() )
  1159. {
  1160. $ret = $this->CI->db->where('target_type', $target_type)->where('mem_idx', $this->CI->member->is_login() )->where('target_idx', $target_idx)->where('mpo_value !=','0')->get('member_point')->row_array();
  1161. if( $ret && isset($ret['mpo_value']) && $ret['mpo_value'] != 0 )
  1162. {
  1163. $this->CI->member->add_point($this->CI->member->is_login(),$ret['mpo_flag']*-1, $ret['mpo_value'], FALSE, $target_type, $msg, $target_idx);
  1164. }
  1165. }
  1166. }
  1167. /**
  1168. * 해당 게시글의 코멘트가 몇개인지 확인한다.
  1169. * @param $brd_key
  1170. * @param $post_idx
  1171. */
  1172. function get_comment_count($brd_key, $post_idx)
  1173. {
  1174. $count = (int)$this->CI->db->select('COUNT(*) AS cnt')->from('board_comment')->where_in('cmt_status', array('Y','B'))->where('brd_key',$brd_key)->where('post_idx',$post_idx)->get()->row(0)->cnt;
  1175. return $count;
  1176. }
  1177. /**
  1178. * 해당 게시물의 댓글수를 최신화 한다
  1179. * @param $brd_key
  1180. * @param $post_idx
  1181. */
  1182. function update_post_comment_count($brd_key, $post_idx)
  1183. {
  1184. $count = $this->get_comment_count($brd_key, $post_idx);
  1185. $this->CI->db->where('brd_key', $brd_key)->where('post_idx', $post_idx)->set('post_count_comment', (int)$count);
  1186. return $this->CI->db->update('board_post');
  1187. }
  1188. }