HTML forms have capability for uploading files of arbitrarily large size 39. The files are typically transmitted through HTTP POST method 40.
39) HTTP file uploads are described in RFC-1867. This mechanism allows to upload large files by using binary content transfer encoding. The "multipart/form-data" encoding type is utilized for this purpose.
40) The HTTP GET method is inefficient for file uploads, because URL length has some upper limit. Also, URL-encoding the file data greatly increases the URL length.
By default, HTTP uses the URL encoding for transfers of form data, and you could see how that encoding looks like in previous chapters. However, this encoding is inefficient for uploading large files, since URL-encoding binary data dramatically increases the length of the HTTP request. For the purpose of uploading files, it is instead recommended to use the so called "binary transfer encoding" described in the next section.
A simple HTML form capable of file uploads is shown in the code example below. The binary
encoding type is enabled by setting the enctype
attribute of the form with the value
of "multipart/form-data":
<form action="upload" method="POST" enctype="multipart/form-data">
<input type="file" name="myfile">
<br/>
<input type="submit" name="Submit">
</form>
In line 1, we explicitly set form encoding (enctype
attribute) to "multipart/form-data"
to utilize effective binary content transfer encoding for the form.
In line 2, we define an input field with type "file" and name "myfile". This input field will allow site visitor to select the file for upload.
If you now save the above mentioned markup to an .html file and open it in your web browser, you will see the page like in figure 10.1.
The file element has the Browse... button allowing to pick a file for upload. When the site user picks some file and clicks the Submit button on the form, the web browser will send an HTTP request to the web server, and the request will contain the data of the file being uploaded. The example below illustrates how the HTTP request may look like:
POST http://localhost/upload HTTP/1.1
Host: localhost
Content-Length: 488
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64)
Content-Type: multipart/form-data; boundary=----j1bOrwgLvOC3dy7o
Accept-Encoding: gzip,deflate,sdch
------j1bOrwgLvOC3dy7o
Content-Disposition: form-data; name="myfile"; filename="Somefile.txt"
Content-Type: text/html
(file binary data goes here)
------j1bOrwgLvOC3dy7o
Content-Disposition: form-data; name="Submit"
Submit Request
------j1bOrwgLvOC3dy7o--
As you can see from the example above, the HTTP request with "multipart/form-data" encoding type looks analogous to a usual HTTP request (has the status line, the headers, and the content area), however it has the following important differences:
Line 5 sets the "Content-Type" header with "multipart/form-data" value; The form is assembled of the fields marked by the "boundary" -- a unique randomly generated sequence of characters delimiting form fields of each other.
Lines 8-17 represent the content of the HTTP request. The form fields are delimited by the "boundary" sequences (lines 8, 13, 17). The data of the file being uploaded are transmitted in binary format (line 12), and that allows to reduce the content size to its minimum.
By default, PHP engine's settings do not allow to upload large files (larger than 2MB). In order to upload large files, you may need to edit the php.ini configuration file and modify the
post_max_size
andupload_max_filesize
parameters (please refer to Appendix A. Configuring Web Development Environment for information on how to do that). Setting these with100M
allows to upload files up to 100 Mb in size, and this would typically be sufficient. If you plan to upload very large files up to 1 GB in size, than better set these with 1024M. Do not forget to restart your Apache Web Server after editing the configuration file.
When a site visitor uploads some files to your Apache Web Server, the files are placed to a temporary location
(usually to system temporary directory that is /tmp in Linux and C:\Windows\Temp in Windows).
The PHP script receives the file information to the special super-global array named $_FILES
.
The
$_FILES
array is analogous to the$_GET
and$_POST
super-globals. The latter two are used to store the GET and POST variables, respectively, while the first one is used to store information about uploaded files.
For example, for the above mentioned simple upload form, the $_FILES
super-global array will look
as follows (the output is generated with the var_dump()
PHP function):
array (size=1)
'myfile' =>
array (size=5)
'name' => string 'somefile.txt' (length=12)
'type' => string 'text/plain' (length=10)
'tmp_name' => string '/tmp/phpDC66.tmp' (length=16)
'error' => int 0
'size' => int 18
As you can see from the example above, the $_FILES
array contains an entry per
each uploaded file. For each uploaded file, it contains the following information:
name
-- original file name (line 4).type
-- MIME 41 type of the file (line 5).tmp_name
-- temporary name for the uploaded file (line 6).error
-- error code signalling about the status of the upload (line 7);
error code zero means the file was uploaded correctly.size
-- file size in bytes (line 8).41) MIME type, also known as "content type" is a standard identifier used on the Internet to indicate the type of data that a file contains. For example the "text/plain" MIME type is assigned to a text file, while the "application/octet-stream" MIME type is assigned to a binary file.
PHP engine stores the uploaded files in a temporary location which is cleaned up as soon as the PHP
script execution ends. So, if you want to save the uploaded files to some directory for later use,
you need to utilize the move_uploaded_file()
PHP function. The move_uploaded_file()
function
takes two arguments: the first one is the name of the temporary file, and the second one is the
destination file name.
You might be confused why you cannot use the usual
rename()
PHP function for moving the temporary uploaded file to its destination path. PHP has special function for moving uploaded files for security reasons. Themove_uploaded_file()
function is analogous torename()
function, but it takes some additional checks to ensure the file was really transferred through HTTP POST request, and that the upload process has finished without errors.
The following code example shows how to move the file uploaded with the simple form we have considered above:
$destPath = '/path/to/your/upload/dir';
$result = move_uploaded_file($_FILES['myfile']['tmp_name'], $destPath);
if(!$result) {
// Some error occurred.
}
Above, in line 1, we set the $destPath
with the directory name where to save the
uploaded file.
In line 2, we call the move_uploaded_file()
function and pass it two arguments: the path to the
temporary file and the destination path.
Specifying the directory name as the second argument of the
move_uploaded_file()
function is suitable when you do not want to rename the file. If you need to save the uploaded file under another name than its original name, you can specify the full file path instead of the directory name.
In line 3, we check the returned value of the function. If the operation is successful,
the function will return true
. If some error occurs (for example, if directory permissions
are insufficient to save the file), the boolean false
will be returned.