[12. 회원게시판 - 게시글확인 (+댓글 기능)]

Minseok Jo·2025년 9월 12일
post-thumbnail

개발 대상은 [회원게시판 - 게시글확인] 페이지이다.
구성은 다음과 같다.

mem_view.php : 게시글 내용 & 댓글 출력 페이지
download.php : 파일 다운로드 처리 페이지
mem_edit.php : 게시글 관련 처리 페이지 (추천기능)
comment_proc.php : 댓글 작성 처리 페이지
comment_delete.php : 댓글 삭제 처리 페이지
boord_view.css : 게시글 확인 페이지 CSS


0. 테이블 구조

likes
○ 추천 정보 테이블



comment
○ 댓글 정보 테이블

1. Frontend + Backend

<mem_view.php>

<?php
    session_start();
    if (!isset($_SESSION["user_id"])) {
        echo "<script>
        alert('회원만 이용가능합니다.');
        location.href='../auth/login.php';
        </script>";
        exit;
    }

    include "../db/db_con.php";

    if (!isset($_GET["num"]))
        echo "<script>location.href='./mem_list.php</script>";

    $sql = "select title, content, user_name, write_time, views, likes from memboard where num = {$_GET['num']}";
    $result = mysqli_query($con, $sql);
    $row = mysqli_fetch_assoc($result);

    if ($row == 0)
        echo "<script>location.href='./mem_list.php'</script>";

    $views = $row["views"];
    $views++;
    $sql = "update memboard set views={$views} where (num={$_GET['num']})";
    mysqli_query($con, $sql);

    $sql = "select * from memboard where num = {$_GET['num']}";
    $result = mysqli_query($con, $sql);
    $row = mysqli_fetch_assoc($result);

    $num = $row["num"];
    $title = $row["title"];
    $content = $row["content"];
    $username = $row["user_name"];
    $userid = $row["user_id"];
    $write_time = $row["write_time"];
    $display_date = date("Y-m-d H:i", strtotime($row['write_time']));
    $views = $row["views"];
    $likes = $row["likes"];
    $comments = $row["comments"];
    $file_name = $row["file_name"];
?>

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>회원 게시판</title>
        <link rel="stylesheet" href="../css/board_view.css?v=<?=time()?>">
    </head>
    <body>
        <?php include "../include/header.php" ?>
        <h2>회원게시판 View</h2>
        <div class="view-container">
            <table>
                <tr>
                    <td><i class='fa-solid fa-book'></i> <?php echo "제목:&nbsp $title"?></td>
                    <td><i class='fa-solid fa-calendar-days'></i> &nbsp <?php echo "$display_date"?></td>
                </tr>
                <tr>
                    <td><i class='fa-solid fa-user-pen'></i> <?php echo "작성자:&nbsp $username"?></td>
                    <td><i class= 'fa-solid fa-eye'></i> <?php echo "조회수 {$views}"?>  &nbsp;&nbsp;  <i class='fa-solid fa-thumbs-up'></i> <?php echo "추천수 {$likes}"?> &nbsp;&nbsp; <i class="fa-solid fa-comment"></i> &nbsp<?php echo "댓글 {$comments}"?></td>
                </tr>
                <tr>
                    <td colspan=2><div class="view-content"><?php echo nl2br($content); ?></div></td>
                </tr>
                <?php
                if (!empty($file_name)) {
                    echo "
                    <tr>
                        <td colspan='2' class='file-cell'>
                            <i class='fa-solid fa-paperclip'></i> 첨부파일:
                            <a href='download.php?num=$num'>$file_name &nbsp;<i class='fa-solid fa-download'></i></a>
                        </td>
                    </tr>
                    ";
                }
                ?>
                <tr>
                    <td>
                        <form method="POST" action="mem_edit.php">
                            <input type="hidden" name=num value="<?php echo $num ?>">
                            <button type="submit" name="type" value="likes"><i class="fa-solid fa-thumbs-up"></i> 추천</button>
                            <?php
                                if (isset($_SESSION["user_id"])) {
                                    if ($userid == $_SESSION["user_id"]) {
                                    echo '<button type="submit" name="type" value="modify"><i class="fa-solid fa-pen-to-square"></i> 수정</button>';
                                    echo '<button type="submit" name="type" value="delete"><i class="fa-solid fa-x"></i> 삭제</button>';
                                    }
                                }
                            ?>
                        </form>
                    </td>
                    <td class="view-list-btn">
                        <buttontoken punctuation">.php'"><i class="fa-solid fa-list-ul"></i> 게시글 목록</button>
                    </td>
                </tr>
            </table>
        </div>

        <div class="comment-form">
            <form method="post" action="comment_proc.php">
                <input type="hidden" name="board_num" value="<?php echo $num; ?>">
                <textarea name="input_cmt" placeholder="댓글을 입력하세요"></textarea>
                <input type="submit" value="등록">
            </form>
        </div>

        <div class="comment-list">
            <?php
            $sql = "select * from comment where board_num=$num order by id";
            $result = mysqli_query($con, $sql);

            if (mysqli_num_rows($result) > 0) {
                while ($row = mysqli_fetch_assoc($result)) {
                    echo "<div class='comment'>";
                    echo "<b>{$row['user_name']}</b> <span class='date'>{$row['write_time']}</span><br>";
                    echo "<div class='comment-text'>" . nl2br($row['content']) . "</div>";

                    if (isset($_SESSION['user_id']) && $_SESSION['user_id'] == $row['user_id']) {
                        echo "<div class='comment-actions'>
                        <a class='comment-action' href='comment_delete.php?comment_id={$row['id']}&board_num={$num}'>[삭제]</a>
                        </div>";
                    }
                    echo "</div>";
                }
            }
            else
                echo "<p>아직 댓글이 없습니다.</p>";
            ?>
        </div>
    </body>
</html>
mem_view.php

[1. 게시글 관련 부분]

  • 1. 게시글 정보 검색
    GET 방식으로 게시글 번호(num) 값을 전달받아, 그 값에 해당하는 게시글 필드를 memboard 테이블에서 검색한다.

    그 결과를 바탕으로 ($num, $title, $content, $writer, $write_time, $display_date, $views, $likes, $comments, $file_name) 변수에 해당 게시글의 (게시글 번호, 게시글 제목, 게시글 내용, 게시글 작성자 이름, 게시글 작성시간, 작성시간 출력 형태, 조회수, 추천수, 댓글수, 업로드된 파일 이름)을 저장한다.

  • 2. 게시글 전처리
    1) 작성시간 출력형태: 만약 게시글이 당일날 작성된 것이라면 작성된 시간만 출력하며, 게시글 작성후 자정이 지난 이후에는 작성날짜와 시간을 모두 출력한다.

    2) 조회수 카운트: mem_view.php 페이지를 호출하게 되면 현재 조회수(views) 값에 +1을 하여 조회수를 1씩 증가시킨다.

  • 3. 게시글 출력:
    1) 제목(title), 본문내용(content), 게시글 작성시간(display_time), 작성자 이름(writer), 조회수(views), 추천수(likes), 댓글수(comments)를 각 위치에 출력한다.

    2) 첨부파일이 존재하는 경우에만 첨부파일의 이름, 다운로드 버튼을 출력한다.

    3) 본인이 작성한 게시글인 경우에만 수정, 삭제 버튼을 출력한다. 그렇지 않은 경우에는 추천 버튼만 출력한다.

[2. 댓글 관련 부분]

  • 1. 댓글 영역:
    1) 게시글 하단에 (댓글 입력, 댓글 목록 출력) 영역이 위치한다.

    2) 출력되는 댓글 정보는 (댓글 작성자 닉네임, 작성시간, 댓글 내용) 이다.

    3) 댓글은 작성순서대로 출력되며, 본인이 쓴 댓글인 경우에만 댓글 삭제버튼이 출력된다.

  • 2. 댓글 정보 처리:
    1) 댓글을 작성하는 경우 게시글 번호(board_num), 게시글 내용(input_cmt)이 POST방식으로 comment_proc.php로 전달된다.

    2) 자신이 게시한 댓글을 삭제하는 경우 댓글 번호(commtent_id), 게시글 번호(board_num)이 GET방식으로 comment_delete.php로 전달된다.

  • 3. 댓글 출력
    1) comment 테이블에서 해당 게시글번호의 댓글 필드를 조회한다.

    2) mysqli_fetch_assoc() 함수를 통해, 결과값 배열에서 값을 하나씩 꺼내서 댓글 형태로 출력한다.

2. Backend

[1. 첨부파일 다운로드]

<download.php>

<?php
    session_start();

    if (!isset($_SESSION["user_id"])) {
        echo "<script>
            alert('회원만 다운로드할 수 있습니다.');
            location.href='../auth/login.php';
        </script>";
        exit;
    }

    if(!isset($_GET["num"])) {
        echo "<script>history.go(-1)</script>";
        exit;
    }

    include "../db/db_con.php";

    $sql = "select file_name, file_copy from memboard where num={$_GET['num']}";
    $result = mysqli_query($con, $sql);
    $row = mysqli_fetch_assoc($result);

    if ($row <= 0) {
        echo "<script>history.go(-1)</script>";
        exit;
    }

    $upload_dir = "../uploads/";
    $filepath = $upload_dir.$row["file_copy"];
    $filename = $row["file_name"];

    header("Content-Type: application/octet-stream");
    header("Content-Disposition: attachment; filename=\"" . basename($filename) . "\"");
    header("Content-Length: " . filesize($filepath));
    header("Pragma: no-cache");
    header("Expires: 0");

    readfile($filepath);
    exit;
?>
  • 1. 입력값 확인:
    1) 로그인된 회원만 다운로드 가능하므로, user_id 세션값이 할당되지 않았다면(비로그인 상태) 로그인 페이지로 이동

    2) 만약 다운로드 대상페이지 번호가 지정되지 않았다면 이전 페이지로 이동

  • 2. 파일 정보 불러오기:
    1) membaord 테이블에서 해당 게시글번호에 해당하는 파일 정보를 불러온다.

    2) 만약 조회 결과가 없다면 이전 페이지로 이동, 조회 결과가 있다면 filepath에 파일경로를, filename에는 원본 파일명을 저장한다.

  • 3. 다운로드 헤더 설정:
    1) Content-Type: application/octet-stream : 브라우저에게 해당 파일이 이진 데이터임을 알린다
    → 브라우저가 직접 열려고 하지 않고, 다운로드 처리하도록 강제한다.

    2) Content-Disposition: attachment; filename="..." : 파일을 첨부파일로 인식시켜 저장 창을 띄우도록 한다. filename은 다운로드시 사용자에게 보이는 파일이름으로서, 업로드한 원본 파일이름을 지정한다.

    3) Content-Length : 파일의 전체크기(byte)를 알려준다. 이 크기를 바탕으로 현재 다운로드 진행률 또는 남은 시간을 알려준다.

    4)Pragma: no-cache : 캐싱하지 않고 항상 서버에서 새로 받아오도록 지정

    5) Expires: 0 : 브라우저 캐시를 사용하지 않고, 항상 새로운 파일을 받아오도록 한다.


[2. 추천 기능]

<mem_edit.php 중에서 (나머지 부분은 다음장(게시글수정)에 정리)>

session_start();
$sql = "select * from likes where board_num=$num and user_id='{$_SESSION['user_id']}'";
$result = mysqli_query($con, $sql);

if (mysqli_num_rows($result) <= 0) {
    $sql = "insert into likes (board_num, user_id) values ($num, '{$_SESSION['user_id']}')";
    mysqli_query($con, $sql);

    $likes++;
    $views--;

    $sql = "update memboard set likes=$likes, views=$views where num=$num";
    mysqli_query($con, $sql);

    mysqli_close($con);

    echo "<script>location.href='mem_view.php?num=$num'</script>";
    exit;
}
else {
    echo "<script>
        alert('이미 추천한 글입니다.');
        location.href='mem_view.php?num=$num';
        exit;
    </script>";
}
  • 게시글 추천시:
    1) likes 테이블에 (현재 사용자 아이디, 추천을 누른 게시글의 번호) 정보를 추가한다.

    2) memboard 테이블에서 해당 게시글의 추천수 컬럼값을 1증가 시킨다.

    3) 만약 likes 테이블에 정보가 추가된 이후, 한번더 추천을 누르게 되면 이미 추천한 글이라는 알림을 띄운다. (게시글별 추천은 1회만 가능)

[3. 댓글 작성]

<comment_proc.php>

<?php
    session_start();
    include "../db/db_con.php";

    if (!isset($_SESSION["user_id"])) {
        echo "<script>
            alert('권한이 없습니다.');
            history.go(-1);
        </script>";
        exit;
    }

    $board_num = $_POST["board_num"];
    $user_id = $_SESSION["user_id"];
    $user_name = $_SESSION["user_name"];
    $content = $_POST["input_cmt"];
    
    if (empty($content)) {
        echo "<script>
            alert('댓글을 입력해주세요.');
            history.go(-1);
        </script>";
        exit;
    }

    $sql = "insert into comment (board_num, user_id, user_name, content) values ('$board_num', '$user_id', '$user_name', '$content')";
    mysqli_query($con, $sql);

    $sql = "select * from memboard where num = $board_num";
    $result = mysqli_query($con, $sql);
    $row = mysqli_fetch_assoc($result);
    $comments = $row["comments"];
    $comments++;
    $views = $row["views"];
    $views--;
    $sql = "update memboard set comments = $comments, views=$views where num = $board_num";
    mysqli_query($con, $sql);

    echo "<script>location.href='mem_view.php?num=$board_num'</script>";
?>

  • 1. 입력값 확인:
    1) 회원만 댓글 작성이 가능하므로, user_id 세션값을 확인하여 만약 값이 할당되지 않은 경우(비로그인 상태) 이전 페이지로 돌아간다.

    2) mem_view.php에서 사용자가 댓글을 입력한 경우 게시글 번호(board_num), 댓글 내용(input_cmt)를 전달받는다.
    → 만약 댓글 내용이 없는 경우 다시 댓글 작성 페이지로 돌아간다.

  • 2) 댓글 정보 업데이트:
    1) mem_view.php로부터 전달받은 (게시글번호, 댓글내용) 정보와, 세션에 저장되어있는 (user_id, user_name) 정보를 comment 테이블의 (board_num, user_id, user_name, content) 컬럼에 저장한다.

    2) memboard 테이블에서 해당 게시글 필드를 조회하여, 해당 필드의 댓글수(comments) 컬럼의 값을 1증가 시킨다.


[4. 댓글 삭제]

<comment_delete.php>

<?php
    session_start();
    include "../db/db_con.php";

    if (!isset($_SESSION["user_id"])) {
        echo "<script>
            alert('권한이 없습니다');
            history.go(-1);
        </script>";
        exit;
    }

    $comment_id = $_GET["comment_id"];
    $board_num = $_GET["board_num"];

    $sql = "delete from comment where id = $comment_id and board_num = $board_num";
    mysqli_query($con, $sql);

    $sql = "select * from memboard where num = $board_num";
    $result = mysqli_query($con, $sql);
    $row = mysqli_fetch_assoc($result);
    $comments = $row['comments'];
    $comments--;
    $views = $row["views"];
    $views--;
    
    $sql = "update memboard set comments = $comments, views = $views where num = $board_num";
    mysqli_query($con, $sql);

    echo "<script>location.href='mem_view.php?num=$board_num'</script>";
?>

  • 1. 세션 확인:
    회원게시판의 댓글이므로 user_id 세션값이 없다면(비로그인 상태) 이전 페이지로 돌아간다.

  • 2. 댓글 삭제 처리:
    1) comment 테이블에서 GET방식으로 전달받은 댓글 번호(comment_id), 게시글 번호(board_num) 와 일치하는 필드를 삭제한다.

    2) memboard에서 해당 게시글 번호(board_num)값을 가지는 게시글 필드를 조회하여, 댓글수(comments) 컬럼의 값을 1감소 시킨다.


3. 동작 정리

1. 회원게시판 - 게시글확인 페이지 기본 화면



2. 첨부파일 출력 여부
↑ 첨부파일 존재하는 경우 (첨부파일 다운로드 버튼 출력)
↑ 첨부파일 존재하지 않는 경우 (파일 관련 내용 출력 X)



3. 수정/삭제 버튼 출력 여부
↑ 게시글 작성자가 본인인 경우 (게시글 수정 / 삭제) 버튼 출력
↑ 타 이용자 게시글의 경우, 추천 버튼만 출력



4. 파일 다운로드 클릭 (영상)



4. 추천 클릭 (영상)
○ 게시글 당 추천한 1번만 가능



5. 댓글 작성 (영상)



5. 댓글 삭제 (영상)

0개의 댓글