오늘은 4주차에 진행했던 Web Server 에 이어서 게시판 페이지를 만들어 볼 것이다.
바로 본론으로 들어가기 전, 진행 상황을 다시 떠올려보자.
[ COMPLETED ]
: write 버튼으로 이동한 write_post page에서 사용자가 글을 작성하면 board Table에 저장
: 글 작성을 마친 후, 다시 index page로 돌아가면 board Table에 들어있는 정보로 게시판 구성
[ NEXT ]
: 게시판 목록에 있는 글을 하나 선택하면 해당 POST의 내용을 볼 수 있는 상세 페이지로 이동
: 찾고자 하는 데이터를 입력하면 지정된 카테고리에 한하여 게시물 정렬
: 게시물이 10개 이상 작성되면, 여러 페이지에 걸쳐 게시판 목록 제공 ( 페이징 )
이번 페이지에서는 우선, 페이징 기능부터 구현할 예정이다.
그럼 바로 코드로 넘어가 보자!!
[ index.php ]
Copy <?php
session_start();
if($_SESSION['login_check'] != 1) {
header("location: login.html");
exit;
} else if($_SESSION['login_check'] == 1) {
require_once("jwt.php");
require_once("./db_connect.php");
$usr = getToken($_COOKIE['JWT'])['usr'];
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./css/index.css">
<title>Main page</title>
</head>
<body>
<div class="header">
<p><?php echo $usr;?>님</p>
<button id="mypage_btn">
My Page
</button>
</div>
<div class="container">
<div class="page_title">
BOARD
</div>
<div class="table">
<div class="funcs">
<form method="post">
<select name="order" id="order">
<option value="date" autofocus>Date</option>
<option value="author">Author</option>
<option value="title">Title</option>
<option value="hit">Hit</option>
</select>
<input type="text" placeholder="Search" class="search" name="search_value">
<input type="submit" value="Search" id="search_btn" name="submit">
</form>
<button id="write_btn">WRITE</button>
</div>
<table>
<?php
if(isset($_GET['page'])) {
$page = $_GET['page'];
} else {
$page = 1;
}
if(isset($_POST['submit'])) {
$search_value = $_POST['search_value'];
$option = $_POST['order'];
}
if(isset($_POST['search_value'])) {
$sql = "SELECT * FROM board WHERE $option LIKE '%$search_value%' ORDER BY $option";
// $page = 1;
} else {
$sql = "SELECT * from board";
}
$res = mysqli_query($conn, $sql);
$cnt = mysqli_num_rows($res);
$post_per_page = 10;
$start = ($page - 1) * $post_per_page;
if(!$res) { //에러
echo "Error";
} else if($cnt == 0) { //Post 없음
echo "<tr><th>There is No Post</th></tr>";
} else {
echo "<tr><th></th><th>Title</th><th>Author</th><th>Date</th><th>Hit</th></tr>";
if(isset($_POST['search_value'])) {
$get_post_sql = "SELECT * FROM board WHERE $option LIKE '%$search_value%' ORDER BY $option LIMIT $start,$post_per_page";
} else {
$get_post_sql = "SELECT * FROM board ORDER BY date LIMIT $start,$post_per_page";
}
$get_post_res = mysqli_query($conn, $get_post_sql);
while($row = mysqli_fetch_array($get_post_res)) {?>
<tr class="article_row" id="article_row">
<th><?=$row['id'];?></th>
<th class="title"><a href="article.php?idx=<?=$row['id'];?>"><?=$row['title'];?></a></th>
<th><?=$row['author'];?></th>
<th><?=$row['date']?></th>
<th><?=$row['hit']?></th>
</tr>
<?php }} ?>
</table>
<div class="footer">
<?php
$total_page = ceil($cnt / $post_per_page);
$page_num = 1;
while($page_num <= $total_page) {
if($page_num == $page) {
echo "<strong>$page_num</strong>";
} else {
echo "<a href='index.php?page=$page_num'>$page_num</a>";
}
$page_num++;
}
?>
</div>
</div>
</div>
<script src="./btn.js"></script>
<script src="https://kit.fontawesome.com/5b18c6ebda.js" crossorigin="anonymous"></script>
</body>
</html>
일단 가볍게 달라진 점을 먼저 언급해보면 전에는 JWT의 발행 여부 로 로그인 여부를 확인했는데,
지금은 Session 을 사용하고 있다는 정도?
자! 그럼 바-로 페이징 기능과 관련된 코드를 살펴보자.
Copy <?php
if(isset($_GET['page'])) {
$page = $_GET['page'];
} else {
$page = 1;
}
if(isset($_POST['submit'])) {
$search_value = $_POST['search_value'];
$option = $_POST['order'];
}
if(isset($_POST['search_value'])) {
$sql = "SELECT * FROM board WHERE $option LIKE '%$search_value%' ORDER BY $option";
// $page = 1;
} else {
$sql = "SELECT * from board";
}
$res = mysqli_query($conn, $sql);
$cnt = mysqli_num_rows($res);
$post_per_page = 10;
$start = ($page - 1) * $post_per_page;
if(!$res) { //에러
echo "Error";
} else if($cnt == 0) { //Post 없음
echo "<tr><th>There is No Post</th></tr>";
} else {
echo "<tr><th></th><th>Title</th><th>Author</th><th>Date</th><th>Hit</th></tr>";
if(isset($_POST['search_value'])) {
$get_post_sql = "SELECT * FROM board WHERE $option LIKE '%$search_value%' ORDER BY $option LIMIT $start,$post_per_page";
} else {
$get_post_sql = "SELECT * FROM board ORDER BY date LIMIT $start,$post_per_page";
}
$get_post_res = mysqli_query($conn, $get_post_sql);
$i = 0;
while($row = mysqli_fetch_array($get_post_res)) {?>
<tr class="article_row" id="article_row">
<th><?=$row['id'];?></th>
<th class="title"><a href="article.php?idx=<?=$row['id'];?>"><?=$row['title'];?></a></th>
<th><?=$row['author'];?></th>
<th><?=$row['date']?></th>
<th><?=$row['hit']?></th>
</tr>
<?php }} ?>
위의 코드는 table tag 안에 작성된 PHP 코드이다.
순서대로 코드를 분석해보면
Copy if(isset($_GET['page'])) {
$page = $_GET['page'];
} else {
$page = 1;
}
우선, $_GET에 KEY page가 존재하는 지 확인한다.
여기서 page 값이 무엇인지는 아래에서 확인할 수 있을 것이다!
만약 page 값이 존재하지 않는 다면 1을, 존재한다면 $_GET['page']를 변수 $page에 할당해준다.
Copy if(isset($_POST['submit'])) {
$search_value = $_POST['search_value'];
$option = $_POST['order'];
}
그 다음 확인하는 값은 $_POST['submit]으로
이는 index page에서 게시물을 검색하기 위해 search 버튼을 클릭했을 경우,
form tag가 post method로 현재 경로에 전달하는 값이다.
즉 $_POST['submit']이 존재하는 지를 확인하는 건,
사용자가 검색 버튼을 눌렀는 지를 확인하는 절차인 것이다.
만약 사용자가 검색 기능을 사용했다면
검색 창에 입력한 값을 $search_value에, select tag에서 선택한 옵션을 $option에 할당한다.
Copy if(isset($_POST['search_value'])) {
$sql = "SELECT * FROM board WHERE $option LIKE '%$search_value%' ORDER BY $option";
// $page = 1;
} else {
$sql = "SELECT * from board";
}
사용자가 특정 게시물을 찾기 위해 어떤 값을 입력했다면
LIKE operator를 사용해 SQL을 작성하고 그렇지 않다면 그냥 모든 게시물을 가져오도록 한다.
Copy $res = mysqli_query($conn, $sql);
$cnt = mysqli_num_rows($res);
$post_per_page = 10;
$start = ($page - 1) * $post_per_page;
케이스에 따라 작성해둔 SQL을 실행한 후, 꺼내온 게시물의 개수를 $cnt에 넣고
각 페이지 당 보여줄 게시물 개수를 $post_per_page에 할당해둔다.
다음으로 계산해야 하는 건, 몇 번째 게시물부터 현재 페이지에 띄워야 하는 지!
현재 페이지에 띄울 첫 번째 게시물 순서를 알아내는 것이다.
Copy $page = 1
$post_per_page = 10
$start = (1-1) * 10 = 0
현재는 $_GET['page'] 값이 없기 때문에 $page는 1을 할당 받은 상태이고
이때의 $start 값은 0이 된다.
Copy if(!$res) { //에러
echo "Error";
} else if($cnt == 0) { //Post 없음
echo "<tr><th>There is No Post</th></tr>";
}
SQL을 실행하는 과정에서 문제가 발생했다면 Error를 출력하고
SQL 실행 결과, row가 0개 라면 There is No Post 문구를 출력하도록 처리한다.
Copy else {
echo "<tr><th></th><th>Title</th><th>Author</th><th>Date</th><th>Hit</th></tr>";
if(isset($_POST['search_value'])) {
$get_post_sql = "SELECT * FROM board WHERE $option LIKE '%$search_value%' ORDER BY $option LIMIT $start,$post_per_page";
} else {
$get_post_sql = "SELECT * FROM board ORDER BY date LIMIT $start,$post_per_page";
}
$get_post_res = mysqli_query($conn, $get_post_sql);
$i = 0;
while($row = mysqli_fetch_array($get_post_res)) {?>
<tr class="article_row" id="article_row">
<th><?=$row['id'];?></th>
<th class="title"><a href="article.php?idx=<?=$row['id'];?>"><?=$row['title'];?></a></th>
<th><?=$row['author'];?></th>
<th><?=$row['date']?></th>
<th><?=$row['hit']?></th>
</tr>
<?php }} ?>
if & else if문으로 처리한 경우가 아니라면 while문을 돌면서 게시판을 구성하도록 하는 데 이때,
위에서 했던 거 처럼 search_value의 여부로 각 상황에 알맞은 Query가 실행될 수 있도록 처리한다.
실행한 Query를 보면 위에서 구한
Copy > SELECT * FROM board WHERE $option LIKE '%$search_value%' ORDER BY $option LIMIT $start,$post_per_page
> SELECT * FROM board ORDER BY date LIMIT $start,$post_per_page
$start 값을 사용해 총 10개의 게시물 정보만 가져오도록 작성한 걸 확인할 수 있다.
참고로 Query에 사용된 limit 은
start 위치부터 cnt 개수 만큼만 결과를 가져오도록 개수를 제한하는 기능 을 담당한다.
Copy <?php
$total_page = ceil($cnt / $post_per_page);
$page_num = 1;
while($page_num <= $total_page) {
if($page_num == $page) {
echo "<strong>$page_num</strong>";
} else {
echo "<a href='index.php?page=$page_num'>$page_num</a>";
}
$page_num++;
}
?>
총 게시물 개수를 페이지 당 보여줄 게시물의 개수로 나누면,
우리가 꺼내온 게시물을 보여주기 위해 몇 개의 페이지가 필요한 지 알아낼 수 있다.
필요한 페이지 개수를 알아냈다면 while문을 돌면서
현재 페이지와 $page_num이 일치하는 경우에는 그 숫자를 strong tag로 처리하고
그 밖의 페이지는 숫자를 클릭했을 때, 해당 페이지로 이동할 수 있도록 a tag로 처리 한다.
이때 a tag의 href 값을 보면
Copy href = 'index.php?$page=$page_num'
page parameter 에 클릭한 페이지 번호가 전달되는 걸 볼 수 있다.
즉, 맨 처음에 확인했던 $_GET['page'] 는
페이징 기능으로 제공된 페이지 순번 링크가 클릭 되는 경우에만 생성되는 값 으로
클릭 되지 않은 경우(ex. 사용자가 로그인을 마친 후, index page로 막 접근한 경우)에는
첫 번째 페이지를 제공해야 하기 때문에 $page 값을 1로 설정했던 것이다.
이렇게 해서 완성된 페이지를 확인해보면~.~
게시판 하단에 제공되는 페이지 버튼을 누르면
다음 게시물 목록이 보이는 페이지로 이동하는 걸 볼 수 있다!
하단에 제공되는 페이지 번호를 클릭함으로써 다음 페이지로 넘어갈 수 있고