※ 보안적 요소는 거의 고려하지 않고 php명령어 숙달용으로 혼자서 만드는 로그인 페이지 입니다.
▶게시판 페이지를 위해 만들어야 할 파일 (※이번 시간에 만들파일은 굵은 글씨로 표기)
db.php : 데이터베이스 연결파일
index.php : 게시판 홈 화면
search_result.php : 게시글 검색 화면
board_read.php : 게시글 읽는 페이지
board_modify.php : 게시글 수정&생성 페이지
modify_check.php : 게시글 수정&생성 처리 페이지
thumb_check.php : 좋아요 기능 처리 페이지
▶말하기 앞서
내가 예시로 보여주는 홈페이지 사진(내가 완성한 페이지 사진)은 Bootstrap으로 미적 요소를 많이 가미한 결과이므로, 현재 자신의 페이지가 빠진게 많아보여도 그게 정상이다(바로 전에 포스팅한 게시판 페이지 참조). 내가 미적요소를 가미하는 부분은 추후에 Bootstrap 설명을 할 때, 어떤식으로 했는지 부연설명을 하도록 하겠다.
▶게시글 읽는 페이지 구상
개인적으로 제일 구상할게 많은 부분이라 생각한다. 기본적으로 제목, 작성자, 작성날짜, 조회수, 추천수를 보여줘야 할 것이며, 우리가 만들 페이지의 요구사항 상당부분이 여기와 연결된다. 요구사항 중 여기서 연결하거나 해결해야할 부분을 생각해보면,
[1] 게시글 보기 : 당연히 있어야 하는 기능이다. 게시글 읽는 페이지의 본질이기 때문에 절대 빠뜨리면 안되는 항목이다.
[2] 게시글 수정 : 게시글 수정은 게시글에 들어간 뒤에 수정버튼을 누르면 수정페이지로 넘어갈 수 있게끔 구상했다.
[3] 게시글 삭제 : 게시글 삭제도 게시글에 들어간 뒤에 삭제버튼을 누르면 삭제처리 페이지로 넘어갈 수 있게끔 구상했다. 단, 2번과 3번 기능은 작성자 권한이 있어야 처리할 수 있게끔 한다.(그렇게 하지 않으면 내 게시글을 아무나 수정, 삭제할 수 있기 때문이다.)
[4] 게시글 내 파일 다운로드 기능 : 우리가 만들 페이지의 요구사항에는 게시글 내 파일 업로드/다운로드 기능이 있다. 우리가 떠올릴 수 있는 일반적인 홈페이지를 생각해보면 대다수가 게시글 안에서 파일을 다운로드 가능하게 만들어놓고 있다. 따라서, 여기서 구현해야 함이 당연하다. 파일 업로드 기능은 게시글 생성 파일 설명하면서 자세히 설명하도록 하겠다.
[5] 조회수 갱신 기능 : 게시글을 들어올 때마다 조회수가 1씩 올라가게 구상한다. 쿼리문으로 hit column의 값을 1씩 증가시키는 방법을 사용했다.(자세한 내용은 후술)
[6] 추천기능 (좋아요/좋아요 취소) : 추천기능도 우리가 만들 페이지의 요구사항에 있다. 이 기능을 구상하는게 제일 머리아픈 단계라고 생각한다. 나같은 경우에는 구상할 방법은 많은데 복잡하지만 적은 용량을 쓰는 방법과 간편한 방법 중에서 선택을 해야했고, 결국 후자를 선택했다. (그 과정은 추천기능을 설명할 때 후술하도록 하겠다.). 일단은 추천버튼만 구현하면 되니깐 과정까지는 나중에 생각해보도록 하자.
이번글은 설명할 항목이 많으므로, 위에서 나열한 요구사항들의 순서대로 어떻게 구현했는지 설명하는 방식으로 진행하도록 하겠다.
▶게시글 보기(board_read.php)
구상하기 쉽다. 그냥 게시글이 정상적으로 출력해야될 정보만 출력하게 구상하면 된다. 오히려 나중에 여기서 Bootstrap처리하는게 더 어렵다. 나같은 경우, 웹 프로그래밍 경험이 별로 없어서 div로 구역을 나누지 않고 구상했는데(<br>, <a>, <h1> 태그 사용), div로 구역을 미리 나누면서 진행해야 나중에 Bootstrap 쓸 때 손이 덜 간다.
나같은 경우, 제목을 크게 출력하고, 아래에 작은 글씨로 "이름 | 날짜 | 조회수 | 추천수"를 출력하며, 아래에는 중간 크기의 글씨로 본문내용을 출력하며, 그 아래에 첨부파일란, 그 아래에 조그만한 글씨로 우측에 목록, 수정, 삭제 버튼을 만들고 좌측에는 추천버튼을 구상했다. (자세한 내용은 아래에 설명)
다만, 게시글을 만들다보면 여러가지 버그들이 발생하는데(예를 들면, 권한이 없는데 삭제가 된다거나, 데이터가 존재하지 않는데 접속을 시도하다가 페이지가 죽어버린다거나), 이를 해결하기 위해서 나는 몇몇 코드를 추가했다. 그 결과 주요한 코드들의 구성은 다음과 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
<?php
// 해당 id로 row 호출
$id = $_GET['idx'];
$usr_id = $_SESSION['ss_jj_id'];
$sql = "SELECT * FROM board WHERE idx='$id'";
$res = mysqli_query($conn1, $sql);
$board = mysqli_fetch_array($res);
// 좋아요 데이터 호출
//좋아요 수
$sql2 = "SELECT * FROM thumbs WHERE board_idx='$id'";
//좋아요 사용자 데이터
$sql3 = "SELECT * FROM thumbs WHERE lk_id = '$usr_id' and board_idx = '$id'";
$lik_res = mysqli_query($conn1, $sql2);
$usr_info = mysqli_query($conn1, $sql3);
$thumbs = mysqli_fetch_array($lik_res);
// 데이터 존재 검열
if(mysqli_num_rows($res)<1) {
echo "<script>alert('존재하지 않는 글입니다.');</script>";
echo "<script>location.replace('./index.php');</script>";
exit;
} else {
// 조회수 갱신
$hit = $board['hit'] + 1;
$upd = "UPDATE board SET hit='".$hit."' WHERE idx='".$id."'";
$hit_up = mysqli_query($conn1, $upd);
} ?>
<div class="container">
<div class="col-lg-12 mt-5">
<div class="page-header">
<h1 id="title"><?=$board['title'];?></h1>
<small id="title"><?=$board['name'];?> | <?=$board['date'];?> | 조회수 : <?=$board['hit'];?> | 추천수 : <?=mysqli_num_rows($usr_info);?></small>
</div>
</div>
<hr color="black">
<div class="col-lg-12 mt-5 mb-5">
<div class="bs-component fs-3">
<p><?=nl2br("$board[content]"); ?></p>
</div>
</div>
<hr color="black">
<!-- 첨부파일 -->
<div>
첨부파일 : <a href="./upload_file/<?php echo $board['file'];?>" download><?php echo $board['file']; ?></a>
</div>
<hr color="black">
<!-- 목록, 수정, 삭제 -->
<!-- 좋아요 입력란 -->
<div class="row">
<!-- 좋아요를 이미 눌렀을 경우-->
<div class="col-md-9">
<form action='./thumbs_check.php' method='get'><input type='hidden' name='id' value='<?=$id?>'>
<?php if (mysqli_num_rows($usr_info)>0) {
echo "<button type='submit' class='btn btn-dark'>추천취소 <svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-heart-fill' viewBox='0 0 16 16'>
<path fill-rule='evenodd' d='M8 1.314C12.438-3.248 23.534 4.735 8 15-7.534 4.736 3.562-3.248 8 1.314z'/>
</svg></button></form>";
// 좋아요를 아직 안눌렀을 경우
} else {
echo "<button type='submit' class='btn btn-dark'>추천하기<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-heart' viewBox='0 0 16 16'>
<path d='m8 2.748-.717-.737C5.6.281 2.514.878 1.4 3.053c-.523 1.023-.641 2.5.314 4.385.92 1.815 2.834 3.989 6.286 6.357 3.452-2.368 5.365-4.542 6.286-6.357.955-1.886.838-3.362.314-4.385C13.486.878 10.4.28 8.717 2.01L8 2.748zM8 15C-7.333 4.868 3.279-3.04 7.824 1.143c.06.055.119.112.176.171a3.12 3.12 0 0 1 .176-.17C12.72-3.042 23.333 4.867 8 15z'/>
</svg></button></form>";
} ?>
</form>
</div>
<div class="col-md-1 mt-3">
<a href ="./index.php">[목록]</a>
</div>
<div class="col-md-1 mt-3">
<a href ="./board_modify.php?idx=<?php echo $board['idx']; ?>">[수정]</a>
</div>
<div class="col-md-1 mt-3">
<a href ="./board_delete.php?idx=<?php echo $board['idx']; ?>">[삭제]</a>
</div>
|
cs |
얼마 안될줄 알았는데 글 읽는 기능만 구현하는데도 상당히 코드가 길다. 위에서 언급한 요구사항 순서대로 어느 부분인지 설명하도록 하겠다.(div의 class기능은 bootstrap 기능이므로 bootstrap활용을 설명할 때, 설명하도록 함. 또한, 추천과 관련된 사항도 나중에 한번더 설명하도록 함.)
[1] 게시글 보기 : 위 코드 중에서 게시글 추천과 파일다운로드 출력 부분을 제외하면, 게시글 정보를 출력하는 코드부분은 다음밖에 되지 않는다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<?php
// 해당 id로 row 호출
$id = $_GET['idx'];
$usr_id = $_SESSION['ss_jj_id'];
$sql = "SELECT * FROM board WHERE idx='$id'";
$res = mysqli_query($conn1, $sql);
$board = mysqli_fetch_array($res);
?>
<!-- 제목과 아래에 이름,날짜,조회수,추천수 순으로 출력 -->
<div class="col-lg-12 mt-5">
<div class="page-header">
<h1 id="title"><?=$board['title'];?></h1>
<small id="title"><?=$board['name'];?> | <?=$board['date'];?> | 조회수 : <?=$board['hit'];?> | 추천수 : <?=mysqli_num_rows($usr_info);?></small>
</div>
</div>
<!-- 게시글 내용을 출력 -->
<div class="col-lg-12 mt-5 mb-5">
<div class="bs-component fs-3">
<p><?=nl2br("$board[content]"); ?></p>
</div>
|
cs |
각각 우선 id로 row를 호출하는 과정은 특별한 것 없이 간단하다. 바로 전에 게시판 만들기 할 때, GET방식으로 id정보를 전달하게끔 만들었었는데, 그 정보를 받아서 해당 행의 모든 DB를 호출하는 과정이다. mysqli_fetch_array로 나중에 호출하기 쉽도록 array형식으로 변수를 정해놓는다.
다음은 간단하게 h1태그로 제목을 출력하고, 그 아래에는 small 태그를 사용해 작은 글씨로 이름,날짜,조회수,추천수 를 출력한다. (div 태그가 많아서 그렇지 그것만 빼고 보면 그게 다다)
게시글 내용은 nl2br을 이용해서 content를 불러오는데, 이는 개행표시(\n)를 줄바꿈으로 처리해주는 역할을 해준다.
[2] 게시글 수정, [3] 게시글 삭제 (+ 목록기능) : 아래에 간단히 글자를 넣고 링크를 걸어두었다(각각 board_modify.php와 board_delete.php로 연결되게끔 링크를 설정했다.).
1
2
3
4
5
6
7
8
9
|
<div class="col-md-1 mt-3">
<a href ="./index.php">[목록]</a>
</div>
<div class="col-md-1 mt-3">
<a href ="./board_modify.php?idx=<?php echo $board['idx']; ?>">[수정]</a>
</div>
<div class="col-md-1 mt-3">
<a href ="./board_delete.php?idx=<?php echo $board['idx']; ?>">[삭제]</a>
</div>
|
cs |
[4] 게시글 내 파일다운로드 기능 : 이 기능은 파일 업로드/다운로드 기능을 설명해야 이해가 쉽게 되겠지만, 간단히 설명하고 파일 업로드/다운로드 를 설명할 때도 다시 한 번 설명하도록 하겠다.
1
2
3
4
|
<!-- 첨부파일 -->
<div>
첨부파일 : <a href="./upload_file/<?php echo $board['file'];?>" download><?php echo $board['file']; ?></a>
</div>
|
cs |
파일을 다운로드하도록 내가 설정한 폴더 ( 나같은 경우는 게시판을 정리해놓은 폴더 안에 )에서 해당 게시물을 다운로드 받도록 하는 명령어다.
[5] 조회수 갱신 기능 : 우리가 불러온 정보에서 hit 칼럼의 정보만 추려내고, 1을 더한 다음, 다시 칼럼으로 UPDATE 쿼리문을 쏴주면 된다. 구현하기 어려운듯하면서도 의외로 가장 쉬웠던 기능이다. 나같은 경우는 데이터가 존재하는지 확인하는 단계에서 무사히 넘어가면 조회수를 올려주는 식으로 묶어서 구현했다.
1
2
3
4
5
6
7
8
9
10
11
12
|
<?php
// 데이터 존재 검열
if(mysqli_num_rows($res)<1) {
echo "<script>alert('존재하지 않는 글입니다.');</script>";
echo "<script>location.replace('./index.php');</script>";
exit;
} else {
// 조회수 갱신
$hit = $board['hit'] + 1;
$upd = "UPDATE board SET hit='".$hit."' WHERE idx='".$id."'";
$hit_up = mysqli_query($conn1, $upd);
} ?>
|
cs |
[6] 추천기능 (좋아요/좋아요 취소) : 추천을 하지 않았으면 빈하트가 버튼안에 '추천하기' 글자와 함께 출력이, 그 반대의 경우에는 꽉찬하트가 버튼안에 '추천취소'글자와 함께 출력이 되는 기능을 구현했다. 빈하트와 꽉찬하트의 아이콘은 bootstrap 아이콘에서 구할 수 있었다. 원하는 아이콘을 구하면, svg파일 형식으로 다운로드, i태그로 호출, svg코드 입력 등 다양한 방법으로 해당 아이콘을 웹에서 구현할 수 있다. 참고로 나는 svg코드를 직접 입력하는 방식으로 구현했다. 이렇게 구현된 좋아요 버튼의 코드는 다음과 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<form action='./thumbs_check.php' method='get'><input type='hidden' name='id' value='<?=$id?>'>
<?php if (mysqli_num_rows($usr_info)>0) {
// 좋아요를 이미 눌렀을 경우
echo "<button type='submit' class='btn btn-dark'>추천취소 <svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-heart-fill' viewBox='0 0 16 16'>
<path fill-rule='evenodd' d='M8 1.314C12.438-3.248 23.534 4.735 8 15-7.534 4.736 3.562-3.248 8 1.314z'/>
</svg></button></form>";
// 좋아요를 아직 안눌렀을 경우
} else {
echo "<button type='submit' class='btn btn-dark'>추천하기<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-heart' viewBox='0 0 16 16'>
<path d='m8 2.748-.717-.737C5.6.281 2.514.878 1.4 3.053c-.523 1.023-.641 2.5.314 4.385.92 1.815 2.834 3.989 6.286 6.357 3.452-2.368 5.365-4.542 6.286-6.357.955-1.886.838-3.362.314-4.385C13.486.878 10.4.28 8.717 2.01L8 2.748zM8 15C-7.333 4.868 3.279-3.04 7.824 1.143c.06.055.119.112.176.171a3.12 3.12 0 0 1 .176-.17C12.72-3.042 23.333 4.867 8 15z'/>
</svg></button></form>";
} ?>
</form>
|
cs |
복잡해보이는데 진짜 별거없다. 말 그대로 '버튼' 안에 '추천취소or하기' 와 'svg' 를 넣고 이를 상황별로 2개 나눠놓은 것. svg를 저런식으로 붙여넣기 하면 코드가 복잡해지니, 다운받아서 불러오는 방식도 괜찮을 것 같다. 이에 구현된 페이지의 좋아요 버튼을 확인해보면,
추천 유무에 따라, 이렇게 구현됨을 확인해 볼 수 있다.
'Project > project 1 - JH community' 카테고리의 다른 글
[php] 게시판 페이지 5 - 좋아요 기능 처리페이지 만들기 (0) | 2022.11.11 |
---|---|
[php] 게시판 페이지 4 - 게시글 수정&생성 페이지 만들기 (0) | 2022.11.10 |
[php] 게시판 페이지 2 - 게시글 검색 화면 만들기 (0) | 2022.11.07 |
[php] 게시판 페이지 1 - 게시글 홈 화면 만들기 (0) | 2022.11.07 |
[php] 로그인 페이지 3.5 - 주소 검색창 만들기 (0) | 2022.11.05 |
댓글