Writing the lawmaking to upload images to a server from scratch seems like a very daunting task. I'm going to make a very elementary upload class to demonstrate how file data works and can exist transferred.

In this tutorial, we're going to build an upload form with HTML, ship the files with JavaScript, and process and upload them with PHP.

Annotation that this is not meant to be fully functional, secure, validated, product code. It is but meant to demonstrate in a simple and straightforward manner how to make your beginning upload form.

  • View Source on GitHub

Prerequisites

  • A basic noesis of HTML
  • A bones cognition of PHP syntax and lawmaking structure
  • An understanding of local PHP environments. If y'all don't know what that means, please read this guide on how to set up a MAMP environment.

Goals

  • Build the simplest possible grade with HTML to take a retrieve files from your local calculator.
  • Send the data from an HTML form to a PHP script with vanilla JavaScript.
  • Process the data in the PHP script and move the local files to an uploads/ directory on a server.

Setup

As mentioned in the prerequisites, you lot must have a basic knowledge of PHP and local server environments.

If y'all already know how to utilize PHP and local environments, skip to the next section.

If you're using a Mac, you lot tin can create a server with a single command. To test this, create a file called test.php in the directory of your choice. I'yard going to create a directory called local. The full path will be Users/tania/local.

test.php

                                          <?php                echo                'This is only a test.'                ;                                    

In the Concluding application, which I'll open by pressing SPACEBAR + Command and typing Terminal, navigate to the directory you created your file in.

You should at present be able to become to http://localhost:8888/exam.php and run across the output of the lawmaking.

Screen Shot 2018 04 26 at 3 50 21 PM

If you're on Windows, or yous don't want to use the control line, set up MAMP.

Edifice an Upload Form in HTML

In the root of your local server, create an index.html file. We'll just create a quick skeleton.

                                          <!                DOCTYPE                html                >                                                              <html                lang                                  =                  "en"                                >                                                              <caput                >                                                              <meta                charset                                  =                  "UTF-viii"                                />                                                              <meta                proper name                                  =                  "viewport"                                content                                  =                  "width=device-width, initial-scale=1.0"                                />                                                              <meta                http-equiv                                  =                  "X-UA-Compatible"                                content                                  =                  "ie=edge"                                />                                                              <title                >              Upload Files                                  </title                >                                                              </head                >                                                              <body                >                            <!-- class goes here-->                                                </torso                >                                                              </html                >                                    

Let's add an HTML web grade to the body.

                                                            <form                method                                  =                  "mail"                                enctype                                  =                  "multipart/form-data"                                >                                                              <input                type                                  =                  "file"                                proper noun                                  =                  "files[]"                                multiple                />                                                              <input                type                                  =                  "submit"                                value                                  =                  "Upload File"                                name                                  =                  "submit"                                />                                                              </grade                >                                    

In this grade, nosotros're using the Postal service HTTP method, which how we ship data. The multipart/form-information value is required for uploading files in forms.

From here, we're creating a file input type that takes an array of files (files[]) and we're specifying multiple to allow more than one file to be selected. files[] tin have any name - yous could use uploads[] or images[], but I called information technology files[] for simplicity.

Finally, we have a submit button. Since the adjacent step will exist to add a script, let's just add a link to the JavaScript file nosotros'll create.

                                                            <script                src                                  =                  "upload.js"                                >                                                                            </script                >                                    

And that's all we need for the view.

index.html

                                          <!                DOCTYPE                html                >                                                              <html                lang                                  =                  "en"                                >                                                              <caput                >                                                              <meta                charset                                  =                  "UTF-8"                                />                                                              <meta                proper name                                  =                  "viewport"                                content                                  =                  "width=device-width, initial-calibration=one.0"                                />                                                              <meta                http-equiv                                  =                  "X-UA-Compatible"                                content                                  =                  "ie=edge"                                />                                                              <title                >              Upload Files                                  </championship                >                                                              </caput                >                                                              <body                >                                                              <form                method                                  =                  "post"                                enctype                                  =                  "multipart/form-data"                                >                                                              <input                type                                  =                  "file"                                proper name                                  =                  "files[]"                                multiple                />                                                              <input                type                                  =                  "submit"                                value                                  =                  "Upload File"                                name                                  =                  "submit"                                />                                                              </course                >                                                              <script                src                                  =                  "upload.js"                                >                                                                            </script                >                                                              </body                >                                                              </html                >                                    

Screen Shot 2018 04 26 at 4 12 29 PM

Sending Course Information via JavaScript

Right at present, clicking submit on the form doesn't go anywhere. Since we don't have an activeness that leads to a URL, the form volition just post to itself by default. Since alphabetize.html is an html file, non a PHP file, no class processing tin can happen on this page. Instead, nosotros'll send the class to PHP through JavaScript.

Create a file called upload.js.

First, let's ascertain two variables - the URL where we want to ship the data, and the DOM chemical element for the class.

upload.js

                          // Define processing URL and form element              const              url              =              'process.php'              const              form              =              certificate.              querySelector              (              'form'              )                      

Nosotros're going to add together an outcome listener to watch for the class existence submitted, just we'll foreclose the default action from firing.

                          // Listen for form submit              form.              addEventListener              (              'submit'              ,              (              e              )              =>              {              eastward.              preventDefault              (              )              // ...              }              )                      

Let's gather the files with the .files property, and begin a new FormData() interface.

                          // Gather files and brainstorm FormData              const              files              =              document.              querySelector              (              '[blazon=file]'              )              .files;              const              formData              =              new              FormData              (              )              ;              }              )              ;              // ...                      

For each file that has been submitted, suspend it to the files[] array.

                          // Append files to files array              for              (              let              i              =              0              ;              i              <              files.length;              i++              )              {              allow              file              =              files[i]              formData.              append              (              'files[]'              ,              file)              }              // ...                      

Finally, use the built-in Fetch API to POST the data to the URL nosotros specified. Print the response to the panel (for testing purposes).

                          fetch              (url,              {              method:              'Mail service'              ,              trunk:              formData,              }              )              .              then              (              (              response              )              =>              {              console.              log              (response)              }              )                      

Here is the completed upload.js.

upload.js

                          const              url              =              'process.php'              const              grade              =              document.              querySelector              (              'course'              )              form.              addEventListener              (              'submit'              ,              (              due east              )              =>              {              eastward.              preventDefault              (              )              const              files              =              document.              querySelector              (              '[type=file]'              )              .files              const              formData              =              new              FormData              (              )              for              (              let              i              =              0              ;              i              <              files.length;              i++              )              {              let              file              =              files[i]              formData.              append              (              'files[]'              ,              file)              }              fetch              (url,              {              method:              'Mail service'              ,              body:              formData,              }              )              .              then              (              (              response              )              =>              {              console.              log              (response)              }              )              }              )                      

Now - how can we test if all this information is going through properly? Let's print out the file data.

Create a new file chosen process.php, and print out the contents of the superglobal assortment $_FILES, which will contain the data for all our files.

process.php

In one case you have this file, attempt uploading a few files through the form. I made a phplogo.png and testfile1.txt to examination with, and uploaded the file.

In Developer Tools, under the Console, y'all should come across a response like this:

Developer Tools -> Console

                                                                                                                                                        Response              {              blazon:              "basic",   url:              "http://localhost:8888/process.php",   redirected: fake,   status:              200,   ok: true, …              }                      

If you see status: 200, this ways the file striking the proper URL and the URL exists.

Now in Developer tools, click on the Network tab. Y'all should meet the filename process.php. Click on the file, and click on Response. There, y'all should see the output of print_r($FILES). It volition look something like this:

Developer Tools -> Network -> Response

                          [files]              =>              Assortment              (              [name]              =>              Array              (              [              0              ]              =>              phplogo.png              [              1              ]              =>              testfile1.txt              )              [type]              =>              Array              (              [              0              ]              =>              prototype/png              [              ane              ]              =>              text/plain              )              [tmp_name]              =>              Assortment              (              [              0              ]              =>              /              private              /              var              /xxx              [              1              ]              =>              /              private              /              var              /yyy              )              [error]              =>              Assortment              (              [              0              ]              =>              0              [              1              ]              =>              0              )              [size]              =>              Array              (              [              0              ]              =>              16610              [              1              ]              =>              12              )              )                      

Now we know the proper files, forth with all their associated data, have gone through. Success!

Processing Form Data with PHP

Now that we're gathering all the files from the form and sending them to process.php with JavaScript, nosotros have to motility the file data with PHP.

Commencement, we'll want to make sure the code only runs when a POST request hits the file.

process.php

                                          <?php                if                (                $_SERVER                [                'REQUEST_METHOD'                ]                ===                'POST'                )                {                // ...                }                                    

We also want to make sure files have gone through.

                          if              (              isset              (              $_FILES              [              'files'              ]              )              )              {              // ...              }                      

Create a directory in the root of your project called uploads. This directory will demand to take 755 permissions to accept incoming files.

At this point, we'll create an array for errors, set the path of the directory where uploads should go, and set the approved extensions.

                          $errors              =              [              ]              ;              $path              =              'uploads/'              ;              $extensions              =              [              'jpg'              ,              'jpeg'              ,              'png'              ,              'gif'              ]              ;                      

Since the user can upload multiple files, we'll create an $all_files variable, become the number of files being uploaded, and make a for loop.

                          $all_files              =              count              (              $_FILES              [              'files'              ]              [              'tmp_name'              ]              )              ;              for              (              $i              =              0              ;              $i              <              $all_files              ;              $i              ++              )              {              // ...              }                      

Now, for each file we'll go the file name, temporary file data, type, size, and extension.

                          $file_name              =              $_FILES              [              'files'              ]              [              'name'              ]              [              $i              ]              ;              $file_tmp              =              $_FILES              [              'files'              ]              [              'tmp_name'              ]              [              $i              ]              ;              $file_type              =              $_FILES              [              'files'              ]              [              'blazon'              ]              [              $i              ]              ;              $file_size              =              $_FILES              [              'files'              ]              [              'size'              ]              [              $i              ]              ;              $file_ext              =              strtolower              (              stop              (              explode              (              '.'              ,              $_FILES              [              'files'              ]              [              'proper name'              ]              [              $i              ]              )              )              )              ;              $file              =              $path              .              $file_name              ;                      

Now we can set a few rules for the files. If the file type in not in the canonical list of extensions, or the file is too large, we'll add together it to the error array. I set a file size of 2 megabytes.

                          if              (              !              in_array              (              $file_ext              ,              $extensions              )              )              {              $errors              [              ]              =              'Extension non allowed: '              .              $file_name              .              ' '              .              $file_type              ;              }              if              (              $file_size              >              2097152              )              {              $errors              [              ]              =              'File size exceeds limit: '              .              $file_name              .              ' '              .              $file_type              ;              }                      

If in that location were no errors, we tin can go ahead and move the file to the uploads binder with the move_uploaded_file control.

                          if              (              empty              (              $errors              )              )              {              move_uploaded_file              (              $file_tmp              ,              $file              )              ;              }                      

Now we tin can close out the for loop, and print out the errors. This will display for us in the network tab we used before to see the output of $_FILES.

                          if              (              $errors              )              print_r              (              $errors              )              ;                      

Put it all together, and hither'south procedure.php.

procedure.php

                                          <?php                if                (                $_SERVER                [                'REQUEST_METHOD'                ]                ===                'POST'                )                {                if                (                isset                (                $_FILES                [                'files'                ]                )                )                {                $errors                =                [                ]                ;                $path                =                'uploads/'                ;                $extensions                =                [                'jpg'                ,                'jpeg'                ,                'png'                ,                'gif'                ]                ;                $all_files                =                count                (                $_FILES                [                'files'                ]                [                'tmp_name'                ]                )                ;                for                (                $i                =                0                ;                $i                <                $all_files                ;                $i                ++                )                {                $file_name                =                $_FILES                [                'files'                ]                [                'proper name'                ]                [                $i                ]                ;                $file_tmp                =                $_FILES                [                'files'                ]                [                'tmp_name'                ]                [                $i                ]                ;                $file_type                =                $_FILES                [                'files'                ]                [                'type'                ]                [                $i                ]                ;                $file_size                =                $_FILES                [                'files'                ]                [                'size'                ]                [                $i                ]                ;                $file_ext                =                strtolower                (                stop                (                explode                (                '.'                ,                $_FILES                [                'files'                ]                [                'proper noun'                ]                [                $i                ]                )                )                )                ;                $file                =                $path                .                $file_name                ;                if                (                !                in_array                (                $file_ext                ,                $extensions                )                )                {                $errors                [                ]                =                'Extension not immune: '                .                $file_name                .                ' '                .                $file_type                ;                }                if                (                $file_size                >                2097152                )                {                $errors                [                ]                =                'File size exceeds limit: '                .                $file_name                .                ' '                .                $file_type                ;                }                if                (                empty                (                $errors                )                )                {                move_uploaded_file                (                $file_tmp                ,                $file                )                ;                }                }                if                (                $errors                )                print_r                (                $errors                )                ;                }                }                                    

At present test information technology out. If you employ the form to upload some files, you'll come across them in the uploads folder. If you try to upload a file that's too large or of the wrong type, y'all'll see the errors in the Network response.

Conclusion

Congratulations, you've successfully created a functioning upload form. This is an exciting little process if you've never successfully uploaded a file or used the $_FILES superglobal before.

The complete source is on GitHub.

  • View Source on GitHub

Note that this is not a complete, secure, product procedure. Here are a few things to take into consideration:

  • There is no JavaScript side validation. The user should be shown an error on the front cease if their file is of the incorrect blazon before they submit.
  • Dealing with mutiple files with the aforementioned name.
  • This method of error treatment is but for the development process.

Thanks for reading. I tin can also make 1 well-nigh uploading to Amazon S3 and/or DigitalOcean Spaces if there's interest.