PHP file upload tutorial (example)

  • 2020-03-30 02:37:06
  • OfStack

One, file upload

In order for a client user to be able to upload a file, we must provide a form in the user interface for submitting a request to upload a file. Since the uploaded file is a kind of special data, different from other post data, we must set a special code for the form:

<form action="upload.php" method="POST" enctype="multipart/form-data"></form>


The above enctype attribute may not be familiar to you because it is often ignored. However, if the HTTP post request contains both regular data and file-like data, this property should be shown plus to improve compatibility with various browsers.

Next, we need to add a field to the form for uploading files:

<input type="file" name="attachment">


The above file fields may behave differently in various browsers. For most browsers, the above fields are rendered as a text box with a browse button. In this way, the user can either enter the path of the file into the text box or select the file to be uploaded from the local hard disk by the browse button. However, in apple's Safari, it seems that browsing is the only way to work. Of course, you can also customize the style of the upload box to make it look more elegant than the default style.

Here, to better illustrate how to handle file uploads, is a complete example. For example, the following form allows users to upload attachments to my local server:

<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=" To upload attachments "> 
</form>

Tip: upload_max_filesize in php.ini can be used to set the maximum number of files allowed to be uploaded. In addition, there is a post_max_size that can also be used to set the maximum amount of form data that can be uploaded, which means the sum of the various data in the form, so you can also set this field to control the maximum amount of uploaded files. However, note that the value of the latter must be greater than the former because the former is part of the form data of the latter.

< img border = 0 id = theimg onclick = window. The open this. (SRC) SRC = "/ / files.jb51.net/file_images/article/201404/2014410115518006.jpg? 2014310115531 ">  

Figure 1. The upload form shown in firefox

When the form is submitted, the HTTP request is sent to upload.php. To show exactly what information can be used in upload.php, I print it out in upload.php:


header('Content-Type: text/plain');
print_r($_FILES);


Here to do a test, if I through the above form to upload a logo this blog to my local server, www.360weboy.me/upload.php, look at the upload. What will the output information in PHP:
 Array
        (
            [attachment] => Array
                (
                    [name] => boy.jpg
                    [type] => image/jpeg
                    [tmp_name] => D:xampptmpphp1168.tmp
                    [error] => 0
                    [size] => 11490
                )

        )


That is all the information about the current uploaded file in the global array after the file has been uploaded. But can we guarantee that the information is secure if the name or other information has been tampered with? We always need to be alert to information from clients!

The specific parts of the HTTP request
To better understand file uploads, we have to check what specific information is included in the HTTP requests sent by the client. The attachment I uploaded before is the logo of this blog. Because it is a picture, it is not suitable for us to do the above experiment. So, I re-uploaded a test.text file, which contains the following contents:


    360w
    360days
    Life Of A Web Boy

Okay. Now I will upload this text file, and in upload.php it will output:


        Array
        (
            [attachment] => Array
                (
                    [name] => test.txt
                    [type] => text/plain
                    [tmp_name] => D:xampptmpphp51C0.tmp
                    [error] => 0
                    [size] => 40
                )

        )
 
   
Let's take a look at the HTTP post requests sent by related browsers (I omitted some optional headers) :


        POST /upload.php HTTP/1.1
        Host: www.360weboy.me
        Referer: http://www.360weboy.me/
        multipart/form-data; boundary=---------------------------24464570528145
        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 a few fields that we need to focus on from the request format above: name, filename, and content-type. They represent the field name -- attachment of the upload file box in the form form, the filename -- filename -- that the user uploads from the local hard disk, and the file format -- text/plain -- that the user uploads. Then, below a blank line, we see the details of the upload file.

Second, the strengthening of security
To enhance security in file uploads, we need to check the tmp_name and size in the $_FILES global array. To make sure that the file tmp_name refers to is actually the file the user just uploaded on the client side, and not something like /etc/passwd, you can use the PHP function is_uploaded_file() to determine:



        $filename = $_FILES['attachment']['tmp_name'];

        if (is_uploaded_file($filename)) { 
            
        }
 
   
In some cases, the contents of the successfully uploaded file may be displayed to the user after the user uploads the file, so it is particularly important to check the above code.

The other thing to check is the mime-type for the uploaded file, which is the type field of the output array in upload.php. I uploaded an image in the first example, so the value of $_FILES['attachment']['type'] is 'image/jpeg'. If you intend to accept only mime-type images such as image/ PNG, image/jpeg, image/ GIF, image/x-png and image/p-jpeg on the server side, you can check with code similar to the following (just for example, the specific code, such as error reporting, should follow the mechanism in your system):

    
        $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(' I'm sorry ,  The format of the file you uploaded is not accurate; We only accept image files .');
        }

        //Continue to process uploaded image files
     
As you can see, we've ensured that the file's mime-type is server-side. However, this is not enough to prevent malicious users from uploading other harmful files, because the mime-type malicious user can be disguised. For example, the user makes a JPG image, writes some malicious PHP code into the image's metadata, and then saves it as a file with a PHP suffix. When the malicious file is uploaded, it passes the server side of the mime-type check, is considered a picture, and the dangerous PHP code inside will be executed. The metadata of the specific picture is similar to the following:


        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();
 
   
As you can see, PHP code has been added to the Comment field of the image metadata. So, obviously, in order to prevent such a dangerous situation, you must also do a necessary check on the extension of the uploaded file. The following code reinforces the previous code that checks for mime-type:


        $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(' I'm sorry ,  The format of the file you uploaded is not accurate; We only accept image files .');
        }

        //Gets the filename with the suffix omitted:
        $filename = substr($image['name'], 0, strrpos($image['name'], '.'));

        //Suffixed name
        $filename .= $allow_mimes[$image['type']];

        //Continue processing uploaded files
     
With the above code, we ensure that even if the uploaded image metafile contains PHP code, the image file will be renamed with the suffix image format, so the PHP code will not be executed. The above code will not have any negative effect on normal uploaded images.

After the security check steps above, if you just want to save the uploaded file to a specified directory, you can use PHP's default function move_uploaded_file:



        $tmp_filename = $_FILES['attachment']['tmp_name'];
        $filename = '/path/to/attachment.txt';

        if (move_uploaded_file(tmp_filename, $filename)) { 
            
        }
   
You may also have a limit on the size of the uploaded file, so you can use the filesize function to get the size of the uploaded file, determine the size, and then work with it.


Related articles: