본문 바로가기

Web/Web 개발

게시판 페이징 기능 만들기

서론

오늘은 게시글에 페이지 기능을 구현하려고 한다.

진짜 페이지 기능 구현하면서 머리가 터지는 줄 알았다..

특히 변수 설정과 블럭 부분...

그럼 시작해보자

 


 

먼저 생각할 것은

  • 게시글 목록을 페이지 단위로 보여준다.
    - 1페이지에 글 5개, 2페이지에 글 5개 
  • 페이지 개수도 너무 많으면 페이지도 나눠서 보여준다.
    - ‘<’ ‘>’ 버튼으로 이전/다음 블럭으로 이동
  • 페이지 번호 묶음을 블럭(Block) 단위로 관리한다.
    - '1페이지,2페이지 등 5페이지'까지 한블럭 
  • 맨 처음과 마지막으로 이동할 수 있는 버튼을 추가해준다.
    - '<<' = 1페이지 '>>' = 마지막 페이지

최종화면

 

 

1. 현재페이지에 변수 할당

 if(isset($_GET['page'])){
        $page = $_GET['page'];
    }else{
        $page = 1;
    }
  • 페이지를 이동할 떄는 GET메서드를 사용한다
    -페이지 이동은 단순 데이터 조회이기 때문
  • GET으로 넘어온 page 파라미터값을 $page에 변수 할당
  • 파라미터값이 없을 시 기본인 1페이지 즉, 1 할당

2. 필요한 변수 할당

✅ 매우 헷갈릴 수 있으니 주의

$sql="SELECT * FROM board";
$result = $mysqli->query($sql);
$total_post = $result->num_rows;//총 게시글 수
  • board 테이블 컬럼 모두 가져오기
  • $total_post(총 게시글 수) DB결과에서 모든 개수를 할당한다.
    - 이용자가 적은 모든 게시글
$per_post = 5;//페이지당 보여줄 게시글 수
  • $per_post(페이지당 보여줄 게시글 수)
    - 1페이지당 보여줄 게시글 개수이다. 나는 5개로 설정했다.
$start = ($page-1)*$per_post;//페이지당 보여줄 게시글 시작번호
  • $start(페이지당 보여줄 게시글 시작번호)
    -  1페이지에 1,2,3,4,5 라면 $start=1
    - 2페이지에 6,7,8,9,10 라면 $start=6
$total_page = ceil($total_post/$per_post);//총 페이지 수
  • $total_page(총 페이지 수) = 총 게시글 수/ 페이지 당 보여줄 게시글 수
    -총 50개의 게시글이 있다면 1페이지당 5개의 게시글이 보이기 때문에 총 10페이지가 될 것이다.
    -만약 48개의 게시글이 있다면 1페이지당 5개지만 9페이지하고 게시글 3개가 남는다
    버릴 수 없기 때문에 10페이지가 생성되어야하고 10페이지에는 3개의 게시글만 존재할 것이다.
    즉 ,나머지가 없이 올림을 해줘야한다 ( ceil= 올림함수)
per_block = 5;//한 블럭당 보여줄 페이지 수
  • $per_block(한 블럭당 보여줄 페이지 수)
    -내가 헷갈렸던 블럭이기 때문에 사진으로 같이보자

➡️ 페이지들이 나와있다. 내가 아까 5로 설정했기 때문에 5페이지가 존재한다. 이 묶음이 한 블럭이다.

$total_block = ceil($total_page/$per_block);//총 블럭 수
  • $total_block(총 블럭 수) = 총 페이지 수 / 블럭 당 보여줄 페이지 수
    - 20개의 페이지가 있다. 블럭 당 나는 5개로 설정했고 그렇다면 4개의 블럭이 필요하다
    -1블럭{1,2,3,4,5}, 2블럭{6,7,8,9,10}, 3블럭{11,12,13,14,15}, 4블럭{16,17,18,19,20} 
    -18개의 페이지가 있다. 그렇다면 세블럭이면 3개의 페이지가 남는다. 즉 4개의 블럭이 필요하기 떄문에 올림해준다.
    (이제 이해했다고 생각하고 올림설명은 여기까지)
$current_block = ceil($page/$per_block);//현재 페이지가 속한 블럭
  • $current_block(현재 페이지가 속한 블럭) = 현재 페이지 / 한 블럭 당 보여줄 페이지 수
    - 블럭당 나는 5개로 설정했다.
    -현재 페이지가 속한 블럭은 현재 페이지가 1~5라면 1블럭  6~10이라면 2블럭이다.
    -현재페이지가 1~5라고 가정해보자. 내가 설정한 블럭 당 페이지개수(5) 로 나누면
    0.2~1이 될 것이다. 즉, 올림을해줘서 1을 맞춰주면 1블럭에 있다는 로직이 된다.
$start_block = ($current_block-1)*$per_block+1;//지금 블럭의 시작 페이지 번호
  • $start_block(지금 블럭의 시작 페이지 번호)  복잡하기 떄문에 바로 설명
    - 블럭의 시작 페이지 번호란 1블럭은 1페이지, 2블럭은 6페이지, 3블럭은 11페이지이다.
    예를 들면,
    - 1블럭에 있다고 해보자(1~5페이지) (1블럭- 1)*내가 설정한 블럭 당 페이지 수(5) +1 = 1
    - 2블럭에 있다고 해보자(6~10페이지) (2블럭-1)*5 +1 = 6
    즉, 블럭의 시작 페이지 번호이다.
$end_block = min(($start_block + $per_block -1),$total_page);//지금 블럭의 마지막 페이지 번호
  • $end_block(지금 블럭의 마지막 페이지 번호) 이것도 복잡하니 바로 설명
    - min함수란 두 인자를 비교해 더 적은 숫자를 반환한다. (ex. min(5,10) = 5)
    - 블럭의 마지막 페이지 번호란 1블럭은 5, 2블럭은 10, 3블럭은 15페이지이다.
    min(블럭의 시작 페이지 번호 + 내가 설정한 블럭 당 페이지 수(5) - 1 , 총 페이지수

    예를 들면,
    - 1블럭(1~5)이 있고 총 페이지수가 23개라고 해보자
    →min(1+5-1, 23) = 5
    -2블럭(6~10)이 있고 총 페이지수가 8개라고 해보자
    →min(6+5-1,8) = 8 
    -2블럭에는 페이지수가 6~10페이지가 있어야되는데 8페이지밖에 없다.
    그렇기 때문에 이런 것을 걸러내고 마지막 번호만 찾기 위해서 min함수로 더 적은 값을 찾는 것이다.

3. 게시글 가져오기

<?php
        $sql_page = "SELECT * FROM board ORDER BY idx DESC LIMIT $start,$per_post";
        $res_page = $mysqli->query($sql_page);
        while($row = $res_page->fetch_assoc()){
        ?>
            <tr>
                <td><?= $row['idx']; ?></td>
                <td><?= $row['title']; ?></td>
                <td><?= $row['author']; ?></td>
                <td><?= $row['post_date']; ?></td>
                <td><?= $row['views']; ?></td>
                <td><?= $row['likes']; ?></td>
            </tr>
        <?php } ?>
  • ORDER By idx DESC
    - idx 기준으로 내림차순으로 가져온다.
  • LIMIT $start,$per_post
    - 게시글 시작번호부터 $per_post개수만큼 가져온다.

4. 블럭당 페이지 출력

while($start_block<=$end_block){
            //현재페이지는 페이지 클릭 안되게 하기
            if($start_block==$page) {
                echo "<a href='/board/board.php?page=$start_block' class='active'>$start_block</a>";
            } else {
                echo "<a href='/board/board.php?page=$start_block'>$start_block</a>";
            }
            $start_block++;
}
  • 블럭의 시작페이지가 블럭의 마지막페이지와 같거나 작을 때 반복해준다
    - 1블럭일 때, 1~5페이지 출력 2블럭일 때, 6~10페이지 출력
  • 시작페이지와 현재 내 페이지가 같다면 효과를 주기 위해 if문 사용
    - 1페이지에 있다면 1페이지 외에 다른페이지만 클릭 가능

5. 처음/이전/다음/끝 편의기능

✅글이 적다면 상관없지만 많아졌을 땐 불편함을 호소할 수 있기 때문에 구현했다.

<?php

        //처음 블럭으로
        if($current_block>1){
            echo "<a href='/board/board.php?page=1'><<</a>";
        }

        //이전 블럭으로
        if($current_block>1){
            $pre_page = $start_block - 1;
            echo "<a href='/board/board.php?page=$pre_page'><</a>";
        }

        //블럭당 페이지 출력
        while($start_block<=$end_block){
            //현재페이지는 페이지 클릭 안되게 하기
            if($start_block==$page) {
                echo "<a href='/board/board.php?page=$start_block' class='active'>$start_block</a>";
            } else {
                echo "<a href='/board/board.php?page=$start_block'>$start_block</a>";
            }
            $start_block++;
        }
        
        //다음 블럭으로
        if($current_block<$total_block){
            $next_page=$end_block + 1;
            echo "<a href='/board/board.php?page=$next_page'>></a>";
        }

        //마지막 블럭으로
        if($current_block<$total_block){
            echo "<a href='/board/board.php?page=$total_page'>>></a>";
        }
        ?>
  • 처음 = 현재블럭이 1이상 즉, 2번째 블럭,3번째 블럭일 때만 젤 처음 페이지로 이동
  • 이전 = 현재 블럭이 1이상 즉, 2번째 블럭,3번째 블럭일 때 전 블럭으로 이동
    - 2번째 블럭 시작페이지는 6에서 -1을 해주면 5페이지 1번째 블럭으로 이동됨
    - 3번째 블럭 시작페이지는 11에서 -1을 해주면 10페이지 2번째 블럭으로 이동됨
  • 다음 =  현재블럭이 총 블럭 개수보다 작을 때 다음 블럭으로 이동
    - 2번째 블럭 마지막페이지는 10에서 +1을 해주면 11페이지 3번째 블럭으로 이동됨
    - 3번째 블럭 마지막페이지는 15에서 +1을 해주면 16페이지 4번째 블럭으로 이동됨
  • 끝 = 현재블럭이 총 블럭 개수보다 작을 때 맨 끝 페이지로 이동

6. 테스트 해보자

✅먼저 테스트를 위한 50개의 게시글을 작성했다.

<?php
require_once $_SERVER['DOCUMENT_ROOT'].'/board/dummy_data.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/php/db.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/php/session_guard.php';

$author = $_SESSION['user_id'];

for ($i = 1; $i <= 50; $i++) {
    $title = "테스트글 $i";
    $content = "이것은 테스트용 게시글입니다.";
    $post_date = date("Y-m-d H:i:s");
    $views = 0;
    $likes = 0;

    $sql = "
        INSERT INTO board (title, content, author, post_date, views, likes)
        VALUES ('$title', '$content', '$author', '$post_date', $views, $likes)
    ";

    $mysqli->query($sql);
}

echo "더미 게시글 50개 삽입 끝";
?>

➡️삽입 성공!

 

✅>>(끝) 클릭해보기

➡️성공적으로 제일 끝페이지에 도달했다.

 

✅<<(처음) 클릭해보기

➡️성공적으로 제일 첫 페이지에 도달했다.

 

✅>(다음) 클릭해보기

➡️1번째 블럭에서 2번째 블럭으로 이동됐다.

 

✅<(이전) 클릭해보기

➡️다시 1번째 블럭으로 돌아온 것을 확인할 수 있다.

 


7. 최종코드

<?php
    require_once $_SERVER['DOCUMENT_ROOT'].'/php/db.php';

    if(isset($_GET['page'])){
        $page = $_GET['page'];
    }else{
        $page = 1;
    }
    
    $sql="SELECT * FROM board";
    $result = $mysqli->query($sql);

    $total_post = $result->num_rows;//총 게시글 수
    $per_post = 5;//페이지당 보여줄 게시글 수

    $start = ($page-1)*$per_post;//페이지당 보여줄 게시글 시작번호

    $total_page = ceil($total_post/$per_post);//총 페이지 수

    $per_block = 5;//한 블럭당 보여줄 페이지 수
    $total_block = ceil($total_page/$per_block);//총 블럭 수

    $current_block = ceil($page/$per_block);//현재 페이지가 속한 블럭
    $start_block = ($current_block-1)*$per_block+1;//지금 블럭의 시작 페이지 번호
    $end_block = min(($start_block + $per_block -1),$total_page);//지금 블럭의 마지막 페이지 번호

    
?>

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>게시판</title>
    <link rel="stylesheet" href="/CSS/basic.css">
    <link rel="stylesheet" href="/CSS/board.css">
</head>
<body>
    <header class="board_title">
        <h1>Board</h1>
        <div class="nav">
            <a href="/board/board.php">회원게시판</a>
            <a href="/pages/main.php">메인페이지</a>
            <a href="/pages/mypage.php">마이페이지</a>
        </div>
        <hr>
    </header>
    <div class="write_btn1">
        <a href="/board/board_write.php">글쓰기</a>
    </div>
    <table class="board_table">
        <thead>
            <tr>
                <th>POST ID</th>
                <th>제목</th>
                <th>작성자</th>
                <th>작성일</th>
                <th>조회수</th>
                <th id="emot">💌</th>
            </tr>
        </thead>
        <tbody>
        <?php
        $sql_page = "SELECT * FROM board ORDER BY idx DESC LIMIT $start,$per_post";
        $res_page = $mysqli->query($sql_page);
        while($row = $res_page->fetch_assoc()){
        ?>
            <tr>
                <td><?= $row['idx']; ?></td>
                <td><?= $row['title']; ?></td>
                <td><?= $row['author']; ?></td>
                <td><?= $row['post_date']; ?></td>
                <td><?= $row['views']; ?></td>
                <td><?= $row['likes']; ?></td>
            </tr>
        <?php } ?>
        </tbody>
    </table>   
    <div class="page_wrapper"> 
        <?php

        //처음 블럭으로
        if($current_block>1){
            echo "<a href='/board/board.php?page=1'><<</a>";
        }

        //이전 블럭으로
        if($current_block>1){
            $pre_page = $start_block - 1;
            echo "<a href='/board/board.php?page=$pre_page'><</a>";
        }

        //블럭당 페이지 출력
        while($start_block<=$end_block){
            //현재페이지는 페이지 클릭 안되게 하기
            if($start_block==$page) {
                echo "<a href='/board/board.php?page=$start_block' class='active'>$start_block</a>";
            } else {
                echo "<a href='/board/board.php?page=$start_block'>$start_block</a>";
            }
            $start_block++;
        }
        
        //다음 블럭으로
        if($current_block<$total_block){
            $next_page=$end_block + 1;
            echo "<a href='/board/board.php?page=$next_page'>></a>";
        }

        //마지막 블럭으로
        if($current_block<$total_block){
            echo "<a href='/board/board.php?page=$total_page'>>></a>";
        }
        ?>
    </div>
</body>
</html>

 


 

페이징 기능까지 끝났다..이해하는데 좀 오래걸렸지만

그래도 막상 오래생각하고 만들어내니까 뿌듯함도 더 크다 ㅎㅎ🤣