Multi uploading in PHP, Jquery and The File Api With Thumbnail Preview

In this tutorial we will create a multi upload form using php, jquery and the new javascript File Api. for people who don’t know the File Api it’s a new Api Added to the DOM in the Html5 specification that enables web browsers to read the file locally and displays its contents before uploading them to the server. in this tutorial we will use it to display a thumbnail preview of each image that we select. refer to my article here for more details about the file api.

 

Project requirements

  • twitter bootstrap.
  • jquery library.
  • php with apache or IIS server.

 

Implementation

 

Project Structure

first create a new directory in your localhost path with the below file structure.

 

  • index.php: load the home page which contains the upload form.
  • upload.php: will do the actual uploading of the form.
  • success.php: loaded when upload is done and success message displayed to the user along with the uploaded images.
  • js: contain javascript files required for form manipulation.
  • css: contain custom css for the form.
  • uploads: writable directory that will contain the uploaded images. be sure that to give this directory a writable permission.

  • Let’s begin with the homepage index.php

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Multi upload</title>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" crossorigin="anonymous">

        <link rel="stylesheet" href="css/style.css" type="text/css" />
    </head>
    <body id="wrapper">
        <div class="row">
            <div class="col-md-12">
                <form method="post" action="upload.php" enctype="multipart/form-data">
                    <div class="row">
                        <div class="col-md-3">
                            <label for="image">Choose images</label>
                        </div>
                        <div class="col-md-6">
                            <input type="file" class="form-control" id="file-input" style="display: none;" />
                            <button type="button" id="add-images" class="btn btn-warning">Add images</button>
                        </div>
                       
                    </div>

                    <div id="preview">
                        <div class="row">

                        </div>
                    </div>

                    <button type="submit" name="submit" class="btn btn-primary">Upload</button>
                </form>
            </div>
        </div>


        <script src="https://code.jquery.com/jquery-1.12.4.min.js" crossorigin="anonymous"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" crossorigin="anonymous"></script>
        <script type="text/javascript" src="js/scripts.js"></script>
    </body>
</html>

In the above code first we begin by loading some external assets for jquery and bootstrap then we create a form with file input that has a display none and button of type button like this.

<input type="file" class="form-control" id="file-input" style="display: none;" />
<button type="button" id="add-images" class="btn btn-warning">Add images</button>

and the reason we  set display none to the file input to show a nice upload button with bootstrap instead of the classic html file input.

Then we create a div with id of #preview and this will contain the thumbnails of the selected images.

<div id="preview"> <div class="row"> </div> </div>

 

Next we will go through the scripts file in the js folder:

/**
 * Upload Api
 */

$(function () {

    $("#add-images").on("click", function () {

        $("#file-input").trigger("click");

    });

    $("#file-input").on("change", function (e) {

        // check if the file api supported or not to display a message to the user to upgrade his browser
        if(window.File && window.FileReader && window.FileList && window.Blob) {

            handleFile(e);

        } else {
            alert('The File APIs are not fully supported in this browser.');
        }

    });

});

function handleFile(evt) {
    var files = evt.target.files; // FileList object

    // Loop through the FileList and render image files as thumbnails.
    for (var i = 0, f; f = files[i]; i++) {

        // Only process image files.
        if (!f.type.match('image.*')) {

            alert('invalid file type!!');

            continue;
        }

        var reader = new FileReader();

        // Closure to capture the file information.
        reader.onload = (function(theFile) {
            return function(e) {
                // Render thumbnail.

                var holder = '<div class="col-md-2">';

                holder += '<a href="#" onclick="$(this).parent().remove(); return false;"><i class="fa fa-remove"></i></a>';

                holder += ['<img class="thumbnail" width="200" height="150" src="', e.target.result,
                    '" title="', escape(theFile.name), '"/>'].join('');

                holder += '</div>';

                // append the holder to the div with Id #preview
                $("#preview .row").append(holder);

                // finally clone the original file input and append it every image so that
                // it will be available to be submitted to the server as multi file element
                var appendInput = $("#file-input").clone(true).removeAttr("id").attr("name", "photos[]");

                $("#preview .col-md-2:last-child").append(appendInput);
            };
        })(f);

        // Read in the image file as a data URL.
        reader.readAsDataURL(f);
    }
}

First when we click on the add images button we trigger click on the file input to show the file dialog

$("#add-images").on("click", function () {

        $("#file-input").trigger("click");

});

Then we listen to change event and checking if the File Api is supported or not to show a message to the user. then if File Api is supported we call function handleFile() which will preview the the selected file.

$("#file-input").on("change", function (e) {

        // check if the file api supported or not to display a message to the user to upgrade his browser
        if(window.File && window.FileReader && window.FileList && window.Blob) {

            handleFile(e);

        } else {
            alert('The File APIs are not fully supported in this browser.');
        }

});

handleFile() first will validate the file to be sure that its image file or not then we will create a new instance of the FileReader(). Then using the FileReader.onload we will process and display the thmbnails. again refer to my article here for more details about the File Api.

reader.onload = (function(theFile) {
            return function(e) {
                // Render thumbnail.

                var holder = '<div class="col-md-2">';

                holder += '<a href="#" onclick="$(this).parent().remove(); return false;"><i class="fa fa-remove"></i></a>';

                holder += ['<img class="thumbnail" width="200" height="150" src="', e.target.result,
                    '" title="', escape(theFile.name), '"/>'].join('');

                holder += '</div>';

                // append the holder to the div with Id #preview
                $("#preview .row").append(holder);

                // finally clone the original file input and append it every image so that
                // it will be available to be submitted to the server as multi file element
                var appendInput = $("#file-input").clone(true).removeAttr("id").attr("name", "photos[]");

                $("#preview .col-md-2:last-child").append(appendInput);
            };
})(f);

Next the upload code:

<?php

if(isset($_POST['submit']))
{
    $files = reformatFilesArray($_FILES);

    $uploadedFiles = upload($files);

    $data['uploadedFiles'] = $uploadedFiles;

    renderView($data);
}

function reformatFilesArray($files)
{
    $photos = [];

    foreach ($files['photos']['name'] as $key => $val)
    {
        $arr['name'] = $val;
        $arr['type'] = $files['photos']['type'][$key];
        $arr['tmp_name'] = $files['photos']['tmp_name'][$key];
        $arr['error'] = $files['photos']['error'][$key];
        $arr['size'] = $files['photos']['size'][$key];

        $photos[] = $arr;
    }

    return $photos;
}

function upload($files)
{
    $filesUploaded = [];

    try{

        foreach ($files as $k => $v)
        {

            $fileExtension = pathinfo($v['name'], PATHINFO_EXTENSION);

            // check for extension
            if(!in_array($fileExtension, ['jpg', 'jpeg', 'gif', 'png'])) {

                throw new Exception("Invalid file extension! supported extensions gif, jpg, png");

            }

            // check if is uploaded file
            if(!is_uploaded_file($v['tmp_name'])) {

                throw new Exception("unable to upload file");

            }

            // check if uploads directory is writable
            if(!is_writable("uploads")) {

                throw new Exception("please make sure that uploads directory is writable");

            }


            // if everything is ok then continue with uploading
            $filename = time() . "-" . md5(uniqid()) . "." . $fileExtension;

            $status = move_uploaded_file($v['tmp_name'], "uploads/" . $filename);

            if($status) {

                array_push($filesUploaded, $filename);

            }

        }

    }catch (Exception $ex){

        echo "Error while uploading: " . $ex->getMessage();

        exit(1);

    }

    return $filesUploaded;
}

function renderView($data)
{
    ob_start();

    extract($data);

    include 'success.php';

    $contents = ob_get_contents();

    ob_end_clean();

    echo $contents;
}

The code above is pretty easy first we check if the form was submitted then we call reformatFilesArray($_FILES) function to restructure the files array so that each file has it’s own array then we call upload() function and pass on the $files variable.  The upload function will loop through the files and do some checks like validating each file with valid extension and check if the file is_upload_file() then process the file. after successful upload we return the uploaded files and display a success message and the uploaded files in the success.php file.

success.php

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Multi upload success</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" crossorigin="anonymous">

    <link rel="stylesheet" href="css/style.css" type="text/css" />
</head>
<body id="wrapper">
    <div class="row">
        <?php

            echo '<h3>Uploaded files ('.sizeof($uploadedFiles).')</h3>';

            foreach ($uploadedFiles as $file)
            {
                echo '<div class="col-md-3">
                        <img src="uploads/'.$file.'" width="200" height="150" />
                      </div>';
            }

        ?>
    </div>


</body>
</html>

css/style.css

#wrapper{
    margin: 10px;
    margin-left: 27px;
}
#preview{
    margin-top: 10px;
}

Download source code

In this tutorial you learned how to build upload form and how to use the File Api to read file data and display thumbnails actually it’s a greet addition in the Html5 also how to validate file extensions to display the right files.

0 0 vote
Article Rating
Share this: