[Web Application-개발] 2024-01-10 웹 어플리케이션 제작 프로젝트 : 게시판 만들기 #9-5

2024. 1. 10. 14:27Project/Web Application-개발

 

프로젝트 일지

 

  지난 작업에서 게시판의 필수적인 기능 대부분을 구현하였고 이제부터 추가되는 기능들은 선택 사항에 해당된다. 다음으로 구현할 기능은 게시글 작성 시 글로만 표현하기에는 심심하여 이미지 파일을 업로드하여 게시글 내용을 이해하기 쉽도록 도와준다거나, 아니면 게시글을 읽는 사람들에게 파일을 공유하는 목적으로 파일을 업로드하고 다운로드할 수 있게 하는 기능인 파일 업로드/다운로드를 구현할 예정이다.

 

파일 업로드/다운로드 기능 설명

 

  파일 업로드 기능을 구현 하기 위해서 추가되는 코드들과 그 코드들이 어떤 역할을 하는지 알아보고 결과적으로 파일 업로드가 어떤 흐름으로 진행되는지 file_upload.php 페이지에서 알아보도록 하자.

 

 

1) file_upload.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>파일 업로드</title>
</head>
<body>
 
  <form name="fileUpload" method="post" action="/file_upload_proc.php" enctype="multipart/form-data">
    <input type="file" name="imgFile" />
    <input type="submit" value="업로드" />
  </form>
  
</body>
</html>
cs

file_upload.php 페이지 코드 및 출력화면

 

  file_upload.php 페이지의 간단한 코드와 출력 화면이다. file_upload.php 페이지에서는 선택한 파일을 등록하고 서버로 전달하는 기능이 구현되어 있다. 파일 업로드 기능 구현 시 추가되는 코드는 다음과 같다.

 

[1] enctype="multipart/form-data"

 

  form 태그는 데이터를 전달할 때 사용하는 태그이며 form 태그의 속성 중 enctype이 존재한다. enctype 속성은 전달할 데이터의 형식을 결정하는 속성으로 3가지 속성값이 존재한다.

 

  • application/www-form-urlencoded : enctype 속성의 기본값으로 설정되어있으며 생략 시 해당 속성값으로 적용된다. 데이터 전달 시 URL-Encode 한 상태로 전달한다.
  • multipart/form-data : 파일이나 이미지 파일 전달 시 enctype의 속성값으로 설정해줘야하 한다. 그렇지 않으면 데이터 전달 시 파일의 경로명만 전송되고 파일 내용이 전송되지 않는다. 또한 enctype이 해당 속성값으로 설정되면 method의 속성값은 POST로 설정해줘야 한다.
  • text/plain : 해당 속성값은 인코딩하지 않은 그대로 데이터를 전송한다.

  파일 업로드를 하기 위해서는 enctype 속성값을 "multipart/form-data"로 설정해줘야 하며 method 속성값은 "POST"로 설정해 줘야하 한다.

 

[2] type="file"

 

  input 태그의 속성 중 type 속성값을 "file"로 설정해 준 태그로 파일을 등록할 수 있다. 위 file_upload.php 페이지 출력에서 보이듯이 '파일 선택' 버튼을 클릭하게 되면 로컬 컴퓨터에서 파일을 선택 후 '업로드' 버튼을 클릭하게 되면 서버로 파일을 전송하게 된다.

 

 

2) file_upload_proc.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
 
    // 임시 저장된 정보
    $file_tmp_name = $_FILES['imgFile']['tmp_name'];
 
    // 파일명을 기존의 파일명을 그대로 쓰고 싶은 경우
    $file_name = $_FILES['imgFile']['name'];
 
    // 파일 타입 및 확장자 구하기
    $file_type_extension = explode("/"$_FILES['imgFile']['type']);
 
    // 파일 타입
    $file_type = $file_type_extension[0];
    
    // 파일 확장자
    $file_extention = $file_type_extension[1];
 
    // 임시 파일 옮길 폴더 및 파일명
    $file_path = "upload_folder/".$file_name;
 
    // 임시 저장된 파일을 우리가 저장할 장소 및 파일명으로 옮김
    move_uploaded_file($file_tmp_name$file_path);
?>
 
<img src="<?= $file_path;?>"/><br>
<a href="<?= $file_path;?>" download>file_download</a>
cs
file_upload_proc.php 페이지 코드 및 출력화면

 

  file_upload_proc.php 페이지의 코드와 출력 화면이다. file_upload_proc.php 페이지는 file_upload.php 페이지에서 등록한 파일이 전달되어 출력하는 기능이 구현되어 있다. 데이터로 파일이 전달되면 어떤 형태로 전달되는지 먼저 알아보자.

 

[1] $_FILES['첫번째 인자']['두번째 인자']

 

  데이터로 파일이 전달되어 서버로 도착하면 파일에 대한 정보들은 $_FILES라는 전역변수로 저장된다. $_FILES 변수는 2차 배열로 이루어져 있으며 '첫번째 인자'는 파일 전달 시 input 태그의 name 속성값이며, '두번째 인자'는 각 파일마다의 정보를 나타내는 인자들이다. $_FILES의 두번째 인자들은 다음과 같이 존재한다.

 

  • $_FILES['파일 이름']['name'] : 파일 업로드 시 파일 명
  • $_FILES['파일 이름']['tmp_name'] : 파일 업로드 후 파일이 저장되는 임시 경로
  • $_FILES['파일 이름']['type'] : 파일의 형식과 확장자, '형식/확장자' 형태의 문자열로 이루어짐
  • $_FILES['파일 이름']['size'] : 파일 크기
  • $_FILES['파일 이름']['error'] : 파일 업로드 시 나타나는 에러를 구분하는 값, 출력되는 값에 따라 에러를 구분가능

 

  전달되는 파일에 대한 정보가 저장된 변수만으로는 파일 업로드 및 다운로드하는 기능을 사용할 수 없기에 별도의 가공 과정이 진행된다. $_FILES 변수를 가공하는 과정은 사람마다 다르기 때문에 참고 정도로만 생각한다.

 

  1. $_FILES 변수들을 각 변수에 나누어 저장한다.
  2. $_FILES['첫번째 인자']['type'] 변수는 explode 함수를 사용하여 파일의 형식과 확장자를 나타내는 문자열을 분리하여 저장한다.
  3. 업로드된 파일이 저장될 경로를 생각하여 파일 경로를 저장하는 변수를 생성한다.
  4. move_uploaded_file 함수를 사용하여 임시로 저장된 파일경로를 변경한다.
  5. 추가적으로 개발자가 의도한 파일의 형식이나 확장자, 크기 등 조건을 검사한다.
  6. DB가 연동되어 있는 경우 업로드된 파일이 저장되는 경로를 DB에 저장한다.

 

  위 내용에 대해 이해에 어려움이 없다면 file_upload_proc.php 페이지의 코드가 어떤 의도로 입력되었는지 무리 없이 이해가 가능할 것이다.

 

[2] img 태그

 

  img 태그는 이미지 파일을 출력해 주는 태그이다. img 태그의 속성은 여러 가지가 존재하며 필요에 따라 검색하여 사용하면 된다. 그러나 필수적으로 입력해줘야 하는 속성이 존재하는데 그것은 이미지 파일의 경로를 명시하는 src 속성이다. 

 

[3] a 태그

 

  a 태그는 주로 하이퍼 링크 기능을 구현할 때 사용되는 태그로서 파일 다운로드 기능을 구현할 때에도 사용한다. 파일 다운로드 기능을 구현하기 위해서는 먼저 href 속성값에 업로드된 파일이 저장된 경로를 입력한다. 그리고 download 속성을 입력해 주면 다운로드 기능이 활성화된다. value 속성값은 생략하면 파일이 저장된 이름으로 표시되며 따로 지정해 주면 지정해 준 문자열로 표시된다. file_upload_proc.php 페이지에서는 value 속성값으로 'file_download'으로 설정해 주었다.

 

  지금까지 설명한 내용은 파일 업로드 및 다운로드 기능을 구현하기 위해 필수적이다. 이제 개발한 게시판 페이지에 파일 업로드 및 다운로드 기능을 구현하기 위해 코드들을 추가하여 정상적으로 작동하는지 확인한다.

 

 

파일 업로드/다운로드 기능 구현

 

 

1) board_crud.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script type = "text/javascript" src="/js/board.js?ver=1"></script>
    <title>CRUD</title>
</head>
<body>
    <?php
        session_start();
        require_once("db.php");
 
        $mode=$_GET['mode'];
        $num=$_GET['num'];
 
        // 권한이 필요한 모드(c,u,d)일 경우 세션 ID가 없으면 로그인 페이지로 안내
        if(!isset($_SESSION['user_id']) && ($mode == 'c'|| $mode == 'u' || $mode == 'd'))
        {
            echo "<script>alert('로그인 되어 있지 않습니다. 로그인 페이지로 이동합니다.')</script>";
            echo "<script>window.location.replace('http://192.168.74.128:1018/php/login.php')</script>";
            exit();
        }
 
        else  
        {?>
            <form id="f" method="POST" action="/php/board_proc.php" style="text-align:center;" onsubmit='return check_write();' enctype="multipart/form-data">
            <?php
            // 제목 타고 들어옴 mode=r,mode=u
            if($mode == 'r' || $mode == 'u')
            {
                $result=db_select_board("test_board",$num);
                $row = mysqli_fetch_array($result);
                
                if($mode == 'r'){?>
 
                    <textarea id="title" rows="1" name="title" style="resize:none;width: 50%;font-size: 30px;" readonly><?= $row['title'];?></textarea><br>
                    <textarea id="content" rows="30" name="content" style="resize:none;width: 50%;font-size: 20px;" readonly><?= $row['content'];?></textarea><br>
 
                    <img src="<?= $row['file_name'];?>">
 
                    <button type = "button" onClick = "location.href = '/php/board.php'"> 목록으로 </button>
 
                    <?php
                    // 작성자와 로그인한 사용자가 같은 경우
                    if($_SESSION['user_id'== $row['user_id'])
                    {?>
                        <button type = "button" onClick = "location.href = '/php/board_crud.php?mode=u&num=<?= $num ?>'"> 수정 </button>
                        <button type = "button" onClick = "location.href = '/php/board_crud.php?mode=d&num=<?= $num ?>'"> 삭제 </button>
                    <?php
                    }
                                            
                }
 
                else{?>
                    <textarea id="title" rows="1" name="title" style="resize:none;width: 50%;font-size: 30px;"><?= $row['title'];?></textarea><br>
                    <textarea id="content" rows="30" name="content" style="resize:none;width: 50%;font-size: 20px;"><?= $row['content'];?></textarea><br>
 
                    <img src="<?= $row['file_name'];?>">          
 
                    <input type = "hidden" name= "mode" value="u">
                    <input type = "hidden" name= "num" value="<?= $num ?>">
 
                    <input type = file name="upload_file"><br><br>
 
                    <button type = "button" onClick = "location.href = '/php/board.php'"> 목록으로 </button>
                    <button type = "button" onClick = "location.href = '/php/board_crud.php?mode=r&num=<?= $num ?>'"> 취소 </button>
                    <button type = "submit"> 저장 </button>
                <?php    
                }
            }
 
            else if($mode == 'c')
            {?>
                <textarea id="title" rows="1" name="title" placeholder="제목을 입력하세요" style="resize:none;width: 50%;font-size: 30px;"></textarea><br>
                <textarea id="content" rows="30" name="content" placeholder="내용을 입력하세요" style="resize:none;width: 50%;font-size: 20px;"></textarea><br>
                <input type = "hidden" name= "mode" value="c">
                
                <input type = file name="upload_file"><br><br>
 
                <button type = "button" onClick = "location.href = '/php/board.php'"> 목록으로 </button>
                <button type = "submit"> 작성 </button>
            <?php
            }
 
            else if($mode == 'd')
            {
                db_delete_board("test_board",$num);
                echo "<script>alert('삭제되었습니다.')</script>";
                echo "<script>window.location.replace('http://192.168.74.128:1018/php/board.php')</script>";
            }
 
            else
            {   
                echo "<script>alert('잘못된 명령입니다.')</script>";
                echo "<script>window.location.replace('http://192.168.74.128:1018/php/board.php')</script>";
                exit();
            }      
            
            ?></form><?php
        }
    ?>
 
</body>
</html>
 
cs

 

  board_crud.php 페이지에서 추가되는 부분은 27, 40, 59, 64, 79라인이며 같은 기능을 구현하는 라인끼리 묶어 설명한다.

 

[1] 27라인 : form 태그

1
<form id="f" method="POST" action="/php/board_proc.php" style="text-align:center;" onsubmit='return check_write();' enctype="multipart/form-data">
cs

 

  27라인 코드는 form 태그로서 데이터 전달 기능을 담당한다. 파일을 전달하기 위해서는 form 태그의 속성인 enctype의 속성값을 "multipart/form-data"으로, method="POST"로 입력해 준다.

 

[2] 40, 59라인 : img 태그

1
<img src="<?= $row['file_name'];?>">
cs

 

  40, 59라인 코드는 img 태그로서 이미지 파일 출력 기능을 담당한다. src 속성값으로 이미지 파일이 저장된 경로를 입력해 주면 이미지 파일을 출력해 준다.

 

[3] 64, 79라인 : input 태그

1
<input type = file name="upload_file"><br><br>
cs

 

  64, 79라인 코드는 input 태그로서 파일을 등록할 수 있는 기능을 담당한다. input 태그의 속성 중 type의 속성값을 file로 입력해 주면 파일을 선택하여 등록할 수 있다.

 

 

2) board_proc.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?php
 
    session_start();
 
    if(!isset($_SESSION['user_id'])) // 로그인 되어있지 않다면 로그인 페이지로 안내
    {
        echo "<script>alert('로그인 되어 있지 않습니다. 로그인 페이지로 이동합니다.')</script>";
        echo "<script>window.location.replace('http://192.168.74.128:1018/php/login.php')</script>";
    }
 
    else 
    {
        require_once("db.php");
 
        // 글쓰기 페이지에서 전송된 변수 저장
        $post = array(
 
            'id' => $_SESSION['user_id'],
            'title' => $_POST['title'],
            'content' => $_POST['content'],
            'mode' => $_POST['mode'],
            'page' => $_POST['num']
        );
 
        // 임시 저장된 정보
        $file_tmp_name = $_FILES['upload_file']['tmp_name'];
 
        // 파일명을 기존의 파일명을 그대로 쓰고 싶은 경우
        $file_name = $_FILES['upload_file']['name'];
 
        // 임시 파일 옮길 폴더 및 파일명
        $file_path = "upload_folder/".$file_name;
        // 임시 저장된 파일을 우리가 저장할 장소 및 파일명으로 옮김
       move_uploaded_file($file_tmp_name$file_path);
 
        
        if($post['mode'== 'c')
        {
            db_insert_to_board($post['id'],$post['title'],$post['content'],$file_path);
            echo "<script>alert('글을 성공적으로 작성하였습니다. 게시판 페이지로 이동합니다.')</script>";
            echo "<script>window.location.replace('http://192.168.74.128:1018/php/board.php')</script>";
        }
 
        else
        {
            db_update_board("test_board"$post['title'], $post['content'],$post['page'],$file_path);
            echo "<script>alert('글이 성공적으로 변경되었습니다. 게시판 페이지로 이동합니다.')</script>";
            echo "<script>window.location.replace('http://192.168.74.128:1018/php/board.php')</script>";
        }
 
    }
 
 
?>
cs

 

  board_proc.php 페이지에서 추가되는 부분은 26, 29, 32, 34라인이다. 각 라인이 어떤 기능을 담당하는지 설명한다.

 

[1] 26 라인

1
2
3
4
5
<?php
 
$file_tmp_name = $_FILES['upload_file']['tmp_name'];
 
?>
cs

 

  26라인 코드는 전달된 파일이 임시로 저장된 경로를 $file_tmp_name 변수에 저장하는 코드이다.

 

[2] 29 라인

1
2
3
4
5
<?php
 
$file_name = $_FILES['upload_file']['name'];
 
?>
cs

 

  29라인 코드는 전달된 파일의 이름을 $file_name 변수에 저장하는 코드이다.

 

[3] 32라인

1
2
3
4
5
<?php
 
$file_path = "upload_folder/".$file_name;
 
?>
cs

 

  32라인 코드는 전달된 파일이 웹 서버에 저장되는 경로를 $file_path 변수에 저장하는 코드이다. 이 코드는 upload_folder 폴더에 업로드된 파일을 저장한다.

 

[4] 34 라인

1
2
3
4
5
<?php
 
move_uploaded_file($file_tmp_name$file_path);
 
?>
cs

 

  34라인 코드는 임시로 저장된 경로를 지정한 경로로 변경하는 코드이다. 이 코드는 $file_tmp_name 변수에 저장된 경로를 $file_path 변수에 저장된 경로로 변경한다.

 

 

작동 화면

 

 

 

앞으로 할 작업

 

  • 파일 업로드 시 파일 전용 테이블 생성
  • 파일 업로드 시 조건 설정 코드 추가(형식, 확장자, 크기 등)
  • DB에 저장된 게시글 정보 출력 시 파일 존재 유무에 따라 출력되는 코드 설정
  • 웹 페이지 디자인