📚 PHP 중급 - 3주차: 게시판 CRUD 구현 (기본) - 03 페이징 처리

2025. 7. 23. 08:21프로그램/PHP 중급

📚 PHP 중급 - 3주차: 게시판 CRUD 구현 (기본) - 03 페이징 처리

📚 PHP 중급 - 3주차: 게시판 CRUD 구현 (기본) - 03 페이징 처리



안녕하세요! 지난 시간에 #PHP #게시판의 #CRUD 기능을 구현해 보았죠. 오늘은 #글 목록을 효율적으로 관리하고 사용자 경험을 향상시키는 데 필수적인 #페이징_처리(Pagination)를 자세히 다뤄볼 거예요. #페이징 처리는 #데이터가 많을 때 웹페이지의 #성능을 최적화하는 중요한 방법입니다.

 

1. 페이징 처리의 필요성

 

#게시판에 #글이 수천, 수만 개 쌓인다고 상상해 보세요. 모든 #글을 한 번에 불러와서 웹페이지에 표시한다면 다음과 같은 문제가 발생할 수 있어요.

 

  • 느린 로딩 속도: #데이터베이스에서 많은 #데이터를 가져오고, #웹페이지에 렌더링하는 데 오랜 시간이 걸립니다. 이는 사용자에게 좋지 않은 경험을 줍니다.
  • 서버 부하 증가: 한 번에 모든 #데이터를 처리하느라 #서버에 과부하가 걸릴 수 있습니다.
  • 사용자 경험 저하: 사용자가 스크롤을 끝없이 내려야 하므로 원하는 #정보를 찾기 어렵고 불편합니다.

 

#페이징_처리는 이러한 문제를 해결하고, #데이터를 적절한 단위로 나누어 표시함으로써 #웹페이지의 #성능과 #사용자_경험을 동시에 개선합니다.


2. 페이징 처리의 핵심 원리

 

#페이징_처리의 기본 원리는 다음과 같아요.

 

  1. 총 #게시물_수 파악: #데이터베이스에 있는 전체 #게시물 수를 먼저 알아냅니다.
  2. 한 페이지당 #게시물_수 설정: 한 페이지에 몇 개의 #글을 보여줄지 정합니다. (예: 10개, 20개)
  3. 총 #페이지_수 계산: 총 #게시물 수를 페이지당 #게시물 수로 나누어 전체 #페이지 수를 계산합니다.
  4. 현재 #페이지 번호 파악: 사용자가 보고자 하는 #페이지 번호를 #URL 파라미터(예: list.php?page=2) 등을 통해 가져옵니다.
  5. #LIMIT과 #OFFSET 사용: #SQL 쿼리에서 #LIMIT과 #OFFSET을 사용하여 현재 #페이지에 해당하는 #데이터만 #데이터베이스에서 가져옵니다.


3. 페이징 처리 코드 구현 (list.php 수정)

 

지난번 list.php 코드에 #페이징_처리 #로직을 추가하여 수정해 볼게요.

 

PHP
 
<?php
// list.php
include 'db_config.php'; // 데이터베이스 연결 설정 포함

// 1. 페이징을 위한 설정값 정의
$posts_per_page = 10; // 한 페이지에 보여줄 게시글 수

// 2. 현재 페이지 번호 파악
// URL 쿼리 파라미터 'page'에서 현재 페이지 번호를 가져오며, 없으면 1로 설정
$current_page = isset($_GET['page']) ? (int)$_GET['page'] : 1;

// 3. OFFSET 계산: 데이터베이스에서 몇 번째 레코드부터 가져올지 결정
// (현재 페이지 번호 - 1) * 페이지당 게시글 수
$offset = ($current_page - 1) * $posts_per_page;

try {
    // 4. 총 게시글 수 가져오기
    $total_posts_stmt = $conn->query("SELECT COUNT(*) FROM board");
    $total_posts = $total_posts_stmt->fetchColumn(); // 전체 게시글 수를 숫자로 가져옴

    // 5. 총 페이지 수 계산
    // ceil() 함수를 사용하여 소수점 이하를 올림 (예: 20.1개면 21페이지 필요)
    $total_pages = ceil($total_posts / $posts_per_page);

    // 6. 현재 페이지에 해당하는 게시글 목록 가져오기
    // ORDER BY created_at DESC: 최신 글부터 정렬
    // LIMIT :offset, :limit: offset부터 limit 개수만큼의 게시글 가져오기
    $stmt = $conn->prepare("SELECT id, title, author, created_at FROM board ORDER BY created_at DESC LIMIT :offset, :limit");
    $stmt->bindParam(':offset', $offset, PDO::PARAM_INT); // OFFSET 바인딩 (정수형)
    $stmt->bindParam(':limit', $posts_per_page, PDO::PARAM_INT); // LIMIT 바인딩 (정수형)
    $stmt->execute();
    $posts = $stmt->fetchAll(); // 모든 결과를 배열로 가져옴

} catch(PDOException $e) {
    echo "오류: " . $e->getMessage();
    $posts = []; // 오류 발생 시 게시글 배열을 비워둠
    $total_pages = 1; // 오류 시 총 페이지 수를 1로 설정
}
?>
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>게시판 글 목록</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        table { width: 80%; border-collapse: collapse; margin: 20px auto; }
        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        th { background-color: #f2f2f2; }
        .pagination { text-align: center; margin-top: 20px; }
        .pagination a { margin: 0 5px; padding: 5px 10px; text-decoration: none; border: 1px solid #ddd; color: #333; }
        .pagination a.active, .pagination a:hover { background-color: #007bff; color: white; border-color: #007bff; }
    </style>
</head>
<body>
    <h1>게시판 글 목록</h1>
    <p><a href="write.php">새 글 작성</a></p>
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>제목</th>
                <th>작성자</th>
                <th>작성일</th>
            </tr>
        </thead>
        <tbody>
            <?php if (count($posts) > 0): ?>
                <?php foreach ($posts as $post): ?>
                    <tr>
                        <td><?php echo htmlspecialchars($post['id']); ?></td>
                        <td><a href="view.php?id=<?php echo htmlspecialchars($post['id']); ?>"><?php echo htmlspecialchars($post['title']); ?></a></td>
                        <td><?php echo htmlspecialchars($post['author']); ?></td>
                        <td><?php echo htmlspecialchars($post['created_at']); ?></td>
                    </tr>
                <?php endforeach; ?>
            <?php else: ?>
                <tr>
                    <td colspan="4">아직 작성된 글이 없습니다.</td>
                </tr>
            <?php endif; ?>
        </tbody>
    </table>

    <div class="pagination">
        <?php for ($i = 1; $i <= $total_pages; $i++): ?>
            <a href="?page=<?php echo $i; ?>" class="<?php echo ($i == $current_page) ? 'active' : ''; ?>"><?php echo $i; ?></a>
        <?php endfor; ?>
    </div>
</body>
</html>


4. 코드 설명 및 보충

 

  • $posts_per_page: 한 페이지에 몇 개의 #게시글을 보여줄지 설정하는 변수예요. 필요에 따라 조절할 수 있습니다.
  • $current_page: 현재 사용자가 요청한 #페이지 번호를 $_GET['page']로 가져와요. #URL에 ?page=숫자 형태로 전달됩니다. (int)로 형 변환하여 #보안을 강화하고 비정상적인 값을 막습니다.
  • $offset: #SQL의 #LIMIT 절에서 사용할 시작 위치를 계산해요. 예를 들어 2페이지를 요청하고 페이지당 10개의 #글을 보여준다면, (2-1) * 10 = 10이 되어 11번째 #글부터 10개를 가져오게 됩니다.
  • COUNT(*): #데이터베이스 쿼리에서 #게시판의 #총_글_수(#total_posts)를 가져와요. #PDO의 fetchColumn()을 사용하면 첫 번째 컬럼의 값(여기서는 COUNT(*))을 바로 얻을 수 있습니다.
  • ceil(): #PHP의 ceil() 함수는 소수점 이하를 무조건 올림 해요. 예를 들어 총 #글이 21개이고 페이지당 10개라면, 21 / 10 = 2.1이 되고, ceil(2.1)은 3이 되어 총 3페이지가 필요하다고 정확히 계산됩니다.
  • LIMIT :offset, :limit: #SQL에서 특정 범위의 #데이터만 가져오는 구문입니다. OFFSET으로 시작 위치를, LIMIT으로 가져올 개수를 지정해요. #준비된_구문(Prepared Statement)을 사용해 #SQL_인젝션 공격을 방지하고 PDO::PARAM_INT로 정수형임을 명시하여 #보안을 강화합니다.
  • #페이지네이션_링크: for 루프를 사용하여 1부터 $total_pages까지의 #페이지_링크를 동적으로 생성합니다. 현재 #페이지에는 active 클래스를 추가하여 시각적으로 강조했어요.

 

이 #페이징_처리 #로직을 적용하면 #게시판이 아무리 커져도 #웹페이지는 빠르고 효율적으로 #글 목록을 보여줄 수 있을 거예요. 다음 주차에는 #게시판의 다른 유용한 기능들을 추가해 보겠습니다!

 


게시판 CRUD 페이징 PHP 데이터베이스 SQL 성능 사용자경험