본문 바로가기

개발과제

[노말틱 모의 해킹 취업반 7주차 개발과제 ] 게시판 만들기(3) - 페이징

안녕하세요!

 

이번엔 저번에 만든 게시물에서 추가로 기능을 넣겠습니다

 

바로 페이징 기능입니다!

 

페이징은 게시물이 너무 많을 때 페이지 별로 나누어서 볼 수 있게 하는 건데요

 

이걸 한 번 만들어 보겠습니다

.

.

.

.

게시판 페이지인 board.php만 손 보면 되겠네요!

 

우선적으로 어떡해 코딩할지 생각을 해봅시다.

 

일단 한 페이지당 얼마나 게시물이 보이게 할지 결정해야 되겠죠?

저는 5개로 하겠습니다

 

그리고 제 데이터베이스에 몇 개의 게시물이 있는지도 알아야 되겠네요!

 

그리고.. 총 게시물 개수랑 한 페이지 당 표시되는 개수를 나눠서 페이지가 얼마나 필요한지 알 수 있습니다.

 

또한 1페이지엔 1번~5번까지 출력 2페이지엔 6~10번까지 출력하게

각 페이지마다 시작 변수를 알 수 있게 코딩을 하면 되겠네요

 

그리고 보여주게 하는 것은 SQL언어에 LIMIT을 활용하면 되겠습니다..

.

.

.

.

.

.

.

.

한번 코딩을 해보겠습니다.

 

저는 한 페이지당 5 게시물 보여주게 하기 위해서 따로 변수에 넣겠습니다.

 

            //한 페이지에 보여줄 게시물 수
            $num_per_page = 5;

 

그리고 제 데이터베이스에 얼마나 게시물이 있는지 확인하겠습니다.

 

            //전체 게시물 수 조회
            $total_sql = "SELECT count(*) AS cnt FROM $db_board";
            $total_result = mysqli_query($conn,$total_sql); //sql문 실행
            $total_row = mysqli_fetch_assoc($total_result); //결과를 배열로 가져온다
            $total_posts = $total_row['cnt']; //배열 중 cnt의 값을 가져온다

참.. 개수 하나 알아내려고 4줄이나 필요하네요.

 

sql문에 count(*) as 함수 이용했습니다!

 

그다음에.. 이제 총 게시물 수랑 한 페이지당 5개랑 나눠서 페이지가 얼마나 필요한지 코딩하겠습니다

 

            //전체 페이지 수
            $total_pages = ceil($total_posts / $num_per_page);

 

ceil() 함수는 만약 () 안에 값이 실수형이면 올림 해서 정수로 표현되게 하는 것입니다! ex) ceil(3.14) => 4 반환

페이지 수가 소수점이 있을 수가 없죠

 

다음에는 각 페이지마다 시작하는 번호를 담는 변수를 만들기 전에!

 

저희는 1페이지 볼 때랑 2페이지 볼 때의 변수를 $page로 만들어서 설정하겠습니다

 

            //현재 페이지 번호
            if(isset($_GET['page'])) {
                $page = intval($_GET['page']);
            } else {
                $page = 1;
            }

 

만약에 GET방식에 page가 있으면 intval로 정수형으로 바꾸고 새로운 GET방식의 page를 받습니다.

무슨 말이면 저희가 1페이지를 보고 있다가 3페이지로 넘어갈 때 get방식으로 page에 3을 담아서 보내는 것입니다!

 

intval은 GET방식이 url에 담아서 보내는 거라 사람들이 실수든 뭐든 정수가 아닌 3.1 이렇게 적을 수 있기에

정수형으로 바꾸게 했습니다.

 

board.php에 처음 들어가면 GET방식으로 page을 받은 게 없을 테니 else문에 첫 페이지인 1을 넣었습니다.

 

 

 

이제 다음에는 각 페이지마다 시작하는 번호를 담는 변수를 만들겠습니다

 

            //각 페이지 시작 인덱스
            $start = ($page - 1) * $num_per_page;

 

-1을 하는 이유가 있습니다. 왜냐하면 저희는 이 start 변수로 데이터베이스 조회할 건데요

배열은 0부터 시작이기 때문에 1을 뺍겁니다!

 

그다음에 검색이 입력된 경우에 검색된 게시물이 몇 개인지 확인하겠습니다.

 

            //검색이 입력된 경우
            if(isset($_POST['search']) && !empty($_POST['search'])) {
                $search = mysqli_real_escape_string($conn, $_POST['search']);
                $sql = "SELECT board_id,id,title FROM $db_board WHERE title LIKE '%$search%'";
                $total_sql = "SELECT count(*) AS cnt FROM $db_board WHERE title LIKE '%$search%'";
            }

$total_sql문이 검색된 게시물 수를 카운터 하는 구문입니다!

 

 

그리고 sql문에 ORDER BY이용해 각 인덱스마다 얼마다 나오게 하는지 코딩하겠습니다

 

            //sql문에 추가로 작성하고 LIMIT 설정하고 DESC 즉 내림차순으로 정렬
            $sql .= " ORDER BY board_id DESC LIMIT $start, $num_per_page";

 

SQL 언어에서 .= 는 본래 작성된 sql문에 뒤에 추가로 붙이겠다는 의미입니다!

 

즉 저 코드는 제가 전에 작성했던 sql문 SELECT board_id,id,title FROM $db_board 여기 뒤에 붙여지겠죠.

 

DESC는 내림차순으로 정렬하는 것이고요 LIMIT는 개수를 한정하는 겁니다. 즉 $start 부터 $num_per_page까지

나오게 하는 거죠

 

 

그다음에 sql문이 실행되고 출력하게 되겠죠?

 

그리고 마지막에 페이지 번호도 적고 GET으로 어느 페이지로 갔는지 작성하겠습니다!

 

            echo '<p> [';
            // 페이지 링크 출력
            for ($i = 1; $i <= $total_pages; $i++) {
                if($i == $page) {
                    echo $i.' ';
                } else {
                    echo '<a href="?page=' . $i .'">'.$i. '</a>';
                }
            }
            echo ' ]</p>';

 

이렇게요

 

만약 현재 페이지가 i랑 같으면 그냥 아무 링크 없이 i 출력하고

아니면 그 페이지의 링크 걸게 했습니다.

 

이러면 끝입니다!

 

한번 실행해 보겠습니다.

 

일단 임의로 게시판을 많이 만들어 놓겠습니다.

 

그리고 확인했더니

 

 

음.. 깔끔하진 않네요

 

그리고 2페이지로 가보겠습니다

 

잘 나오네요!

 

게시물도 잘 들어가지는걸 확인할 수 있습니다.

 

근데 약간만 더 수정하겠습니다! 너무 깔끔해 보이지 않네요

 

            echo '<p> [ ';
            // 페이지 링크 출력
            for ($i = 1; $i <= $total_pages; $i++) {
                if($i == $page) {
                    echo $i.' ';
                } else {
                    echo '<a href="?page=' . $i .'">'.$i. '</a> ';
                }
                echo ' ';
            }
            echo ' ]</p>';

끝에 띄어쓰기 추가 했습니다

 

 

좋아요!

 

깔끔하네요! 

근데 하이퍼 링크 때문에 페이지 색이 바뀌어서 뭔가.. 현재 페이지가 몇 페이지인지 구별하기 힘드네요!

 

그러니 조금만 더 수정하겠습니다

            echo '<p> [ ';
            // 페이지 링크 출력
            for ($i = 1; $i <= $total_pages; $i++) {
                if($i == $page) {
                    echo '<strong>'.$i.' </strong>';
                } else {
                    echo '<a href="?page=' . $i .'">'.$i. '</a> ';
                }
                echo ' ';
            }
            echo ' ]</p>';

strong 구문 사용했습니다!

 

다시 보면

 

그나마 보기 좋네요!

 

저렇게 강조되어 있는 게 보입니다

 

문제점이 있네요

 

아무것도 작성 안 했는데 올라가지네요

이것부터 수정하겠습니다.

 

write_board.php로 가겠습니다.

 

그리고 수정하겠습니다

 

꼭 있어야지만 작성되게요!

 

input 구문에 required 추가해서 꼭 작성하게 하겠습니다.

 

        <form action="write_process_board.php" method="POST"> 
            <p><input type="text" name="title" maxlegth="44" placeholder="제목 입력, 최대 44자까지 가능합니다" required></p>
            <p><textarea name="detail" rows="20" cols="20" maxlength="254" placeholder="내용 작성,최대 254자 가능합니다" required></textarea></p>
            <p><input type="submit" value="올리기"></p>
        </form>

 

좋아요!

 

다시 해보면

 

이렇게 나오게 됩니다

 

 

그다음 문제로는 저희가 페이지를 잘 나오게 했는데 모든 페이지 번호가 나오고 있습니다!

그래서 저는 이렇게 만들겠습니다

 

1~10까지 나오고 10부터는 20까지 보이게 하겠습니다!

 

즉 저는 페이지 번호를 블록처럼 만들겠습니다

 

            echo '<p> [ ';
            
            // 현재 페이지를 10으로 나눈 몫에 10을 곱한 값에서 1을 빼면
            // 현재 페이지가 몇 번째 페이지 블록에 있는지 알 수 있습니다.
            $block_start = floor(($page-1)/10)*10;

            if ($block_start > 1) {
                // 이전 페이지 블록이 있다면, 다음 버튼을 출력합니다.
                $next_block_start = $block_start - 10;
                if($next_block_start == 0) {
                    $next_block_start += 1; //0페이지는 존재 하지 않기에 1더한다
                }
                echo '<a href="?page=' . $next_block_start .'">이전 페이지</a>';
            }
            
            // 페이지 링크 출력
            for ($i = $block_start+1; $i <= min($block_start+10, $total_pages); $i++) {
                if($i == $page) {
                    echo '<strong>'.$i.' </strong>';
                } else {
                    echo '<a href="?page=' . $i .'">'.$i. '</a> ';
                }
                echo ' ';
            }
            
            if ($block_start+10 < $total_pages) {
                // 다음 페이지 블록이 있다면, 다음 버튼을 출력합니다.
                $next_block_start = $block_start + 1;
                echo '<a href="?page=' . $next_block_start .'">다음</a>';
            }
            
            echo ' ]</p>';

 

 

보시면은 floor 함수는 내림 함수입니다. 3.5이면 3을 반환합니다.

$block_start 에 page을 1 빼고 10 나누고 10을 다시 곱합니다.

 

이 말은 page가 1이면 block은 0부터 시작한다는 걸 의미하죠

만약 page가 11이면 block은 10부터 시작하겠죠!

 

이전 페이지는 현 페이지보다 1보다 크면 무조건 이전 페이지 글씨가 보이게 하고

링크를 걸었습니다!

 

 

그리고 for 문에서는 block_start에서 1을 더한 값이 시작입니다.

블록이 0이면 1부터 출력, 10이면 11부터 출력하기 위함이죠

 

min($block_start+10, $total_pages) 이 코드는 만약 1부터 시작이면 10까지 보이게 하고

11부터 시작이면 20까지 보이게 해주는 코드입니다. min은 이 둘 중 작은 값으로 반환하는 거고요.

 

그리고 if 절에 $block_start+10 < $total_pages 이면 다음 페이지 블록이 있다는 걸 뜻합니다

그래서 다음 글씨에 링크 걸어서 $next_block_start에 현 block에 11을 더하여 바로 다음 페이지 보게 했습니다.

 

 

이제 봐보겠습니다!

 

잘 있네요! 누르면은?

 

이번엔 이전 페이지 누르겠습니다

 

깔끔하네요

 

만약 다음 페이지랑 그저 한 페이지만 넘기는 페이지를 구현하고 싶으시면

 

            // 다음 버튼 출력
            if ($page < $total_pages) {
                echo '<a href="?page=' . ($page+1) .'">다음</a> ';
            }

이렇게 하면 되겠죠!

 

 

이전 버튼은 이전 페이지 아래에 작성하겠습니다

 

            // 이전 버튼 출력
            if ($page > 1) {
                echo '<a href="?page=' . ($page-1) .'">이전</a> ';
            }

 

뭔가 글씨로 보니깐 보기가 안 좋네요

 

이전페이지를 <<로 바꾸고

이전을 <

다음 페이지를 >>로 바꾸고

다음을 >로 바꾸겠습니다

 

그나마 낫네요!

 

잘 나오는걸 알 수 있습니다

 

오늘은.. 이렇게 페이징 기능을 넣어 봤습니다. 생각보다 많이 힘들고 이해하기가 어려워서

당황했습니다! 다음에는 파일 업로드 가능하게 하는 기능을 넣겠습니다! 감사합니다.

 

 

 

-board.php

 

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Welcome!</title>
    </head>
    <body>
        <h1>MENU</h1>
        <form method ="POST" action="board.php">
            <input type = "text" name="search" placeholder="검색">
            <input type="submit" value="검색">
        </form>
        <p>
        <?php 
            include 'DB_INFO.php'; //데이터 베이스 정보

            //데이터베이스 연결
            $conn = mysqli_connect($host,$username,$password,$db_board);

            //데이터베이스 오류시 종료
            if(mysqli_connect_errno()) {
                die("데이터 베이스 오류: ". mysqli_connect_error());
            }

            session_start(); //세션 시작

            if(!isset($_SESSION['login_id'])) {
                //로그인하지 않은 사용자
                header("Location: login.php"); //login 화면으로 바꾼다
                exit(); //이 페이지를 바로 닫는다
            }

            //한 페이지에 보여줄 게시물 수
            $num_per_page = 5;

            //현재 페이지 번호
            if(isset($_GET['page'])) {
                $page = intval($_GET['page']);
            } else {
                $page = 1;
            }

            //전체 게시물 수 조회
            $total_sql = "SELECT count(*) AS cnt FROM $db_board";
            $total_result = mysqli_query($conn,$total_sql); //sql문 실행
            $total_row = mysqli_fetch_assoc($total_result); //결과를 배열로 가져온다
            $total_posts = $total_row['cnt']; //배열 중 cnt의 값을 가져온다

            //전체 페이지 수
            $total_pages = ceil($total_posts / $num_per_page);

            //각 페이지 시작 인덱스
            $start = ($page - 1) * $num_per_page;

            //작성된 게시물들 조회 문
            $sql = "SELECT board_id,id,title FROM $db_board";

            //검색이 입력된 경우
            if(isset($_POST['search']) && !empty($_POST['search'])) {
                $search = mysqli_real_escape_string($conn, $_POST['search']);
                $sql = "SELECT board_id,id,title FROM $db_board WHERE title LIKE '%$search%'";
                $total_sql = "SELECT count(*) AS cnt FROM $db_board WHERE title LIKE '%$search%'";
            }
            
            //sql문에 추가로 작성하고 LIMIT 설정하고 DESC 즉 내림차순으로 정렬
            $sql .= " ORDER BY board_id DESC LIMIT $start, $num_per_page";

            //쿼리문 실행
            $result = mysqli_query($conn, $sql);

            if(mysqli_num_rows($result) > 0) {
                //게시물 출력
                while($row = mysqli_fetch_assoc($result)) {
                    $index = $row['board_id'];
                    $id = $row['id'];
                    $title = $row['title'];
                    echo '<p><a href="view_board.php?index='.$index.'">'.$title.'</a> : '.$id.'작성함</p>';
                }
            } else {
                echo "게시물이 없습니다!";
            }
            
            echo '<p> [ ';
            
            // 현재 페이지를 10으로 나눈 몫에 10을 곱한 값에서 1을 빼면
            // 현재 페이지가 몇 번째 페이지 블록에 있는지 알 수 있습니다.
            $block_start = floor(($page-1)/10)*10;

            if ($block_start > 1) {
                // 이전 페이지 블록이 있다면, 다음 버튼을 출력합니다.
                $next_block_start = $block_start - 10;
                if($next_block_start == 0) {
                    $next_block_start += 1; //0페이지는 존재 하지 않기에 1더한다
                }
                echo '<a href="?page=' . $next_block_start .'"><< </a>';
            }

            // 이전 버튼 출력
            if ($page > 1) {
                echo '<a href="?page=' . ($page-1) .'">< </a> ';
            }
            
            // 페이지 링크 출력
            for ($i = $block_start+1; $i <= min($block_start+10, $total_pages); $i++) {
                if($i == $page) {
                    echo '<strong>'.$i.' </strong>';
                } else {
                    echo '<a href="?page=' . $i .'">'.$i. '</a> ';
                }
                echo ' ';
            }

            // 다음 버튼 출력
            if ($page < $total_pages) {
                echo '<a href="?page=' . ($page+1) .'">> </a> ';
            }
            
            if ($block_start+10 < $total_pages) {
                // 다음 페이지 블록이 있다면, 다음 버튼을 출력합니다.
                $next_block_start = $block_start + 11;
                echo '<a href="?page=' . $next_block_start .'">>></a>';
            }

            echo ' ]</p>';
            
        ?>
        </p>
        <p></p>
        <form action="write_board.php" method="POST"> 
            <p><input type="submit" name="write" value="게시판 작성"></p>
        </form>
        <form action="only_login.php"> 
            <p><input type="submit" value="메인페이지로"></p>
        </form>
    </body>
</html>

 

 

-write_board.php

 

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>게시판 작성 중</title>
    </head>
    <body>
        <h1>게시판 작성!</h1>
        <?php 
            session_start(); //세션 시작

            if(!isset($_SESSION['login_id'])) {
                //로그인하지 않은 사용자
                header("Location: login.php"); //login 화면으로 바꾼다
                exit(); //이 페이지를 바로 닫는다
            }
        ?>
        <form action="write_process_board.php" method="POST"> 
            <p><input type="text" name="title" maxlegth="44" placeholder="제목 입력, 최대 44자까지 가능합니다" required></p>
            <p><textarea name="detail" rows="20" cols="20" maxlength="254" placeholder="내용 작성,최대 254자 가능합니다" required></textarea></p>
            <p><input type="submit" value="올리기"></p>
        </form>
        <form action="board.php"> 
            <p><input type="submit" value="돌아가기"></p>
        </form>
        <p>
        <?php session_start();
                if (isset($_SESSION['write_error'])) {
                    echo $_SESSION['write_error'];
                    unset($_SESSION['write_error']);
                }
        ?>
        </p>
    </body>
</html>