1. File upload
In order for the client's user to upload files, we must provide a form in the user interface to submit requests to upload files. Since the uploaded file is a special data, unlike other post data, we must set a special encoding for the form:
Copy the code as follows:<form action="upload.php" method="POST" enctype="multipart/form-data"></form>
You may not be familiar with the above enctype attributes, because this is often ignored. However, if the http post request contains both regular data and file-like data, this attribute should be added, which can improve compatibility for various browsers.
Next, we have to add a field to the form to upload the file:
Copy the code as follows: <input type="file" name="attachment">
The above file fields may behave differently in various browsers. For most browsers, the above fields are rendered into a text box with a browsing button. In this way, the user can enter the file path into the text box by himself, or select the file to be uploaded from the local hard disk through the browsing button. However, in Apple's Safari, it seems that only browsing can be used. Of course, you can also customize the style of this upload box to make it look more elegant than the default style.
Below, in order to better explain how to handle file uploads, give a complete example. For example, the following form allows users to upload attachments to my local server:
Copy the code as follows: <p>Please upload your attachment:</p>
<form action="upload.php" method="POST" enctype="multipart/form-data">
<input type="file" name="attachment">
<input type="submit" value="upload attachment">
</form>
Tip: You can set the maximum value that allows uploading files through upload_max_filesize in php.ini. In addition, there is also a post_max_size that can be used to set the maximum form data that is allowed to be uploaded. The specific meaning is the sum of various data in the form, so you can also control the maximum value of the uploaded file by setting this field. However, note that the value of the latter must be greater than the former, because the former belongs to a portion of the form data of the latter.
Figure 1. Upload form shown in firefox
When this form is submitted, the http request will be sent to upload.php. In order to show what specific information can be used in upload.php, I printed it out in upload.php:
The code copy is as follows:
header('Content-Type: text/plain');
print_r($_FILES);
Let’s do an experiment. If I upload a blog logo to my local server www.360weboy.me/upload.php through the above form, see what information will be output in upload.php:
Copy the code as follows: Array
(
[attachment] => Array
(
[name] => boy.jpg
[type] => image/jpeg
[tmp_name] => D:/xampp/tmp/php1168.tmp
[error] => 0
[size] => 11490
)
)
The above is all the information about the currently uploaded file in the global array after the file is uploaded. However, can we ensure that this information is safe, what if name or other information has been tampered with? We always need to be vigilant about information from clients!
Each part of the specific http request
In order to better understand file upload, we must check what specific information is contained in the http request sent by the client. The attachment I uploaded before was the logo of this blog, because it is a picture, it is not suitable for us to do the above experiments. So, I uploaded a test.text text file again, which contains the following content:
The code copy is as follows:
360w
360days
Life Of A Web Boy
Okay. Now I upload this text file and output it in upload.php:
The code copy is as follows:
Array
(
[attachment] => Array
(
[name] => test.txt
[type] => text/plain
[tmp_name] => D:/xampp/tmp/php51C0.tmp
[error] => 0
[size] => 40
)
)
Let's take a look at the http post request sent by the relevant browser (I omitted some optional headers):
The code copy is as follows:
POST /upload.php HTTP/1.1
Host: www.360weboy.me
Referer: http://www.360weboy.me/
multipart/form-data; boundary=---------------------------------------------------------------------------------------------------------------------
Content-Length: 234
---------------------------------------24464570528145
Content-Disposition: form-data; name="attachment"; filename="test.txt"
Content-Type: text/plain
360weboy
360days
Life Of A Web Boy
------------------------------------24464570528145-
There are several fields in the above request format, name, filename and Content-Type. They represent the field name-attachment of the upload file box in the form form, the file uploaded by the user from the local hard disk. The name is test.txt, and the uploaded file format text/plain (represents text file). Then, we see that the following line is the specific content in the uploaded file.
2. Strengthening safety
In order to enhance the security in file upload, we need to check the tmp_name and size in the $_FILES global array. In order to ensure that the file pointed to by tmp_name is indeed the file uploaded by the user on the client, rather than the pointing to something like /etc/passwd, you can use the function is_uploaded_file() in php to make the following judgment:
The code copy is as follows:
$filename = $_FILES['attachment']['tmp_name'];
if (is_uploaded_file($filename)) {
/* is an uploaded file. */
}
In some cases, after the user uploads the file, the content of the successfully uploaded file may be displayed to the user for viewing, so the check of the above code is particularly important.
Another thing to check is the mime-type of the upload file, which is the type field of the output array in the above upload.php. What I uploaded in the first example is an image, so the value of $_FILES['attachment']['type'] is 'image/jpeg'. If you plan to only accept mime-type images such as image/png, image/jpeg, image/gif, image/x-png and image/p-jpeg on the server side, you can use code similar to the following to check (just give a look at it) Examples, specific codes, such as errors, should follow the mechanisms in your system):
The code copy is as follows:
$allow_mimes = array(
'image/png',
'image/x-png',
'image/gif',
'image/jpeg',
'image/pjpeg'
);
$image = $_FILES['attachment'];
if(!in_array($image['type'], $allow_mimes)) {
die('Sorry, the file format you uploaded is inaccurate; we only accept image files.');
}
// Continue to process uploaded image files
As you can see, we have ensured that the mime-type of the file meets the server-side requirements. However, it is not enough to prevent malicious users from uploading other harmful files, because malicious users can pretend to be disguised by this mime-type. For example, the user made a jpg picture, wrote some malicious php code into the metadata of the picture, and saved it as a file with the suffix named php. When this malicious file is uploaded, it will be successfully checked by the server side for mime-type, which is considered to be a picture, and the dangerous php code inside will be executed. The metadata of the specific picture is similar to the following:
The code copy is as follows:
File name: image.jpg
File size : 182007 bytes
File date : 2012:11:27 7:45:10
Resolution : 1197 x 478
Comment : passthru($_POST['cmd']); __halt_compiler();
We can see that php code is added to the Comment field of the image metadata. So, it is obvious that in order to prevent similar dangerous situations, a necessary check of the extension of the uploaded file must also be carried out. The following code enhances the previous code for checking Mime-type:
The code copy is as follows:
$allow_mimes = array(
'image/png' => '.png',
'image/x-png' => '.png',
'image/gif' => '.gif',
'image/jpeg' => '.jpg',
'image/pjpeg' => '.jpg'
);
$image = $_FILES['attachment'];
if(!array_key_exists($image['type'], $allow_mimes )) {
die('Sorry, the file format you uploaded is inaccurate; we only accept image files.');
}
// Get the file name with omitted suffix name:
$filename = substr($image['name'], 0, strpos($image['name'], '.'));
// Add a suffix name
$filename .= $allow_mimes[$image['type']];
// Continue to process uploaded files
Through the above code, we ensure that even if the uploaded image metafile contains the php code, the image file will be renamed as a file with the suffix name and the image format, so the php code in it will not be executed. The above code will not have any negative impact on normal uploaded images.
After performing the above several steps to improve security checks, if you just want to save the uploaded file to a specified directory, you can use the default function move_uploaded_file of php to implement it:
The code copy is as follows:
$tmp_filename = $_FILES['attachment']['tmp_name'];
$filename = '/path/to/attachment.txt';
if (move_uploaded_file(tmp_filename, $filename)) {
/* $temp_filename The upload file saved in the temporary directory, and then successfully save it to the attachment.txt file in the corresponding directory. */
}
You may also have to limit the size of the uploaded file, so you can use the filesize function to get the size of the uploaded file, make judgments and do further processing. This is not the case here, just do it yourself.
Okay, let’s write this for now about file upload. Hope this introductory article will be helpful to you.