PHP 파일 업로드와 다운로드 만들기

PHP 에서 간단히 파일 업로드와 다운로드를 구현해 봅니다. 파일 업로드 할때는 파일명 중복 방지와 파일명을 추측해서 다운로드 하는 것을 방지하기 위해 랜덤하게 파일명을 만들어서 서버에 저장합니다. 보안을 위해서는 파일 업로드 위치를 웹루트 밖에 하는것이 좋습니다.

 

파일 정보를 데이터베이스에 저장할 때도 파일을 구분할 파일 아이디를 예측 가능하지 않게 만들어서 다운로드시 사용합니다. 보안을 위해서는 다운로드 프로그램에 권한이 적용되면 더 좋습니다.

 

전체 예제 파일은 글 하단에 첨부하여 두었습니다.

 

 

1. 파일정보를 저장할 테이블 구조

- 데이터베이스는 캐릭터셋 utf8collation은 utf8_general_ci 로 만들었습니다.

 

 

CREATE TABLE upload_file (

  file_id   VARCHAR(255) NOT NULL PRIMARY KEY,

  name_orig VARCHAR(255),

  name_save VARCHAR(255),

  reg_time  TIMESTAMP NOT NULL

);

 

file_id : 각각의 파일을 유일하게 구별하는 아이디 값입니다.

name_orig : 업로드 당시의 원래 파일 이름입니다. 다운로드시 이 이름으로 파일이 생성됩니다.

name_save : 예측하기 힘들게 변경된 파일 이름입니다. 이 이름으로 서버에 파일이 저장됩니다.

reg_time : 파일이 업로드된 시간 입니다.

 

 

2. 파일 업로드 폼(up/upload.php)

 

 

<script type="text/javascript">

function formSubmit(f) {

    // 업로드 할 수 있는 파일 확장자를 제한합니다.

var extArray = new Array('hwp','xls','doc','xlsx','docx','pdf','jpg','gif','png','txt','ppt','pptx');

var path = document.getElementById("upfile").value;

if(path == "") {

alert("파일을 선택해 주세요.");

return false;

}

 

var pos = path.indexOf(".");

if(pos < 0) {

alert("확장자가 없는파일 입니다.");

return false;

}

 

var ext = path.slice(path.indexOf(".") + 1).toLowerCase();

var checkExt = false;

for(var i = 0; i < extArray.length; i++) {

if(ext == extArray[i]) {

checkExt = true;

break;

}

}

 

if(checkExt == false) {

alert("업로드 할 수 없는 파일 확장자 입니다.");

    return false;

}

 

return true;

}

</script>

 

<form name="uploadForm" id="uploadForm" method="post" action="upload_process.php" 

      enctype="multipart/form-data" onsubmit="return formSubmit(this);">

    <div>

        <label for="upfile">첨부파일</label>

        <input type="file" name="upfile" id="upfile" />

    </div>

    <input type="submit" value="업로드" />

</form>

 

- 업로드 폼을 체크하는 formSubmit(); 자바스크립트에서 업로드 할 수 있는 파일의 확장자를 제한하고 있습니다.

- 파일 업로드를 위해서 method="post" 이고, enctype="multipart/form-data" 로 지정해야 합니다.

- 파일 선택 엘리먼트의 이름은 "upfile" 입니다.

 

 


 

3. 서버측 파일 업로드 처리(upload_process.php)

 

 

<?php

$db_conn = mysqli_connect("localhost", "testdbadm", "testdbadm", "testdb");

 

if(isset($_FILES['upfile']) && $_FILES['upfile']['name'] != "") {

    $file = $_FILES['upfile'];

    $upload_directory = 'data/';

    $ext_str = "hwp,xls,doc,xlsx,docx,pdf,jpg,gif,png,txt,ppt,pptx";

    $allowed_extensions = explode(',', $ext_str);

    

    $max_file_size = 5242880;

    $ext = substr($file['name'], strrpos($file['name'], '.') + 1);

    

    // 확장자 체크

    if(!in_array($ext, $allowed_extensions)) {

        echo "업로드할 수 없는 확장자 입니다.";

    }

    

    // 파일 크기 체크

    if($file['size'] >= $max_file_size) {

        echo "5MB 까지만 업로드 가능합니다.";

    }

    

    $path = md5(microtime()) . '.' . $ext;

    if(move_uploaded_file($file['tmp_name'], $upload_directory.$path)) {

        $query = "INSERT INTO upload_file (file_id, name_orig, name_save, reg_time) VALUES(?,?,?,now())";

        $file_id = md5(uniqid(rand(), true));

        $name_orig = $file['name'];

        $name_save = $path;

        

        $stmt = mysqli_prepare($db_conn, $query);

        $bind = mysqli_stmt_bind_param($stmt, "sss", $file_id, $name_orig, $name_save);

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

        $exec = mysqli_stmt_execute($stmt);

      

        mysqli_stmt_close($stmt);

        

        echo"<h3>파일 업로드 성공</h3>";

        echo '<a href="file_list.php">업로드 파일 목록</a>';

        

    }

} else {

    echo "<h3>파일이 업로드 되지 않았습니다.</h3>";

    echo '<a href="javascript:history.go(-1);">이전 페이지</a>';

}

 

mysqli_close($db_conn);

?>

 

- 데이터베이스는 mysqli 를 사용해서 prepared statement로 작업을 했습니다.SQL Injection을 대비하는 가장 좋은 방법 입니다.

- 서버측에서도 업로드된 파일의 확장자를 체크해야 합니다.

- 업로드 가능한 파일 용량도 체크합니다. 제한을 하지 않을 경우 대용량 파일을 업로드 하여 서버를 다운시키는 공격을 받을 수 있습니다.

$file_id는 uniqid(rand(), true) 함수로 생성한 유일한 값을 md5() 로 해시해서 추측하기 힘들 값을 만들어 사용합니다.

 

 

4. 파일 목록 조회(file_list.php)

 

 

<table border="1">

<tr>

<th>파일 아이디</th>

<th>원래 파일명</th>

<th>저장된 파일명</th>

</tr>

<?php

$db_conn = mysqli_connect("localhost", "testdbadm", "testdbadm", "testdb");

$query = "SELECT file_id, name_orig, name_save FROM upload_file ORDER BY reg_time DESC";

$stmt = mysqli_prepare($db_conn, $query);

$exec = mysqli_stmt_execute($stmt);

$result = mysqli_stmt_get_result($stmt);

while($row = mysqli_fetch_assoc($result)) {

?>

<tr>

  <td><?= $row['file_id'] ?></td>

  <td><a href="download.php?file_id=<?= $row['file_id'] ?>" target="_blank"><?= $row['name_orig'] ?></a></td>

  <td><?= $row['name_save'] ?></td>

</tr>

<?php

 

mysqli_free_result($result); 

mysqli_stmt_close($stmt);

mysqli_close($db_conn);

?>

</table>

 

- 파일 다운로드를 위해 파일 목록을 조회합니다.

- download.php?file_id=<?= $row['file_id'] ?> 로 파일 다운로드 링크를 만듭니다. 파일 아이디 단순한 번호로 만들면 번호만 바꿔서 호출하여 다른 파일을 다운로드 받을 수 있게 됩니다. 필요하다면 실제 구현에서는 권한을 적용하여 자신에게 다운로드 권한이 없는 파일을 다운 받을 수 없도록 하여야 겠습니다.

 

 

 

5. 파일 다운로드(download.php)

 

 

<?php

$file_id = $_REQUEST['file_id'];

 

$db_conn = mysqli_connect("localhost", "testdbadm", "testdbadm", "testdb");

$query = "SELECT file_id, name_orig, name_save FROM upload_file WHERE file_id = ?";

$stmt = mysqli_prepare($db_conn, $query);

 

$bind = mysqli_stmt_bind_param($stmt, "s", $file_id);

$exec = mysqli_stmt_execute($stmt);

 

$result = mysqli_stmt_get_result($stmt);

$row = mysqli_fetch_assoc($result);

 

$name_orig = $row['name_orig'];

$name_save = $row['name_save'];

 

$fileDir = "data/";

$fullPath = $fileDir."/".$name_save;

$length = filesize($fullPath);

 

header("Content-Type: application/octet-stream");

header("Content-Length: $length");

header("Content-Disposition: attachment; filename=".iconv('utf-8','euc-kr',$name_orig));

header("Content-Transfer-Encoding: binary");

 

$fh = fopen($fullPath, "r");

fpassthru($fh);

 

mysqli_free_result($result);

mysqli_stmt_close($stmt);

mysqli_close($db_conn);

 

exit;

?>

 

- GET 방식으로 받은 file_id를 이용하여 파일정보를 조회합니다.

Content-Disposition 헤더를 사용하여 다운로드될 파일 이름을 원래 파일명으로 지정합니다. 데이터베이스에 UTF-8로 데이터가 저장되어 있으므로 euc-kr로 변환해야 한글 파일명이 깨지지 않습니다.

 

 

이것으로 간단히 PHP 에서 파일을 업로드하고 다운로드 하는 방법을 알아보았습니다. 실제 구현에서는 데이터베이스 연결정보를 추출해서 include 파일로 만들고, 업로드 위치를 웹루트 밖으로 바꾸고, 업로드/다운로드에 권한을 적용하고, 데이터베이스 에러처리, 파일 관련 에러처리 등이 추가되어야 겠습니다.

 

※ 전체소스

 php 사진 업다운로드 upload.zip

 



출처: https://offbyone.tistory.com/279 [쉬고 싶은 개발자]

 

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
129 [Redis] php 세션 저장소를 redis 로 바꾸어 본 후기. file 졸리운_곰 2021.04.11 47
128 Creating a Website Design Templating System Using PHP 졸리운_곰 2021.02.13 22
127 Build a CRUD Operation using PHP & MongoBD 졸리운_곰 2021.01.04 23
126 CRUD Operation using PHP & Mongodb file 졸리운_곰 2021.01.04 26
125 PHP and MongoDB Connection file 졸리운_곰 2021.01.04 63
124 PHP 기반의 Micro Frameworks 정리 졸리운_곰 2020.12.02 51
123 CKEditor 4 설치와 PHP 연동 하기 file 졸리운_곰 2020.11.22 47
122 [php] CKeditor 설정 및 적용 졸리운_곰 2020.11.22 38
121 [PHP]Fuelframework 설치 및 시작 방법(window10,xampp) file 졸리운_곰 2020.10.01 34
120 Building a Simple Blog App with MongoDB and PHP file 졸리운_곰 2020.09.13 50
119 웹 설문조사 시스템 & 설문조사를 잘 하는 방법 file 졸리운_곰 2020.09.10 190
118 ReactPHP Series 졸리운_곰 2020.07.01 50
117 Building a RESTful API Using ReactPHP and MySQL file 졸리운_곰 2020.07.01 44
116 [PHP 웹개발] MySQL 데이터베이스에서 mysqli(MySQL Improved) 사용법 졸리운_곰 2020.05.07 39
» PHP 파일 업로드와 다운로드 만들기 file 졸리운_곰 2020.05.07 374
114 HOW TO INTEGRATE R WITH PHP : php와 R 언어의 연동 file 졸리운_곰 2020.05.05 255
113 XAMPP, PhpStorm, Hello World 출력하기 졸리운_곰 2020.03.27 40
112 Pico is a stupidly simple, blazing fast, flat file CMS. file 졸리운_곰 2020.03.19 34
111 directorylister php 사용법 file 졸리운_곰 2020.03.18 129
110 flat file 플랫파일시스템 : GRAV CMS file 졸리운_곰 2020.03.18 60
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED