20. 장. Handling file uploads

차례
POST method uploads
일반적인 주의사항 (Common Pitfalls)
여러 파일을 Upload하기 (Uploading multiple files)
PUT method support

POST method uploads

PHP는 RFC-1867을 지원하는 브라우저로부터 파일을 업로드 받을 수 있는 기능이 있다. 이 기능을 사용하면 Text뿐 아니라 Binary파일도 업로드가 가능하다. 여러분은 PHP의 authetication과 파일을 다루는 함수를 사용하여, 파일이 Upload된 후에 해야 할 일을 스크립트에 반드시 정해 두어야 한다.

PHP는 또한 Netscape Composer 와 W3C's Amaya clients를 사용할 경우 PUT-method 의 파일 업로드도 지원한다. 자세한 내용은 PUT Method Support를 읽어보기바란다.

파일 업로드 화면은 다음과 같은 좀 특별한 폼을 만들어 띄울 수 있다. :

예 20-1. File Upload Form

<FORM ENCTYPE="multipart/form-data" ACTION="_URL_" METHOD=POST>
<INPUT TYPE="hidden" name="MAX_FILE_SIZE" value="1000">
Send this file: <INPUT NAME="userfile" TYPE="file">
<INPUT TYPE="submit" VALUE="Send File">
</FORM>
여기서 _URL_은 PHP html파일이어야 합니다. hidden 필드인 MAX_FILE_SIZE는 File input 필드들보다 선행되어야 합니다. 이 값은 PHP html이 받아들이는 최대 파일 크기를 Byte단위로 나타냅니다.

PHP3에서는 업로드가 완료되면 실행될 스크립트에는 다음 변수들이 설정된다. (물론 php3.ini 파일에 register_globals가 켜져있어야 한다.) 또한 만약 track_vars가 켜져있으면, 전역변수 $HTTP_POST_VARS 내에도 이 변수들이 설정된다. 다음 예제에 있는 변수명들은 업로드시 'userfile'이라는 필드명을 사용한 것으로 가정한다.:

위 변수의 "$userfile"부분은 upload form에서 TYPE=filed을 가진 INPUT 필드의 이름이 된다. 위의 예제에서 우리는 그 이름은 "userfile"이라고 정했다.

PHP4에서는 동작이 약간 다르다. PHP4에서는 엄로드된 파일에 대한 정보를 가지고 있는 $HTTP_POST_FILES 전역 배열을 지원한다. 이 변수는 track_vars가 켜져 있어야만 사용가능하지만, PHP 4.0.2 이후에서는 항상 켜져 있으므로 걱정할 필요는 없다.

$HTTP_POST_FILES의 내용은 다음과 같다. 위에 있는 예와 같이 업로드시 'userfile'이라는 필드명을 사용한 것으로 가정한다.:

$HTTP_POST_FILES['userfile']['name']

클라이언트에서의 원래 파일명

$HTTP_POST_FILES['userfile']['type']

해당 파일의 mime 타입. 브라우저가 이 타입 대한 정보를 가지고 있는 경우에만 설정된다. (예 : "image/gif")

$HTTP_POST_FILES['userfile']['size']

업로드된 파일의 크기. byte 단위이다.

$HTTP_POST_FILES['userfile']['tmp_name']

업로드가 완료된후 서버에 저장된 파일의 파일명. (임시파일이다.)

업로드된 파일은 php.iniupload_tmp_dir지시자가 특정 디렉토리를 지정하지 않으면, 기본적으로 우선 서버의 default temporary directory에 저장된다. 이 디폴트 디렉토리는 PHP가 돌아가는 컴퓨터의 환경변수 TMPDIR을 설정하여 변경할 수 있다. 이를 PHP 스크립트 안에서 putenv() 함수를 사용하여 변경하는 것은 동작하지 않는다.

예 20-2. Validating file uploads

다음 예제는 PHP3 3.0.16 이상이나 PHP4 4.0.2 이상에서만 실행이 가능하다. 그리고 is_uploaded_file()move_uploaded_file()함수를 살펴보자.

<?php 
if (is_uploaded_file($userfile)) {
    copy($userfile, "/place/to/put/uploaded/file");
} else {
    echo "Possible file upload attack: filename '$userfile'.";
}
/* ...or... */
move_uploaded_file($userfile, "/place/to/put/uploaded/file");
?>

이전 버전의 PHP에서는 다음과 같은 처리하여야 한다. 가 필요하다. For earlier versions of PHP, you'll need to do something like the following.

참고: 이 예제는 PHP4 4.0.2이후 버전에서는 동작하지 않는다. 4.0.2이후 부터는 내부적으로 처리하는 방법이 달라졌기 때문이다.

<?php 
/* Userland test for uploaded file. */ 
function is_uploaded_file($filename) {
    if (!$tmp_file = get_cfg_var('upload_tmp_dir')) {
        $tmp_file = dirname(tempnam('', ''));
    }
    $tmp_file .= '/' . basename($filename);
    /* User might have trailing slash in php.ini... */
    return (ereg_replace('/+', '/', $tmp_file) == $filename);
}

if (is_uploaded_file($userfile)) {
    copy($userfile, "/place/to/put/uploaded/file");
} else {
    echo "Possible file upload attack: filename '$userfile'.";
}
?>

업로드된 파일을 다루는 PHP 스크립트는 그 파일을 다루는 작업을 설정해 줄 필요가 있다. 예를들어, $file_size 변수를 사용하여 너무 작거나 큰 파일을 버릴 수도 있다. 또한 $file_type 변수를 가지고 특정한 타입에 맞지 않는 파일을 버릴 수 있다. 어떤 로직이던, 임시 디렉토리에 있는 파일을 지우거나 나중에 필요할 경우에는 다른 곳에 이동시켜야 한다.

만약 임시 디렉토리에 있는 파일을 해당 request가 끝날 때 까지도 지우거나 이동시키지 않았다면, 이 파일은 해당 request가 종료되는 시점에서 자동으로 지워진다.