[11. 회원게시판 - 게시글 작성 (+파일첨부기능)]

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

개발 대상은 [회원게시판 - 게시글 작성] 페이지이다.
자유게시판(비회원게시판) 과 차이점은 파일첨부가 가능하다.
구성은 다음과 같다.

mem_wirte.php : 게시글 작성 양식 페이지
memwrite_proc.php : 게시글 작성 처리 페이지
board_edit.css : 게시글 관련 CSS


0. 테이블 구조

memboard

1. Frontend

<mem_write.php>

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

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>회원 게시판</title>
        <link rel="stylesheet" href="../css/board_edit.css?v=<?=time()?>">
    </head>
    <body>
        <?php include "../include/header.php" ?>
        <h2>게시글 작성</h2>

        <div class="edit-container">
            <form class="edit-form" method="post" action="memwrite_proc.php" enctype="multipart/form-data">
                <div class="edit-row">
                    <label for="input_title">제목 <i class="fa-solid fa-pen-to-square"></i></label>
                    <input id="input_title" name="input_title" type="text" placeholder="제목 입력">
                </div>

                <label for="input_cont">본문 <i class="fa-solid fa-pen-to-square"></i></label>
                <textarea id="input_cont" name="input_cont" placeholder="내용을 입력하세요"></textarea>

                <div class="edit-row">
                    <label for="input_file">파일 첨부 <i class="fa-solid fa-paperclip"></i></label>
                    <input type="file" id="input_file" name="input_file">
                </div>

                <div class="edit-actions">
                    <input type="submit" value="작성">
                    <input type="button" onclick="location.href='mem_list.php'" value="목록으로">
                </div>
            </form>
        </div>
    </body>
</html>
mem_write.php

  • 1. 세션 체크 :
    회원게시판은 로그인된 회원만 사용가능하므로, 로그인 상태가 아닌 경우(user_id 세션값 미존재) 로그인 페이지로 돌려보낸다.

  • 2. 입력값 처리:
    Input 값은 모두 POST 방식으로 memwrite_proc.php로 전달된다.

    파일 업로드 시에는 반드시 enctype="multipart/form-data" 속성을 추가해주어야 한다. 그렇지 않으면 $_FILES가 항상 비어있게 된다.

    사용자가 입력한 제목(input_title), 본문(input_cont), 파일(input_file)은 POST 방식으로 memwrite_proc.php에 전달된다.


2. Backend

<memwrite_proc.php>

<?php
    session_start();
    date_default_timezone_set("Asia/Seoul");

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

    $input_title = $_POST["input_title"];
    $user_id = $_SESSION["user_id"];
    $user_name = $_SESSION["user_name"];
    $input_cont = $_POST["input_cont"];

    if (empty($input_title)) {
        echo "<script>
            alert('게시글 제목을 입력해주세요');
            history.go(-1);
        </script>";
        exit;
    }


    /* 파일 처리 부분 */
    if (isset($_FILES["input_file"]["name"]))
        $file_name = $_FILES["input_file"]["name"];
    else
        $file_name = "";


    if (isset($_FILES["input_file"]["tmp_name"]))
        $file_tmp = $_FILES["input_file"]["tmp_name"];
    else
        $file_tmp = "";


    if (isset($_FILES["input_file"]["error"]))
        $file_error = $_FILES["input_file"]["error"];
    else
        $file_error = 4;

    $file_copy = "";


    if ($file_error === UPLOAD_ERR_OK && $file_name != "") {
        $ext = pathinfo($file_name, PATHINFO_EXTENSION); // 확장자 추출
        $file_copy = date("Ymd_His") . "." . $ext;

        $upload_dir = "../uploads/";

        if (!move_uploaded_file($file_tmp, $upload_dir . $file_copy)) {
            echo "<script>
                alert('파일 업로드에 실패하였습니다.');
                history.go(-1);
            </script>";
            exit;
        }
    }

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

    $sql = "insert into memboard (title, content, user_id, user_name, file_name, file_copy) values
                                  ('$input_title', '$input_cont', '$user_id', '$user_name', '$file_name', '$file_copy')";
    mysqli_query($con, $sql);
    mysqli_close($con);

    echo "<script>
        alert('게시글이 작성되었습니다');
        location.href='./mem_list.php';
    </script>"
?>

[1. 초반 처리]

  • 1. 세션확인
    로그인 완료된 회원만 글쓰기(처리)가 가능하므로, user_id 세션값이 존재하지 않는다면(비로그인 상태) 로그인페이지로 이동시킨다.

  • 2. 현재시간 동기화
    PHP는 기본적으로 서버 OS 시간대를 따라가므로, 한국시간과 맞지 않는다. 따라서 동기화를 위해 date_default_timezone_set() 를 추가해준다.

[2. 게시글 정보 부분]

  • 1. 게시글 제목 & 본문 내용:
    게시글의 제목과 본문 값은 mem_write.php에서 POST방식으로 보낸 input_title 값과, input_cont 값을 받아 저장한다.

  • 2. 입력값 확인:
    만약 게시글 제목이 입력되어있지 않다면, 이전페이지로 돌려보낸다.

  • 3. 게시글 작성자 정보:
    게시글을 작성한 사용자의 정보는 로그인후 할당된 세션에 저장된 user_id, user_name 값을 받아 저장한다.


[3. 파일 처리 부분]

  • 1. 파일 정보 저장:
    1) $file_name 에는 사용자가 업로드한 파일의 원래 이름이 저장된다. (ex. 보고서.docx)

    2) $file_tmp 에는 PHP가 임시로 저장한 업로드 파일의 경로가 저장된다.
    → 파일을 업로드하여도 사용자가 지정한 upload 파일로 바로 들어가는 것이 아닌, 서버의 임시 폴더에 저장되어 있다. 이를 이후에 옮겨주는 처리를 해주어야 한다.

    3) $file_error 에는 파일 업로드 과정에서 발생한 에러 코드가 저장된다.
    → 정상 업로드: UPLOAD_ERR_OK (0)
    → 업로드 오류: UPLOAD_ERR_NO_FILE (4)

    4) $file_copy 에는 서버에 저장될 파일명이 저장된다. 파일이름 충돌을 방지하기 위해 서버에서 저장되는 새로운 파일명을 저장한다.

  • 2. 파일 데이터 업로드:
    1) 만약 파일이 정상 업로드된 경우(error=0) 처리를 시작한다.

    2) $ext에는 pathinfo() 함수를 통해 추출한 파일의 확장자를 저장한다.

    3) $file_copy에는 업로드 날짜+시간을 붙혀 새로운 파일명을 저장한다. (ex. 20250911_130417.docx)

    4) move_uploaded_file(임시경로, 최종경로) 함수를 사용하여 tmp에 저장되어 있던 임시 파일을 uploads/ 디렉토리로 옮긴다.

[4. DB에 저장]

  • 회원게시판 테이블에 정보 저장:
    1) 위에서 처리한 내용을 바탕으로 테이블의 (title, content, user_id, user_name, file_name, file_copy) 컬럼에 ($input_title, $input_cont, $user_id, $user_name, $file_name, $file_copy) 값을 저장한다.

    2) 게시글 작성이 완료되면, 회원게시판 게시글 목록 페이지(mem_list.php)로 이동한다.

3. 동작 정리

1. 게시글 작성 페이지 기본 화면



2. 게시글 내용 작성 & 파일 첨부



3. 작성시



4. DB 처리 결과



5. 디렉토리에 업로드 결과

0개의 댓글