mirror of
https://github.com/sigmasternchen/php-doc-en
synced 2025-03-17 01:18:55 +00:00

git-svn-id: https://svn.php.net/repository/phpdoc/en/trunk@141299 c90b9560-bf6c-de11-be94-00142212c4b1
526 lines
19 KiB
XML
526 lines
19 KiB
XML
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
<!-- $Revision: 1.65 $ -->
|
|
<chapter id="features.file-upload">
|
|
<title>Handling file uploads</title>
|
|
|
|
<sect1 id="features.file-upload.post-method">
|
|
<title>POST method uploads</title>
|
|
|
|
<simpara>
|
|
PHP is capable of receiving file uploads from any RFC-1867
|
|
compliant browser (which includes Netscape Navigator 3 or later,
|
|
Microsoft Internet Explorer 3 with a patch from Microsoft, or
|
|
later without a patch). This feature lets people upload both text
|
|
and binary files. With PHP's authentication and file manipulation
|
|
functions, you have full control over who is allowed to upload and
|
|
what is to be done with the file once it has been uploaded.
|
|
</simpara>
|
|
<note>
|
|
<title>Related Configurations Note</title>
|
|
<para>
|
|
See also the <link linkend="ini.file-uploads">file_uploads</link>,
|
|
<link linkend="ini.upload-max-filesize">upload_max_filesize</link>,
|
|
<link linkend="ini.upload-tmp-dir">upload_tmp_dir</link>, and
|
|
<link linkend="ini.post-max-size">post_max_size</link> directives
|
|
in &php.ini;
|
|
</para>
|
|
</note>
|
|
<para>
|
|
Note that PHP also supports PUT-method file uploads as used by
|
|
Netscape Composer and W3C's Amaya clients. See the <link
|
|
linkend="features.file-upload.put-method">PUT Method
|
|
Support</link> for more details.
|
|
</para>
|
|
<para>
|
|
A file upload screen can be built by creating a special form which
|
|
looks something like this:
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<title>File Upload Form</title>
|
|
<programlisting role="html">
|
|
<![CDATA[
|
|
<form enctype="multipart/form-data" action="_URL_" method="POST">
|
|
<input type="hidden" name="MAX_FILE_SIZE" value="30000">
|
|
Send this file: <input name="userfile" type="file">
|
|
<input type="submit" value="Send File">
|
|
</form>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
The "_URL_" in the above example should be replaced, and point to a PHP
|
|
file. The MAX_FILE_SIZE hidden field (measured in bytes) must precede
|
|
the file input field, and its value is the maximum filesize accepted.
|
|
Also, be sure your file upload form has
|
|
<literal>enctype="multipart/form-data"</literal> otherwise the file
|
|
upload will not work.
|
|
<warning>
|
|
<para>
|
|
The MAX_FILE_SIZE is advisory to the browser. It is easy to
|
|
circumvent this maximum. So don't count on it that the browser
|
|
obeys your wish! The PHP-settings for maximum-size, however,
|
|
cannot be fooled. But you should add MAX_FILE_SIZE anyway as
|
|
it saves users the trouble to wait for a big file being
|
|
transferred only to find out that it was too big afterwards.
|
|
</para>
|
|
</warning>
|
|
</para>
|
|
|
|
<para>
|
|
The Variables defined for uploaded files differs depending on
|
|
the PHP version and configuration. The autoglobal
|
|
<link linkend="reserved.variables.files">$_FILES</link>
|
|
exists as of PHP 4.1.0 The <varname>$HTTP_POST_FILES</varname> array
|
|
has existed since PHP 4.0.0. These arrays will contain all
|
|
your uploaded file information. Using <varname>$_FILES</varname>
|
|
is preferred. If the PHP directive
|
|
<link linkend="ini.register-globals">register_globals</link> is
|
|
<emphasis>on</emphasis>, related variable names will also exist.
|
|
<link linkend="ini.register-globals">register_globals</link>
|
|
defaults to <emphasis>off</emphasis> as of PHP
|
|
<ulink url="&url.php.release4.2.0;">4.2.0</ulink>.
|
|
</para>
|
|
<para>
|
|
The contents of <link linkend="reserved.variables.files">$_FILES</link>
|
|
from our example script is as follows. Note that this assumes the use of
|
|
the file upload name <emphasis>userfile</emphasis>, as used in the example
|
|
script above. This can be any name.
|
|
<variablelist>
|
|
<varlistentry>
|
|
<term><varname>$_FILES['userfile']['name']</varname></term>
|
|
<listitem>
|
|
<para>
|
|
The original name of the file on the client machine.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><varname>$_FILES['userfile']['type']</varname></term>
|
|
<listitem>
|
|
<para>
|
|
The mime type of the file, if the browser provided this
|
|
information. An example would be
|
|
<literal>"image/gif"</literal>.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><varname>$_FILES['userfile']['size']</varname></term>
|
|
<listitem>
|
|
<para>
|
|
The size, in bytes, of the uploaded file.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><varname>$_FILES['userfile']['tmp_name']</varname></term>
|
|
<listitem>
|
|
<para>
|
|
The temporary filename of the file in which the uploaded file
|
|
was stored on the server.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><varname>$_FILES['userfile']['error']</varname></term>
|
|
<listitem>
|
|
<para>
|
|
The <link linkend="features.file-upload.errors">error code</link>
|
|
associated with this file upload. <emphasis>['error']</emphasis>
|
|
was added in PHP 4.2.0
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
</para>
|
|
<note>
|
|
<para>
|
|
In PHP versions prior 4.1.0 this was named
|
|
<varname>$HTTP_POST_FILES</varname> and it's not an
|
|
<link linkend="language.variables.superglobals">autoglobal</link>
|
|
variable like <varname>$_FILES</varname> is. PHP 3 does not
|
|
support <varname>$HTTP_POST_FILES</varname>.
|
|
</para>
|
|
</note>
|
|
<para>
|
|
When <link linkend="ini.register-globals">register_globals</link>
|
|
is turned <emphasis>on</emphasis> in &php.ini;, additional
|
|
variables are available. For example,
|
|
<varname>$userfile_name</varname> will equal
|
|
<varname>$_FILES['userfile']['name']</varname>,
|
|
<varname>$userfile_type</varname> will equal
|
|
<varname>$_FILES['userfile']['type']</varname>, etc. Keep in mind
|
|
that as of PHP 4.2.0, register_globals defaults to off. It's
|
|
preferred to not rely on this directive.
|
|
</para>
|
|
<para>
|
|
Files will by default be stored in the server's default temporary
|
|
directory, unless another location has been given with the <link
|
|
linkend="ini.upload-tmp-dir">upload_tmp_dir</link> directive in
|
|
&php.ini;. The server's default directory can
|
|
be changed by setting the environment variable
|
|
<envar>TMPDIR</envar> in the environment in which PHP runs.
|
|
Setting it using <function>putenv</function> from within a PHP
|
|
script will not work. This environment variable can also be used
|
|
to make sure that other operations are working on uploaded files,
|
|
as well.
|
|
<example>
|
|
<title>Validating file uploads</title>
|
|
<para>
|
|
See also the function entries for <function>is_uploaded_file</function>
|
|
and <function>move_uploaded_file</function> for further information. The
|
|
following example will process the file upload that came from a form.
|
|
</para>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// In PHP earlier then 4.1.0, $HTTP_POST_FILES should be used instead of
|
|
// $_FILES. In PHP earlier then 4.0.3, use copy() and is_uploaded_file()
|
|
// instead of move_uploaded_file
|
|
|
|
$uploaddir = '/var/www/uploads/';
|
|
$uploadfile = $uploaddir. $_FILES['userfile']['name'];
|
|
|
|
print "<pre>";
|
|
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
|
|
print "File is valid, and was successfully uploaded. ";
|
|
print "Here's some more debugging info:\n";
|
|
print_r($_FILES);
|
|
} else {
|
|
print "Possible file upload attack! Here's some debugging info:\n";
|
|
print_r($_FILES);
|
|
}
|
|
print "</pre>";
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
<simpara>
|
|
The PHP script which receives the uploaded file should implement
|
|
whatever logic is necessary for determining what should be done
|
|
with the uploaded file. You can for example use the
|
|
<varname>$_FILES['userfile']['size']</varname> variable
|
|
to throw away any files that are either too small or too big. You
|
|
could use the
|
|
<varname>$_FILES['userfile']['type']</varname> variable
|
|
to throw away any files that didn't match a certain type criteria.
|
|
As of PHP 4.2.0, you could use <varname>$_FILES['userfile']['error']</varname>
|
|
and plan your logic according to the <link
|
|
linkend="features.file-upload.errors">error codes</link>.
|
|
Whatever the logic, you should either delete the file from the
|
|
temporary directory or move it elsewhere.
|
|
</simpara>
|
|
<simpara>
|
|
If no file is selected for upload in your form, PHP will return
|
|
$_FILES['userfile']['size'] as 0, and $_FILES['userfile']['tmp_name'] as
|
|
none.
|
|
</simpara>
|
|
<simpara>
|
|
The file will be deleted from the temporary directory at the end
|
|
of the request if it has not been moved away or renamed.
|
|
</simpara>
|
|
</sect1>
|
|
|
|
<sect1 id="features.file-upload.errors">
|
|
<title>Error Messages Explained</title>
|
|
<simpara>
|
|
Since PHP 4.2.0, PHP returns an appropriate error code along with the
|
|
file array. The error code can be found in the
|
|
<emphasis>['error']</emphasis> segment of the file array that is created
|
|
during the file upload by PHP. In otherwords, the error might be
|
|
found in <varname>$_FILES['userfile']['error']</varname>.
|
|
</simpara>
|
|
<para>
|
|
<variablelist>
|
|
<varlistentry>
|
|
<term><varname>UPLOAD_ERR_OK</varname></term>
|
|
<listitem>
|
|
<para>
|
|
Value: 0; There is no error, the file uploaded with success.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><varname>UPLOAD_ERR_INI_SIZE</varname></term>
|
|
<listitem>
|
|
<para>
|
|
Value: 1; The uploaded file exceeds the
|
|
<link linkend="ini.upload-max-filesize">upload_max_filesize</link>
|
|
directive in &php.ini;.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><varname>UPLOAD_ERR_FORM_SIZE</varname></term>
|
|
<listitem>
|
|
<para>
|
|
Value: 2; The uploaded file exceeds the <emphasis>MAX_FILE_SIZE</emphasis>
|
|
directive that was specified in the html form.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><varname>UPLOAD_ERR_PARTIAL</varname></term>
|
|
<listitem>
|
|
<para>
|
|
Value: 3; The uploaded file was only partially uploaded.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term><varname>UPLOAD_ERR_NO_FILE</varname></term>
|
|
<listitem>
|
|
<para>
|
|
Value: 4; No file was uploaded.
|
|
</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
</para>
|
|
<note>
|
|
<para>
|
|
These became PHP constants in PHP 4.3.0
|
|
</para>
|
|
</note>
|
|
</sect1>
|
|
|
|
<sect1 id="features.file-upload.common-pitfalls">
|
|
<title>Common Pitfalls</title>
|
|
<simpara>
|
|
The <literal>MAX_FILE_SIZE</literal> item cannot specify a file size
|
|
greater than the file size that has been set in the <link
|
|
linkend="ini.upload-max-filesize">upload_max_filesize</link> ini-setting.
|
|
The default is 2 Megabytes.
|
|
</simpara>
|
|
<simpara>
|
|
If memory limit is enabled, larger <link
|
|
linkend="ini.memory-limit">memory_limit</link> may be needed. Make
|
|
sure to set <link linkend="ini.memory-limit">memory_limit</link>
|
|
large enough.
|
|
</simpara>
|
|
<simpara>
|
|
If <link linkend="ini.max-execution-time">max_execution_time</link>
|
|
is set too small, script execution may be exceeded the value. Make
|
|
sure to set <literal>max_execution_time</literal> large enough.
|
|
</simpara>
|
|
<note>
|
|
<simpara>
|
|
<link linkend="ini.max-execution-time">max_execution_time</link> only
|
|
affects the execution time of the script itself. Any time spent
|
|
on activity that happens outside the execution of the script
|
|
such as system calls using <function>system</function>, the
|
|
<function>sleep</function> function, database queries, time taken by
|
|
the file upload process, etc. is not included when determining the maximum
|
|
time that the script has been running.
|
|
</simpara>
|
|
</note>
|
|
<simpara>
|
|
If <link linkend="ini.post-max-size">post_max_size</link> set too
|
|
small, large files cannot be uploaded. Make sure to set
|
|
<literal>post_max_size</literal> large enough.
|
|
</simpara>
|
|
<simpara>
|
|
Not validating which file you operate on may mean that users can access
|
|
sensitive information in other directories.
|
|
</simpara>
|
|
<simpara>
|
|
Please note that the CERN httpd seems to strip off everything
|
|
starting at the first whitespace in the content-type mime header
|
|
it gets from the client. As long as this is the case, CERN httpd
|
|
will not support the file upload feature.
|
|
</simpara>
|
|
<simpara>
|
|
Due to the large amount of directory listing styles we cannot guarantee
|
|
that files with exotic names (like containing spaces) are handled properly.
|
|
</simpara>
|
|
</sect1>
|
|
|
|
<sect1 id="features.file-upload.multiple">
|
|
<title>Uploading multiple files</title>
|
|
<simpara>
|
|
Multiple files can be uploaded using different
|
|
<literal>name</literal> for <literal>input</literal>.
|
|
</simpara>
|
|
<simpara>
|
|
It is also possible to upload multiple files simultaneously and
|
|
have the information organized automatically in arrays for you. To
|
|
do so, you need to use the same array submission syntax in the
|
|
HTML form as you do with multiple selects and checkboxes:
|
|
</simpara>
|
|
<note>
|
|
<para>
|
|
Support for multiple file uploads was added in version 3.0.10.
|
|
</para>
|
|
</note>
|
|
<para>
|
|
<example>
|
|
<title>Uploading multiple files</title>
|
|
<programlisting role="html">
|
|
<![CDATA[
|
|
<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>
|
|
When the above form is submitted, the arrays
|
|
<varname>$_FILES['userfile']</varname>,
|
|
<varname>$_FILES['userfile']['name']</varname>, and
|
|
<varname>$_FILES['userfile']['size']</varname> will be
|
|
initialized (as well as in $HTTP_POST_FILES for PHP version
|
|
prior 4.1.0).
|
|
When
|
|
<literal>register_globals</literal> is on, globals for uploaded
|
|
files are also initialized. Each of these will be a numerically
|
|
indexed array of the appropriate values for the submitted files.
|
|
</simpara>
|
|
<simpara>
|
|
For instance, assume that the filenames
|
|
<filename>/home/test/review.html</filename> and
|
|
<filename>/home/test/xwp.out</filename> are submitted. In this
|
|
case, <varname>$_FILES['userfile']['name'][0]</varname>
|
|
would contain the value <filename>review.html</filename>, and
|
|
<varname>$_FILES['userfile']['name'][1]</varname> would
|
|
contain the value <filename>xwp.out</filename>. Similarly,
|
|
<varname>$_FILES['userfile']['size'][0]</varname> would
|
|
contain <filename>review.html</filename>'s filesize, and so forth.
|
|
</simpara>
|
|
<simpara>
|
|
<varname>$_FILES['userfile']['name'][0]</varname>,
|
|
<varname>$_FILES['userfile']['tmp_name'][0]</varname>,
|
|
<varname>$_FILES['userfile']['size'][0]</varname>, and
|
|
<varname>$_FILES['userfile']['type'][0]</varname> are
|
|
also set.
|
|
</simpara>
|
|
</sect1>
|
|
|
|
<sect1 id="features.file-upload.put-method">
|
|
<title>PUT method support</title>
|
|
<simpara>
|
|
PUT method support has changed between PHP 3 and PHP 4.
|
|
In PHP 4, one should use the standard input stream to read
|
|
the contents of an HTTP PUT.
|
|
</simpara>
|
|
<para>
|
|
<example>
|
|
<title>Saving HTTP PUT files with PHP 4</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
/* PUT data comes in on the stdin stream */
|
|
$putdata = fopen("php://stdin","r");
|
|
|
|
/* Open a file for writing */
|
|
$fp = fopen("myputfile.ext","w");
|
|
|
|
/* Read the data 1kb at a time
|
|
and write to the file */
|
|
while ($data = fread($putdata,1024))
|
|
fwrite($fp,$data);
|
|
|
|
/* Close the streams */
|
|
fclose($fp);
|
|
fclose($putdata);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
<note>
|
|
<para>
|
|
All documentation below applies to PHP 3 only.
|
|
</para>
|
|
</note>
|
|
<para>
|
|
PHP provides support for the HTTP PUT method used by clients such
|
|
as Netscape Composer and W3C Amaya. PUT requests are much simpler
|
|
than a file upload and they look something like this:
|
|
<informalexample>
|
|
<programlisting>
|
|
PUT /path/filename.html HTTP/1.1
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
<para>
|
|
This would normally mean that the remote client would like to save
|
|
the content that follows as: /path/filename.html in your web tree.
|
|
It is obviously not a good idea for Apache or PHP to automatically
|
|
let everybody overwrite any files in your web tree. So, to handle
|
|
such a request you have to first tell your web server that you
|
|
want a certain PHP script to handle the request. In Apache you do
|
|
this with the <emphasis>Script</emphasis> directive. It can be
|
|
placed almost anywhere in your Apache configuration file. A
|
|
common place is inside a <Directory> block or perhaps inside
|
|
a <Virtualhost> block. A line like this would do the trick:
|
|
<informalexample>
|
|
<programlisting>
|
|
Script PUT /put.php
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
<simpara>
|
|
This tells Apache to send all PUT requests for URIs that match the
|
|
context in which you put this line to the put.php script. This
|
|
assumes, of course, that you have PHP enabled for the .php
|
|
extension and PHP is active.
|
|
</simpara>
|
|
<simpara>
|
|
Inside your put.php file you would then do something like this:
|
|
</simpara>
|
|
<para>
|
|
<informalexample><programlisting role="php">
|
|
<![CDATA[
|
|
<?php copy($PHP_UPLOADED_FILE_NAME,$DOCUMENT_ROOT.$REQUEST_URI); ?>
|
|
]]>
|
|
</programlisting></informalexample>
|
|
</para>
|
|
<simpara>
|
|
This would copy the file to the location requested by the remote
|
|
client. You would probably want to perform some checks and/or
|
|
authenticate the user before performing this file copy. The only
|
|
trick here is that when PHP sees a PUT-method request it stores
|
|
the uploaded file in a temporary file just like those handled but
|
|
the <link
|
|
linkend="features.file-upload.post-method">POST-method</link>.
|
|
When the request ends, this temporary file is deleted. So, your
|
|
PUT handling PHP script has to copy that file somewhere. The
|
|
filename of this temporary file is in the $PHP_PUT_FILENAME
|
|
variable, and you can see the suggested destination filename in
|
|
the $REQUEST_URI (may vary on non-Apache web servers). This
|
|
destination filename is the one that the remote client specified.
|
|
You do not have to listen to this client. You could, for example,
|
|
copy all uploaded files to a special uploads directory.
|
|
</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:
|
|
vim600: syn=xml fen fdm=syntax fdl=2 si
|
|
vim: et tw=78 syn=sgml
|
|
vi: ts=1 sw=1
|
|
-->
|