2025. 7. 25. 09:38ㆍ프로그램/PHP 중급
📚 PHP 중급 - 4주차: 파일 업로드 및 이미지 처리 - 02 $_FILES 슈퍼 글로벌 변수

지난 시간에는 #HTML #폼을 이용해 #파일을_업로드하는 기본적인 방법과 #보안_고려사항에 대해 알아보았습니다. 이제 사용자가 전송한 #파일_데이터가 #PHP 스크립트에서 어떻게 접근되고 처리되는지에 대한 핵심인 #$_FILES #슈퍼_글로벌_변수(Super Global Variable)에 대해 깊이 있게 다뤄보겠습니다. #$_FILES 변수를 정확히 이해하고 활용하는 것이 #안전하고 #효율적인 #파일_업로드_처리(#File Upload Handling)의 시작입니다.
1. $_FILES 슈퍼 글로벌 변수의 이해

#$_FILES는 #PHP가 #HTTP_POST_메서드를 통해 #업로드된_파일의_정보를_자동으로_수집하여_저장하는 #연관_배열(Associative Array)입니다. 이 변수는 오직 #enctype="multipart/form-data"로 설정된 #HTML #폼에서만 유효하게 채워집니다.
$_FILES 배열은 #폼의 #input type="file" 태그의 #name 속성 값을 #키(Key)로 사용하며, 각 파일에 대한 상세한 정보를 담고 있는 또 다른 배열을 값으로 가집니다.
$_FILES 배열의 주요 요소
$_FILES['input_name'] (여기서 input_name은 HTML <input type="file"> 태그의 name 속성 값)은 다음과 같은 5가지 주요 정보를 포함합니다.
- name: 클라이언트 #컴퓨터에서 #업로드된_파일의 #원본_이름(Original Name)입니다. 사용자가 선택한 파일의 실제 이름을 나타냅니다.
- 예시: my_document.pdf
- type: 업로드된 파일의 #MIME_타입(MIME Type)입니다. 브라우저가 제공하는 정보이므로, #보안_검사_시_이_값에만_의존해서는_안_됩니다. 이 값은 클라이언트 측에서 쉽게 위변조될 수 있습니다.
- 예시: image/jpeg, application/pdf, text/plain
- tmp_name: 서버에 #임시로_저장된_파일의 #전체_경로와_이름입니다. 업로드된 파일은 서버의 특정 임시 디렉터리(php.ini의 upload_tmp_dir 설정 또는 시스템 기본 임시 디렉터리)에 저장됩니다. #PHP_스크립트에서 이 임시 파일을 읽거나 영구적인 위치로 이동시켜야 합니다.
- 예시: /tmp/phpA2F3g5 (리눅스), C:\Windows\Temp\php1A2B.tmp (윈도우)
- error: #파일_업로드_시_발생한_오류를_나타내는_오류_코드(Error Code)입니다. #UPLOAD_ERR_OK (값: 0)는 파일이 성공적으로 업로드되었음을 의미하며, 다른 값들은 오류를 나타냅니다.
- UPLOAD_ERR_OK (0): 오류 없이 파일 업로드 성공.
- UPLOAD_ERR_INI_SIZE (1): php.ini의 upload_max_filesize를 초과.
- UPLOAD_ERR_FORM_SIZE (2): HTML 폼의 MAX_FILE_SIZE 값을 초과.
- UPLOAD_ERR_PARTIAL (3): 파일이 부분적으로만 업로드됨.
- UPLOAD_ERR_NO_FILE (4): 파일이 업로드되지 않음.
- UPLOAD_ERR_NO_TMP_DIR (6): 임시 디렉터리가 없음.
- UPLOAD_ERR_CANT_WRITE (7): 파일 쓰기 실패.
- UPLOAD_ERR_EXTENSION (8): PHP 확장 기능에 의해 업로드 중지됨.
- size: 업로드된 #파일의_크기를 #바이트(Byte) 단위로 나타냅니다.
- 예시: 102400 (100KB)
2. $_FILES 변수 활용 예시

지난 시간에 작성했던 #HTML #폼 (upload_form.html)에서 name="my_file"로 파일을 업로드했을 때, $_FILES 변수를 출력해보면 다음과 같은 구조를 가집니다.
<?php
// upload_process.php
if (isset($_FILES['my_file'])) {
echo "<pre>";
print_r($_FILES['my_file']);
echo "</pre>";
} else {
echo "파일이 업로드되지 않았습니다.";
}
/*
위 print_r($_FILES['my_file'])의 출력 예시:
Array
(
[name] => example.jpg
[type] => image/jpeg
[tmp_name] => /tmp/phpABCD12
[error] => 0
[size] => 123456
)
*/
?>
3. $_FILES를 이용한 파일 업로드 처리 로직 (심화)

이제 $_FILES 변수의 각 요소를 활용하여 실제 #파일_업로드_처리_스크립트를 작성해 보겠습니다. 이 과정에서 #보안_검사가_매우_중요합니다.
<?php
// upload_process.php
// 1. 업로드 디렉토리 설정 (보안상 웹 접근 불가한 상위 경로 권장)
$upload_dir = './uploads/'; // 현재 스크립트 기준 'uploads' 폴더
// 폴더가 없으면 생성 (권한 0755)
if (!is_dir($upload_dir)) {
mkdir($upload_dir, 0755, true);
}
// 2. 파일 업로드 오류 확인 (필수)
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 "오류: 업로드 파일 크기가 허용된 최대 크기를 초과했습니다.";
break;
case UPLOAD_ERR_NO_FILE:
echo "오류: 파일이 선택되지 않았습니다.";
break;
default:
echo "오류: 파일 업로드 중 알 수 없는 오류가 발생했습니다. 코드: " . $_FILES['my_file']['error'];
break;
}
exit;
}
// 3. 업로드된 파일 정보 변수에 저장
$file_name_original = $_FILES['my_file']['name'];
$file_tmp_name = $_FILES['my_file']['tmp_name'];
$file_type = $_FILES['my_file']['type'];
$file_size = $_FILES['my_file']['size'];
// 4. 엄격한 보안 검사 (매우 중요!)
// 4-1. 파일 크기 제한 (예: 2MB)
$max_file_size = 2 * 1024 * 1024; // 2MB
if ($file_size > $max_file_size) {
echo "오류: 파일 크기가 너무 큽니다. (최대 2MB)";
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_original, PATHINFO_EXTENSION));
// MIME 타입 확인 ($_FILES['type']은 클라이언트에서 전송하므로 참고용)
// 더 안전한 방법은 실제 파일의 MIME 타입을 서버에서 재확인하는 것 (예: finfo_open())
if (!in_array($file_ext, $allowed_extensions)) {
echo "오류: 허용되지 않는 파일 확장자입니다. (허용: " . implode(', ', $allowed_extensions) . ")";
exit;
}
if (!in_array($file_type, $allowed_mime_types)) { // 1차적인 MIME 타입 검사
echo "오류: 허용되지 않는 파일 MIME 타입입니다. (허용: " . implode(', ', $allowed_mime_types) . ")";
exit;
}
// 5. 파일 이름 변경 (보안상 필수: 원본 이름을 그대로 사용하지 마세요!)
// 유니크한 파일 이름 생성 (겹치지 않게, 추측 불가능하게)
$new_file_name = uniqid('upload_') . '.' . $file_ext;
$destination = $upload_dir . $new_file_name; // 최종 저장 경로
// 6. 임시 파일을 영구 저장소로 이동
// move_uploaded_file() 함수는 임시 디렉토리에 있는 업로드된 파일을 안전하게 지정된 목적지로 이동시킵니다.
// 이 함수는 임시 파일 여부와 권한 등을 내부적으로 확인하여 보안상 안전합니다.
if (move_uploaded_file($file_tmp_name, $destination)) {
echo "파일이 성공적으로 업로드되었습니다.\n";
echo "저장된 파일명: " . htmlspecialchars($new_file_name) . "\n";
echo "파일 경로: " . htmlspecialchars($destination) . "\n";
// 이미지가 웹에서 접근 가능하고 이미지인 경우에만 표시
if (strpos($file_type, 'image/') === 0) {
echo "<img src='" . htmlspecialchars($destination) . "' alt='업로드된 이미지' style='max-width:400px; height:auto; display:block; margin-top:20px;'>\n";
}
} else {
echo "오류: 파일 업로드에 실패했습니다. (이동 실패)";
}
?>
4. 다중 파일 업로드 처리

HTML 폼에서 <input type="file" name="my_files[]" multiple>과 같이 #name 속성에 #배열_형식([])을 추가하면 여러 파일을 동시에 업로드할 수 있습니다. 이때 $_FILES 배열의 구조는 약간 달라집니다.
HTML (upload_form_multiple.html)
<form action="upload_process_multiple.php" method="POST" enctype="multipart/form-data">
<label for="my_files">여러 파일 선택:</label>
<input type="file" name="my_files[]" id="my_files" multiple required>
<input type="submit" value="파일 업로드">
</form>
PHP (예시: upload_process_multiple.php)
<?php
// upload_process_multiple.php
// $_FILES['my_files'] 배열 구조:
/*
Array
(
[name] => Array
(
[0] => file1.jpg
[1] => file2.png
)
[type] => Array
(
[0] => image/jpeg
[1] => image/png
)
...
)
*/
if (isset($_FILES['my_files'])) {
$total_files = count($_FILES['my_files']['name']);
echo "총 " . $total_files . "개의 파일이 업로드 시도되었습니다.\n\n";
for ($i = 0; $i < $total_files; $i++) {
// 각 파일의 정보 추출
$file_name_original = $_FILES['my_files']['name'][$i];
$file_tmp_name = $_FILES['my_files']['tmp_name'][$i];
$file_error = $_FILES['my_files']['error'][$i];
$file_size = $_FILES['my_files']['size'][$i];
$file_type = $_FILES['my_files']['type'][$i];
echo "--- 파일 " . ($i + 1) . ": " . htmlspecialchars($file_name_original) . " ---\n";
if ($file_error !== UPLOAD_ERR_OK) {
echo "오류 발생: " . $file_error . "\n";
continue; // 다음 파일로 넘어감
}
// 보안 검사 및 파일 이동 로직은 단일 파일과 동일하게 적용
// (위의 단일 파일 처리 로직을 이 반복문 안에 넣으면 됨)
// 여기서는 간단히 이동만 예시
$upload_dir = './uploads/';
if (!is_dir($upload_dir)) { mkdir($upload_dir, 0755, true); }
$file_ext = strtolower(pathinfo($file_name_original, PATHINFO_EXTENSION));
$new_file_name = uniqid('multi_') . '.' . $file_ext;
$destination = $upload_dir . $new_file_name;
if (move_uploaded_file($file_tmp_name, $destination)) {
echo "성공: " . htmlspecialchars($new_file_name) . " 로 저장되었습니다.\n";
} else {
echo "실패: 파일을 이동할 수 없습니다.\n";
}
echo "\n";
}
} else {
echo "업로드된 파일이 없습니다.";
}
?>
#$_FILES 슈퍼 글로벌 변수는 #PHP에서 #파일_업로드를 다루는 데 있어 핵심적인 역할을 합니다. name, type, tmp_name, error, size 등의 정보를 통해 업로드된 파일을 #안전하게_처리하고 #저장할_수_있습니다. 특히 #보안_취약점을_막기_위해 #파일_이름_변경, #확장자_및_MIME_타입_검사, #파일_크기_제한 등의 #보안_로직을_반드시_적용해야_한다는_점_잊지_마세요! 다음 시간에는 업로드된 #이미지를_다루는_방법에 대해 자세히 알아보겠습니다.
루젠VPN, #VPN추천 끝판왕! #멀티IP와 강력한 #API 지원으로 비즈니스 맞춤 최적화. 안정적이고 빠른 속도로 제한 없이 자유로운 #인터넷 경험을 선사합니다. 지금 바로 루젠VPN을 경험하세요!
VPN 5,500원 / IP교체 1,100원 / 유동프록시 22,000원 | LuzenVPN 루젠VPN
국내최저가 고정IP서비스,유동프록시(IP4000개이상제공),PPTP,L2TP,IPSec,OpenVPNVPN,통신사VPN,VPN프로그램,고정IP,고정아이피,PPTP,저렴한VPN,리니지MVPN,리니지VPN,아이온VPN,던파VPN,유동프록시,유동PROXY,바이
vpn.luzensoft.com
'프로그램 > PHP 중급' 카테고리의 다른 글
| 📚 PHP 중급 - 4주차: 파일 업로드 및 이미지 처리 - 04 이미지 리사이징 및 썸네일 생성 (GD 라이브러리) (0) | 2025.07.27 |
|---|---|
| 📚 PHP 중급 - 4주차: 파일 업로드 및 이미지 처리 - 03 업로드된 파일 유효성 검사 (확장자, 크기) (0) | 2025.07.26 |
| 📚 PHP 중급 - 4주차: 파일 업로드 및 이미지 처리 - 01 HTML 폼을 이용한 파일 업로드 (0) | 2025.07.24 |
| 📚 PHP 중급 - 3주차: 게시판 CRUD 구현 (기본) - 03 페이징 처리 (0) | 2025.07.23 |
| 📚 PHP 중급 - 3주차: 게시판 CRUD 구현 (기본) - 02 글 목록, 글 작성, 글 보기, 글 수정, 글 삭제 (0) | 2025.07.22 |