페이징 기능 - board page

DATE : 2023/12/2

오늘은 4주차에 진행했던 Web Server에 이어서 게시판 페이지를 만들어 볼 것이다.

바로 본론으로 들어가기 전, 진행 상황을 다시 떠올려보자.

[ COMPLETED ]

: write 버튼으로 이동한 write_post page에서 사용자가 글을 작성하면 board Table에 저장

: 글 작성을 마친 후, 다시 index page로 돌아가면 board Table에 들어있는 정보로 게시판 구성

[ NEXT ]

: 게시판 목록에 있는 글을 하나 선택하면 해당 POST의 내용을 볼 수 있는 상세 페이지로 이동

: 찾고자 하는 데이터를 입력하면 지정된 카테고리에 한하여 게시물 정렬

: 게시물이 10개 이상 작성되면, 여러 페이지에 걸쳐 게시판 목록 제공 ( 페이징 )

이번 페이지에서는 우선, 페이징 기능부터 구현할 예정이다.

그럼 바로 코드로 넘어가 보자!!

[ index.php ]

<?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을 사용하고 있다는 정도?

자! 그럼 바-로 페이징 기능과 관련된 코드를 살펴보자.

<?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 코드이다.

순서대로 코드를 분석해보면

if(isset($_GET['page'])) {
    $page = $_GET['page'];
} else {
    $page = 1;
}

우선, $_GET에 KEY page가 존재하는 지 확인한다.

여기서 page 값이 무엇인지는 아래에서 확인할 수 있을 것이다!

만약 page 값이 존재하지 않는 다면 1을, 존재한다면 $_GET['page']를 변수 $page에 할당해준다.

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에 할당한다.

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을 작성하고 그렇지 않다면 그냥 모든 게시물을 가져오도록 한다.

$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에 할당해둔다.

다음으로 계산해야 하는 건, 몇 번째 게시물부터 현재 페이지에 띄워야 하는 지!

현재 페이지에 띄울 첫 번째 게시물 순서를 알아내는 것이다.

$page = 1
$post_per_page = 10

$start = (1-1) * 10 = 0

현재는 $_GET['page'] 값이 없기 때문에 $page는 1을 할당 받은 상태이고

이때의 $start 값은 0이 된다.

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 문구를 출력하도록 처리한다.

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를 보면 위에서 구한

> 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

LIMIT start, cnt

start 위치부터 cnt 개수 만큼만 결과를 가져오도록 개수를 제한하는 기능을 담당한다.

<?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 값을 보면

href = 'index.php?$page=$page_num'

page parameter에 클릭한 페이지 번호가 전달되는 걸 볼 수 있다.

즉, 맨 처음에 확인했던 $_GET['page']

페이징 기능으로 제공된 페이지 순번 링크가 클릭 되는 경우에만 생성되는 값으로

클릭 되지 않은 경우(ex. 사용자가 로그인을 마친 후, index page로 막 접근한 경우)에는

첫 번째 페이지를 제공해야 하기 때문에 $page 값을 1로 설정했던 것이다.

이렇게 해서 완성된 페이지를 확인해보면~.~

게시판 하단에 제공되는 페이지 버튼을 누르면

다음 게시물 목록이 보이는 페이지로 이동하는 걸 볼 수 있다!

다시 첫 번째 페이지로 이동하고 싶다면 " 1 "을 클릭하면 간단히 이동 가능 😄

하단에 제공되는 페이지 번호를 클릭함으로써 다음 페이지로 넘어갈 수 있고

페이지 당 게시물의 개수를 제한해 깔끔하게 페이지를 구성할 수 있게 되었다!! 👍

아주 큰 산을 하나 넘긴 느낌이라 이 기분을 만끽하고 싶지만 🤗

아직 해야 하는 게 많이 남았다..! 다음으로 정렬 & 검색 기능을 구현하러 가보자 😩

Last updated