📚 PHP 중급 - 4주차: 파일 업로드 및 이미지 처리 - 01 HTML 폼을 이용한 파일 업로드

2025. 7. 24. 15:13프로그램/PHP 중급

📚 PHP 중급 - 4주차: 파일 업로드 및 이미지 처리 - 01 HTML 폼을 이용한 파일 업로드

📚 PHP 중급 - 4주차: 파일 업로드 및 이미지 처리 - 01 HTML 폼을 이용한 파일 업로드



안녕하세요! #PHP 중급 과정 4주차입니다. 오늘은 #웹_애플리케이션에서 가장 흔하게 접하는 기능 중 하나인 #파일_업로드(File Upload)에 대해 자세히 알아보겠습니다. 특히 사용자가 #HTML #폼(Form)을 통해 파일을 서버로 전송하는 기본적인 과정을 다룰 거예요. #게시판에 #이미지를 첨부하거나 #프로필_사진을 변경하는 등 다양한 곳에 활용될 수 있는 중요한 기능이니 함께 살펴볼까요?

 


1. 파일 업로드의 개요 및 보안 고려사항

#파일_업로드는 사용자의 로컬 #PC에 있는 #파일을 #웹_서버로 전송하는 과정입니다. 이 과정은 단순히 파일을 옮기는 것을 넘어, #보안(Security)에 대한 깊은 이해를 요구합니다. 악의적인 사용자가 #웹_셸(Web Shell)이나 #바이러스(Virus)를 포함한 #악성_파일을 업로드하여 #서버를_공격할 수 있기 때문이죠.

 

따라서 #파일_업로드 기능을 구현할 때는 다음과 같은 #보안_고려사항을 반드시 지켜야 합니다.

 

  • #확장자_검사: 업로드 가능한 #파일_형식을 엄격하게 제한해야 합니다. (예: .jpg, .png, .gif만 허용)
  • #MIME_타입_검사: #HTTP_헤더에 포함된 #MIME_타입 정보도 확인하여 #확장자_위변조를 막아야 합니다.
  • #파일_크기_제한: 너무 큰 파일 업로드를 막아 #서버_과부하(Server Overload)나 #서비스_거부_공격(DoS Attack)을 방지합니다.
  • #파일_이름_변경: 업로드된 파일 이름을 무작위 문자열로 변경하여 #경로_탐색_공격(Path Traversal Attack)이나 #파일_덮어쓰기를 방지합니다.
  • #업로드_디렉터리_분리: 웹에서 직접 접근할 수 없는 별도의 #디렉터리에 저장하고, 필요시 #스크립트를 통해 접근하게 합니다.
  • #웹_서버_설정_강화: #PHP 설정(php.ini)에서 #파일_업로드 관련 제한(upload_max_filesize, post_max_size 등)을 적절히 설정합니다.

 


2. HTML 폼(Form) 설정

#파일_업로드를 위한 #HTML #폼은 일반적인 폼과 몇 가지 중요한 차이점이 있습니다.

 

2-1. enctype="multipart/form-data"

 

#파일_업로드 폼에서 가장 중요한 속성입니다. 이 속성이 없으면 파일 데이터가 서버로 제대로 전송되지 않습니다. #multipart/form-data는 폼 데이터와 파일 데이터를 함께 전송할 수 있도록 인코딩하는 방식입니다.

 

2-2. method="POST"

 

#파일_데이터는 #URL에 포함될 수 없으므로, 반드시 #POST_메서드를 사용해야 합니다.

 

2-3. <input type="file" name="file_upload">

 

#파일_선택_필드를 생성합니다. name 속성은 PHP에서 파일을 받을 때 사용될 #변수_이름이 됩니다. 여러 파일을 한 번에 업로드하려면 multiple 속성을 추가할 수 있습니다.

 

upload_form.html 예시:

HTML
 
<!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: 50px; }
        form { background-color: #f9f9f9; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); width: 400px; margin: auto; }
        h2 { text-align: center; color: #333; }
        label { display: block; margin-bottom: 8px; font-weight: bold; }
        input[type="file"] { margin-bottom: 15px; border: 1px solid #ddd; padding: 8px; border-radius: 4px; background-color: #fff; width: calc(100% - 18px); }
        input[type="submit"] { background-color: #007bff; color: white; padding: 10px 15px; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; width: 100%; }
        input[type="submit"]:hover { background-color: #0056b3; }
    </style>
</head>
<body>
    <h2>파일 업로드</h2>
    <form action="upload_process.php" method="POST" enctype="multipart/form-data">
        <label for="my_file">업로드할 파일 선택:</label>
        <input type="file" name="my_file" id="my_file" required>
        <input type="submit" value="파일 업로드">
    </form>
</body>
</html>

 


3. PHP에서 파일 업로드 처리

#PHP는 업로드된 #파일_데이터를 전역 변수인 #$_FILES를 통해 접근할 수 있게 합니다. 이 #$_FILES 배열은 업로드된 각 파일에 대한 정보를 담고 있습니다.

 

$_FILES 배열의 구조

 

$_FILES['input_name']은 다음과 같은 정보를 포함합니다. (여기서 input_name은 HTML input type="file"의 name 속성 값입니다.)

  • name: 클라이언트 #PC에 있는 #원본_파일_이름
  • type: 파일의 #MIME_타입 (예: image/jpeg, text/plain)
  • tmp_name: #서버에_임시로_저장된_파일의_경로와_이름
  • error: #파일_업로드_시_발생한_오류_코드 (#UPLOAD_ERR_OK는 오류 없음을 의미)
  • size: 업로드된 #파일의_크기(바이트 단위)

 

파일 업로드 처리 로직 (PHP)

 

upload_process.php 파일에서 실제 파일 업로드 처리 및 #보안_검사를 수행합니다.

 

PHP
 
<?php
// upload_process.php

// 1. 업로드 디렉토리 설정 (반드시 웹 접근 불가능한 상위 경로에 두는 것이 보안상 좋음)
$upload_dir = './uploads/'; // 현재 스크립트가 있는 폴더 하위의 'uploads' 폴더

// 'uploads' 폴더가 없으면 생성 (권한 0755)
if (!is_dir($upload_dir)) {
    mkdir($upload_dir, 0755, true);
}

// 2. 파일 업로드 오류 확인
// UPLOAD_ERR_OK: 파일 업로드 성공
if (!isset($_FILES['my_file']) || $_FILES['my_file']['error'] !== UPLOAD_ERR_OK) {
    switch ($_FILES['my_file']['error']) {
        case UPLOAD_ERR_INI_SIZE:
        case UPLOAD_ERR_FORM_SIZE:
            echo "업로드 파일 크기가 PHP 설정 또는 폼에서 허용된 최대 크기를 초과했습니다.";
            break;
        case UPLOAD_ERR_NO_FILE:
            echo "파일이 업로드되지 않았습니다.";
            break;
        default:
            echo "파일 업로드 중 알 수 없는 오류가 발생했습니다. 오류 코드: " . $_FILES['my_file']['error'];
            break;
    }
    exit;
}

// 3. 업로드된 파일 정보 가져오기
$file_name = $_FILES['my_file']['name']; // 원본 파일 이름
$file_type = $_FILES['my_file']['type']; // MIME 타입
$file_tmp_name = $_FILES['my_file']['tmp_name']; // 임시 파일 경로
$file_size = $_FILES['my_file']['size']; // 파일 크기

// 4. 보안 검사 (매우 중요!)

// 4-1. 파일 크기 제한 (예: 5MB)
$max_file_size = 5 * 1024 * 1024; // 5MB
if ($file_size > $max_file_size) {
    echo "파일 크기가 너무 큽니다. (최대 5MB)";
    exit;
}

// 4-2. 허용된 파일 확장자 및 MIME 타입 설정
$allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'pdf'];
$allowed_mime_types = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf'];

// 파일 확장자 추출 및 소문자로 변환
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));

// MIME 타입 검사 ($_FILES['type']은 클라이언트에서 제공하므로 위조 가능성 있음)
// 실제 파일의 MIME 타입을 검사하는 방법이 더 안전하나, 여기서는 기본적인 검사만 포함
if (!in_array($file_ext, $allowed_extensions) || !in_array($file_type, $allowed_mime_types)) {
    echo "허용되지 않는 파일 형식입니다. (허용: JPG, JPEG, PNG, GIF, PDF)";
    exit;
}

// 5. 파일 이름 변경 (보안을 위해 필수)
// 유니크한 파일 이름 생성 (예: 현재 시간을 기반 + 원본 확장자)
$new_file_name = uniqid() . '.' . $file_ext;
$destination = $upload_dir . $new_file_name; // 저장될 최종 경로

// 6. 임시 파일을 최종 목적지로 이동
// move_uploaded_file() 함수는 업로드된 임시 파일을 안전하게 이동시킵니다.
if (move_uploaded_file($file_tmp_name, $destination)) {
    echo "파일이 성공적으로 업로드되었습니다.<br>";
    echo "저장된 파일명: " . htmlspecialchars($new_file_name) . "<br>";
    echo "파일 경로: " . htmlspecialchars($destination) . "<br>";
    echo "<img src='" . htmlspecialchars($destination) . "' alt='업로드된 이미지' style='max-width:300px;'>";
} else {
    echo "파일 업로드에 실패했습니다.";
}
?>

 


4. PHP 설정 (php.ini) 확인

#PHP의 #php.ini 설정 파일에는 #파일_업로드와 관련된 중요한 지시어들이 있습니다.

 

  • file_uploads = On: 파일 업로드 기능을 활성화합니다. (기본값 On)
  • upload_max_filesize = 2M: 개별 파일 업로드의 최대 크기를 설정합니다. (예: 2M은 2메가바이트)
  • post_max_size = 8M: #POST_요청으로 전송될 수 있는 전체 데이터의 최대 크기를 설정합니다. (upload_max_filesize보다 크거나 같아야 합니다.)
  • upload_tmp_dir =: 업로드된 파일이 임시로 저장될 디렉터리를 지정합니다. (설정하지 않으면 시스템 기본 임시 디렉터리 사용)
  • max_file_uploads = 20: 한 번의 요청으로 업로드할 수 있는 최대 파일 개수입니다.

 

이 값들을 웹 서버의 요구사항과 애플리케이션의 필요에 맞게 조정해야 합니다. 변경 후에는 #웹_서버(Apache, Nginx 등)를 #재시작해야 적용됩니다.

 

오늘은 #HTML #폼을 이용한 #파일_업로드의 기본적인 구현 방법과 #보안_고려사항에 대해 알아보았습니다.