파일 업로드
파일을 업로드하는 방법은 아주 간단하다. 따로 모듈을 사용할 필요 없이 자체 내장 함수만으로도 업로드를 처리할 수 있다. 물론, 이부분도 보안을 처리해주어야 할 것들이 있다. 할 일이 그렇게 많지는 않으므로 같이 언급하고자 한다.
폼
아래의 폼은 파일을 업로드 위해 작성한 폼이다 속성 부분에 있는 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
더 읽을거리
https://www.inflearn.com/course/php7-reboot