너의 개발은/PHP

PHP: 파일 업로드와 다운로드

파일 업로드

파일을 업로드하는 방법은 아주 간단하다. 따로 모듈을 사용할 필요 없이 자체 내장 함수만으로도 업로드를 처리할 수 있다. 물론, 이부분도 보안을 처리해주어야 할 것들이 있다. 할 일이 그렇게 많지는 않으므로 같이 언급하고자 한다.

아래의 폼은 파일을 업로드 위해 작성한 폼이다 속성 부분에 있는 entype="multipart/form-data" 부분이 있어야 하므로 폼을 작성할 때는 이점을 꼭 확인해야한다. POST 요청을 하는 것도 잊지 말자.

<form action="/" method='POST' enctype="multipart/form-data">
    <input type="file" name="uploads">
    <input type="submit">
</form>

$_FILES

이 배열은 슈퍼 글로벌 변수로써 프론트에서 요청한 파일 정보가 담겨있으며, 키값은 폼에서 보이는 것처럼 uploads 이다.  이것은 2차원 배열이기 때문에 해당 값안에는 또 다시 배열이 담겨있으며 파일의 이름과 같은 정보가 담겨있다.

$file = $_FILES['uploads'];

파일 업로드

is_uploaded_file(), move_uploaded_file() 함수를 사용하면 파일 업로드를 진행할 수 있다. 이 함수가 무엇을 하는지는 이름만 봐도 알 수 있을 것이라 생각한다. 파라매터에 대한 설명은 간단하기에 생략하겠지만, is_uploaded_file() 로 파일이 업로드 되었는지를 체크하고, move_uploaded_file() 로 파일을 업로드한다.

if (is_uploaded_file($file['tmp_name'])) {
    move_uploaded_file($file['tmp_name'], '__FILE_FULL_PATH__');
}

PHP는 파일 업로드가 요청되면 서버 내부에 임시 파일을 만들게 되는데, 그 경로가 바로 tmp_name 키에 담겨있다. 따라서 해당 파일을 업로드해도 된다고 검증이 완료되면, move_uploaded_file() 을 통해서 실제로 업로드할 폴더로 이동시키는 것이다.

파일 다운로드

파일을 다운로드하는 코드는 그다지 설명할 내용이 많이 없는데, 아래의 코드를 보자. 헤더의 경우는 그냥 넘겨도 가능하지만, 사실 눈여겨 보아야 할 것은 따로 있다. 바로 basename() 함수다. 파일을 다운로드하는 것은 Document Root 의 바깥 폴더에 있는 것도 다운로드 가능하다는 것을 잊어서는 안 된다.

 

참고로 readfile() 함수는 별도의 출력없이도 Output Stream 으로 내용을 내보내준다.

if (file_exists($filepath)) {
    header('Content-type: application/octet-stream');
    header('Content-Disposition: attachment; filename=' . basename($filepath));
    header('Content-Transfer-Encoding: binary');
    header('Content-Length: ' . filesize($filepath));

    readfile($filepath);
}

보안

basename(string): string

이 함수는 파일의 이름을 포함한 경로를 받게 되면, 파일의 이름을 얻어오는 아주 단순한 함수다. 그런데, 보안의 측면에서 볼때 이것을 사용하게 되면 파일 다운로드 취약점을 어느 정도는 막을 수 있다.

 

파일 다운로드 취약점은 ../../passwd 와 같은 경로가 외부에서 다운로드 요청 파라매터로 들어온 경우, 앞에 ../../ 은 날려주기 때문에 상당히 안전하다. 따라서 해당 함수를 통해 막아줄 필요가 있다.

string $path 파일 경로

정규 표현식

다운로드의 경우 대부분은 사용자가 다운로드할 파일을 지정해줄 수 있다. 여기서 파일의 이름을 조작하거나, 보안상 위험한 파일의 다운로드를 요청할 수 있는데, 그럴 때 필요한 것이 다운로드 하려는 패치 파라매터의 정보에 대해 임의의 정규 표현식을 적용시켜 검증하는 것이다.

if (preg_match('/\d_\d{10}_[0-9a-z]{32}/', $path)) {
    // ...
}

확장자

확장자에 대한 검증은 파일 업로드와 다운로드에서 둘 다 처리해야 한다. 허용하려는 파일 확장자를 미리 정의한다음 단순히 검증을 해주면 된다. 보안을 처리하는 행위는 간단해보일지라도 모르면 당하기 쉽다.

$accepts = ['jpg'];

$fileinfo =  new \SplFileInfo($file['name']);
if (in_array(strtolower($fileinfo->getExtension()), $accepts)) {
    // ....
}

php.ini

php.ini 설정파일에 보면 File Uploads 와 관련된 보안 설정이 있어서 파일 업로드 자체를 끄거나 최대 요청 파일 갯수, 허용 파일크기 제한 등을 걸어줄 수 있다. 따라서 어플리케이션에서 파일과 관련된 기능을 제공한다면 이것들도 참고해서 설정할 수 있을 것이다. file_uploads, upload_max_filesize, max_file_uploads 설정이다.

;;;;;;;;;;;;;;;;
; File Uploads ;
;;;;;;;;;;;;;;;;

; Whether to allow HTTP file uploads.
; http://php.net/file-uploads
file_uploads = On

; Temporary directory for HTTP uploaded files (will use system default if not
; specified).
; http://php.net/upload-tmp-dir
;upload_tmp_dir =

; Maximum allowed size for uploaded files.
; http://php.net/upload-max-filesize
upload_max_filesize = 2M

; Maximum number of files that can be uploaded via a single request
max_file_uploads = 20

 

 

PHP 7+ 프로그래밍: 리부트 - 인프런

기초 문법부터 내장 함수, 웹 보안, 게시판 만들기까지 PHP 언어를 시작하는 분들을 위해 바이블이 될 수 있게 만들어보고자 하는 마음으로 이번 강좌를 만들어보았습니다. 입문 웹 개발 프로그��

www.inflearn.com

 

PHP 7+ 프로그래밍: 객체지향 - 인프런

PHP 객체지향, 내장 클래스, PSR, Composer, MVC(Model, View, Controller)까지 모던 PHP를 익히기 위한 근간을 이야기합니다. 초급 프로그래밍 언어 알고리즘 PHP 객체지향 알고리즘 온라인 강의 모던 PHP 프로��

www.inflearn.com

'너의 개발은 > PHP' 카테고리의 다른 글

PHP: 의존성 관리자 — Composer  (0) 2020.08.14
PHP: MVC(Model, View, Controller)  (0) 2020.06.29
PHP: 파일 업로드와 다운로드  (0) 2020.06.10
PHP: 데이터베이스 (MySQLi, PDO)  (0) 2020.06.10
PHP: 쿠키와 세션  (0) 2020.04.29
PHP: HTML 폼 (GET, POST)  (0) 2020.04.29