오늘은 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로 설정했던 것이다.
이렇게 해서 완성된 페이지를 확인해보면~.~
게시판 하단에 제공되는 페이지 버튼을 누르면
다음 게시물 목록이 보이는 페이지로 이동하는 걸 볼 수 있다!
다시 첫 번째 페이지로 이동하고 싶다면 " 1 " 을 클릭하면 간단히 이동 가능 😄
하단에 제공되는 페이지 번호를 클릭함으로써 다음 페이지로 넘어갈 수 있고
페이지 당 게시물의 개수를 제한해 깔끔하게 페이지를 구성할 수 있게 되었다!! 👍
아주 큰 산을 하나 넘긴 느낌이라 이 기분을 만끽하고 싶지만 🤗
아직 해야 하는 게 많이 남았다..! 다음으로 정렬 & 검색 기능을 구현하러 가보자 😩