1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
|
<?xml version="1.0" encoding="utf-8"?>
<chapter id="features.file-upload">
<title>Handling file uploads</title>
<sect1 id="features.file-upload.post-method">
<title>POST method uploads</title>
<simpara>
PHP는 RFC-1867을 지원하는 브라우저로부터 파일을 업로드 받을 수 있는 기능이 있다.
이 기능을 사용하면 Text뿐 아니라 Binary파일도 업로드가 가능하다.
여러분은 PHP의 authetication과 파일을 다루는 함수를 사용하여,
파일이 Upload된 후에 해야 할 일을 스크립트에 반드시 정해 두어야 한다.
</simpara>
<para>
PHP는 또한 Netscape Composer 와 W3C's Amaya clients를 사용할 경우
PUT-method 의 파일 업로드도 지원한다. 자세한 내용은
<link linkend="features.file-upload.put-method">PUT Method Support</link>를 읽어보기바란다.
</para>
<para>
파일 업로드 화면은 다음과 같은 좀 특별한 폼을 만들어 띄울 수 있다. :
<example>
<title>File Upload Form</title>
<programlisting>
<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>
</programlisting>
</example>
여기서 _URL_은 PHP html파일이어야 합니다.
hidden 필드인 MAX_FILE_SIZE는 File input 필드들보다 선행되어야 합니다.
이 값은 PHP html이 받아들이는 최대 파일 크기를 Byte단위로 나타냅니다.
</para>
<para>
PHP3에서는 업로드가 완료되면 실행될 스크립트에는 다음 변수들이 설정된다.
(물론 <filename>php3.ini</filename> 파일에 <link linkend="ini.register-globals">register_globals</link>가
켜져있어야 한다.)
또한 만약 <link linkend="ini.track-vars">track_vars</link>가 켜져있으면,
전역변수 <varname>$HTTP_POST_VARS</varname> 내에도 이 변수들이 설정된다.
다음 예제에 있는 변수명들은 업로드시 'userfile'이라는 필드명을 사용한 것으로 가정한다.:
<itemizedlist>
<listitem>
<simpara>
<varname>$userfile</varname> - 업로드된 파일 내용이 저장되어 있는 서버의 임시 파일명.
</simpara>
</listitem>
<listitem>
<simpara>
<varname>$userfile_name</varname> - 업로드한 시스템에서 사용하는 파일의 원래 이름.
</simpara>
</listitem>
<listitem>
<simpara>
<varname>$userfile_size</varname> - byte단위의 Upload된 파일의 크기.
</simpara>
</listitem>
<listitem>
<simpara>
<varname>$userfile_type</varname> - 만약 browser가 업로드된 파일의 mime 형식을 안다면, 그 mime 형식.
(예: "image/gif").
</simpara>
</listitem>
</itemizedlist>
위 변수의 "$userfile"부분은 upload form에서 TYPE=filed을 가진 INPUT 필드의 이름이 된다.
위의 예제에서 우리는 그 이름은 "userfile"이라고 정했다.
</para>
<para>
PHP4에서는 동작이 약간 다르다. PHP4에서는 엄로드된 파일에 대한 정보를 가지고 있는
<varname>$HTTP_POST_FILES</varname> 전역 배열을 지원한다.
이 변수는 <link linkend="ini.track-vars">track_vars</link>가 켜져 있어야만 사용가능하지만,
PHP 4.0.2 이후에서는 항상 켜져 있으므로 걱정할 필요는 없다.
</para>
<para>
<varname>$HTTP_POST_FILES</varname>의 내용은 다음과 같다.
위에 있는 예와 같이 업로드시 'userfile'이라는 필드명을 사용한 것으로 가정한다.:
<variablelist>
<varlistentry>
<term>
<varname>$HTTP_POST_FILES['userfile']['name']</varname>
</term>
<listitem>
<para>
클라이언트에서의 원래 파일명
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>$HTTP_POST_FILES['userfile']['type']</varname>
</term>
<listitem>
<para>
해당 파일의 mime 타입. 브라우저가 이 타입 대한 정보를 가지고 있는 경우에만 설정된다.
(예 : <literal>"image/gif"</literal>)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>$HTTP_POST_FILES['userfile']['size']</varname>
</term>
<listitem>
<para>
업로드된 파일의 크기. byte 단위이다.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>$HTTP_POST_FILES['userfile']['tmp_name']</varname>
</term>
<listitem>
<para>
업로드가 완료된후 서버에 저장된 파일의 파일명. (임시파일이다.)
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<para>
업로드된 파일은 <filename>php.ini</filename>의
<link linkend="ini.upload-tmp-dir">upload_tmp_dir</link>지시자가 특정 디렉토리를 지정하지 않으면,
기본적으로 우선 서버의 default temporary directory에 저장된다.
이 디폴트 디렉토리는 PHP가 돌아가는 컴퓨터의 환경변수 <envar>TMPDIR</envar>을 설정하여 변경할 수 있다.
이를 PHP 스크립트 안에서 <function>putenv</function> 함수를 사용하여 변경하는 것은 동작하지 않는다.
<example>
<title>Validating file uploads</title>
<para>
다음 예제는 PHP3 3.0.16 이상이나 PHP4 4.0.2 이상에서만 실행이 가능하다.
그리고 <function>is_uploaded_file</function>과 <function>move_uploaded_file</function>함수를 살펴보자.
</para>
<programlisting role="php">
<?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");
?>
</programlisting>
<para>
이전 버전의 PHP에서는 다음과 같은 처리하여야 한다. 가 필요하다.
For earlier versions of PHP, you'll need to do something like
the following.
<note>
<para>
이 예제는 PHP4 4.0.2이후 버전에서는 동작하지 <emphasis>않는다.</emphasis>
4.0.2이후 부터는 내부적으로 처리하는 방법이 달라졌기 때문이다.
</para>
</note>
</para>
<programlisting role="php">
<?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'.";
}
?>
</programlisting>
</example>
</para>
<simpara>
업로드된 파일을 다루는 PHP 스크립트는 그 파일을 다루는 작업을 설정해 줄 필요가 있다.
예를들어, <varname>$file_size</varname> 변수를 사용하여 너무 작거나 큰 파일을 버릴 수도 있다.
또한 <varname>$file_type</varname> 변수를 가지고 특정한 타입에 맞지 않는 파일을 버릴 수 있다.
어떤 로직이던, 임시 디렉토리에 있는 파일을 지우거나 나중에 필요할 경우에는 다른 곳에 이동시켜야 한다.
</simpara>
<simpara>
만약 임시 디렉토리에 있는 파일을 해당 request가 끝날 때 까지도 지우거나 이동시키지 않았다면,
이 파일은 해당 request가 종료되는 시점에서 자동으로 지워진다.
</simpara>
</sect1>
<sect1 id="features.file-upload.common-pitfalls">
<title>일반적인 주의사항 (Common Pitfalls)</title>
<simpara>
MAX_FILE_SIZE 아이템의 값은 php3.ini에 설정된 upload_max_filesize의 값이나
Apache의 .conf에 설정한 php3_upload_max_filesize의 값보다 크게 설정할 수 없다.
기본값은 2메가 바이트이다.
</simpara>
<simpara>
업로드된 파일에 대한 검사를 게을리하면 일반 사용자들이 시스템이나
다른 디렉토리내의 보안에 관한 정보에 접근할 수도 있으니 주의하기 바란다.
</simpara>
<simpara>
CERN httpd 서버는 client로부터 입력받은 mime header의 앞쪽 여백을 모두 strip off 시켜버리므로,
CERN httpd 서버에서는 File Upload 기능이 동작하지 않는다.
</simpara>
</sect1>
<sect1 id="feature-fileupload.multiple">
<title>여러 파일을 Upload하기 (Uploading multiple files)</title>
<simpara>
한번에 여러개의 파일을 동시에 전송하는 것도 가능하다.
이때 PHP는 이 파일들에 대한 정보를 배열로 전달한다.
따라서 이런 경우에는 여러개를 선택하는 select나 checkbox 때처럼 HTML의 form의 아이템에
동일한 array명을 적어주어야 한다.:
</simpara>
<note>
<para>
여러 파일 전송 기능은 3.0.10부터 추가된 기능이다.
</para>
</note>
<para>
<example>
<title>Uploading multiple files</title>
<programlisting>
<form action="file-upload.php" method="post" enctype="multipart/form-data">
Send these files:<br>
<input name="userfile[]" type="file"><br>
<input name="userfile[]" type="file"><br>
<input type="submit" value="Send files">
</form>
</programlisting>
</example>
</para>
<simpara>
위의 폼이 전송될 때 <computeroutput>$userfile</computeroutput>,
<computeroutput>$userfile_name</computeroutput>,
<computeroutput>$userfile_size</computeroutput>의 배열이 전역 변수로 만들어진다.
($HTTP_POST_FILES(PHP3 에서는 $HTTP_POST_VARS)에도 만들어진다.)
이 배열들은 전송된 파일의 정보를 가지고 있고, 각 배열은 번호로 인덱스되어 있다.
</simpara>
<simpara>
예를 들어, 위의 예에서 <filename>/home/test/review.html</filename>와
<filename>/home/test/xwp.out</filename> 의 두 개의 파일을 전송했다면
<computeroutput>$userfile_name[0]</computeroutput> 에는
<computeroutput>review.html</computeroutput>이라는 값이,
<computeroutput>$userfile_name[1]</computeroutput>에는
<computeroutput>xwp.out</computeroutput>이라는 값이 저장되게 된다.
동시에, <computeroutput>$userfile_size[0]</computeroutput> 에는
<filename>review.html</filename>의 파일 크기가 저장되는 식이 된다
</simpara>
<simpara>
<computeroutput>$userfile['name'][0]</computeroutput>,
<computeroutput>$userfile['tmp_name'][0]</computeroutput>,
<computeroutput>$userfile['size'][0]</computeroutput>, and
<computeroutput>$userfile['type'][0]</computeroutput> are also set.
</simpara>
</sect1>
<sect1 id="features.file-upload.put-method">
<title>PUT method support</title>
<para>
PHP는 Netscape Composer나 W3C Amaya같은 클라이언트에 대해 HTTP PUT 방식(method)을 지원한다.
PUT 요구(request)는 file upload보다 훨씬 쉽다. 단지 다음과 같이 하면 된다. :
<informalexample>
<programlisting>
PUT /path/filename.html HTTP/1.1
</programlisting>
</informalexample>
</para>
<para>
이것은 보통 원격 클라이언트가 보낸 내용을 웹 트리 밑의 /path/filename.html로 저장하라는 의미이다.
그런데 여러분의 웹 트리밑에 있는 파일들을 아무나 덮어 쓸 수 있다는 것은
Apache나 PHP에 있어서 좋지 않은 생각이다.
따라서 이와 같은 요구를 다루기 전에, 우선 웹 서버에게 이런 요구를 다루는
PHP 스크립트를 미리 지정해 주어야 한다.
아파치에서는 <emphasis>Script</emphasis> 지시자로 그 내용을 지정한다.
이 지시자는 Apache 설정 파일중의 어느 위치에 있어도 괜찮으나,
보통 <Directory> 블록 안이나 <Virtualhost> 블록 안에 위치하는 것이 일반적이다.
보통 다음과 같이 설정한다. :
<informalexample>
<programlisting>
Script PUT /put.php3
</programlisting>
</informalexample>
</para>
<simpara>
이것은 이 라인이 속하는 블록의 URI에 해당되는 모든 PUT 요구를
put.php3 스크립트에게 전달하라고 Apache에게 알려 준다.
물론 이 경우 .php3 확장자에 대하여 PHP설정이 완료되어 있고, PHP가 작동중이어야 한다.
</simpara>
<simpara>
put.php3 파일은 보통 다음과 같이 구성될 수 있다. :
</simpara>
<para>
<informalexample>
<programlisting>
<?php copy($PHP_UPLOADED_FILE_NAME,$DOCUMENT_ROOT.$REQUEST_URI); ?>
</programlisting>
</informalexample>
</para>
<simpara>
위의 명령은 해당 파일을 원격 클라이언트가 요청한 위치에 복사하는 것이다.
아마 여러분은 복사하기 전에 사용자를 확인하거나 파일을 검사하는 등의 기능을 원할 것이다.
여기서 알 수 있는 것은 PHP가 <link linkend="features.file-upload.post-method">POST-method</link>의 요구를 받았을 때
POST-method기능과 마찬가지로 임시 파일에 해당 내용을 저장한다는 것이다.
즉, 요구가 끝나게 되면 임시파일은 지워진다.
따라서 PUT을 다루는 PHP 스크립트는 해당 파일을 어디 다른 곳에 복사해 두어야 한다.
임시파일의 이름은 $PHP_PUT_FILENAME 이라는 변수에 저장되고,
$REQUEST_URI 변수에 클라이언트에서 보내온 저장할 파일의 경로와 이름이 저장된다.
(Apache가 아닌 웹서버에서는 모양이 조금 달라진다.)
물론 여러분은 이 경로명과 파일명이 아닌 전혀 다른 위치에 다른 파일명을 사용할 수도 있다.
</simpara>
</sect1>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"../../manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
-->
|