Ajax Image Upload and Resize with jQuery and PHP

There are plenty of great image uploader scripts on the net, but you may find them complicated to implement, especially if you are novice one. Those uploader(s) come with additional scripts and files which you may not even need, so sometimes your best bet is to code your own image upload and resize script, which will serve the purpose and keep things simple.

5.2.0+ 1.6.1+

Today we are going to create an Ajax based image upload and resize script, which means the image file will be uploaded to server using Ajax request. We will also be using HTML5 File API to check file size and image type before uploading, then with PHP support we will create two images, a resized version and a thumbnail from original image file. The examples you’ll find here are pretty easy to understand.

Ajax Image Uploader

HTML Image Upload Form

In HTML form, we need one file input field as shown in code below, notice the multiple=”multiple” attribute in input field, it let’s us select multiple files, you may remove it if you only accept single file.

1
2
3
4
5
6
7
<div class="form-wrap">
    <form action="process.php" method="post" enctype="multipart/form-data" id="upload_form">
        <input name="__files[]" type="file" multiple="multiple" />
        <input name="__submit__" type="submit" value="Upload"/>
    </form>
    <div id="output"><!-- error or success results --></div>
</div>

jQuery

Thanks to HTML5 for new File API, we can now do things like checking file size, type etc. But we also want to make sure client browser supports this feature. Most modern browsers comes with File API support, but for old browsers (like IE8), we can display a nice message like so:

1
2
3
4
5
$("#upload_form").on( "submit", function(event) {//on form submit
    if(!window.File && window.FileReader && window.FileList && window.Blob){ //if browser doesn't supports File API
        alert("Your browser does not support new File API! Please upgrade.");
    }
})

Checking file size/type with HTML5 File API

Once we know the browser supports File API, we can start taking things further. Before we send our files directly to server, we want to make sure, file size is not too big and it is an image file. We also want to limit number of files user can upload. Here’s the example jQuery code :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
$("#upload_form").on( "submit", function(event) {//on form submit
    var proceed = true; //set proceed flag
    if(!window.File && window.FileReader && window.FileList && window.Blob){ //if browser doesn't supports File API
        alert("Your browser does not support new File API! Please upgrade.");
        proceed = false;
    }else{

        //Limit Files Selection
        var total_selected_files = this.elements['__files[]'].files.length; //number of files selected
        if(total_selected_files > 3){ //limit number of files allowed to 3
            alert( "You have selected "+total_selected_files+" file(s), 3 is maximum!"); //notify user
            proceed = false;
        }
       
        //iterate files in file input field
        var total_files_size = 0;
        $(this.elements['__files[]'].files).each(function(i, ifile){
            if(ifile.value !== ""){ //continue only if file(s) are selected
                if(['image/png', 'image/gif', 'image/jpeg', 'image/pjpeg'].indexOf(ifile.type) === -1){ //check unsupported file
                    alert( "<b>"+ ifile.name + "</b> is unsupported file type!");
                    proceed = false;
                }
                total_files_size = total_files_size + ifile.size; //add file size to total size
            }
        });
       
        //if total file size is greater than max file size
        if(total_files_size > 1048576){
            alert( "Make sure total file size is less than 1 MB!");
            proceed = false;
        }

    }
})

Now let’s put things together, this time we also use jQuery Ajax. As you can see in code below, we check file size, type and limit the selection of multiple files, then if everything looks good, we create FormData object new FormData() which will be sent to server using jQuery Ajax.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
//configuration
var max_file_size           = 2048576; //allowed file size. (1 MB = 1048576)
var allowed_file_types      = ['image/png', 'image/gif', 'image/jpeg', 'image/pjpeg']; //allowed file types
var result_output           = '#output'; //ID of an element for response output
var my_form_id              = '#upload_form'; //ID of an element for response output
var total_files_allowed     = 3; //Number files allowed to upload

//on form submit
$(my_form_id).on( "submit", function(event) {
    event.preventDefault();
    var proceed = true; //set proceed flag
    var error = []; //errors
    var total_files_size = 0;
   
    if(!window.File && window.FileReader && window.FileList && window.Blob){ //if browser doesn't supports File API
        error.push("Your browser does not support new File API! Please upgrade."); //push error text
    }else{
        var total_selected_files = this.elements['__files[]'].files.length; //number of files
       
        //limit number of files allowed
        if(total_selected_files > total_files_allowed){
            error.push( "You have selected "+total_selected_files+" file(s), " + total_files_allowed +" is maximum!"); //push error text
            proceed = false; //set proceed flag to false
        }
         //iterate files in file input field
        $(this.elements['__files[]'].files).each(function(i, ifile){
            if(ifile.value !== ""){ //continue only if file(s) are selected
                if(allowed_file_types.indexOf(ifile.type) === -1){ //check unsupported file
                    error.push( "<b>"+ ifile.name + "</b> is unsupported file type!"); //push error text
                    proceed = false; //set proceed flag to false
                }

                total_files_size = total_files_size + ifile.size; //add file size to total size
            }
        });
       
        //if total file size is greater than max file size
        if(total_files_size > max_file_size){
            error.push( "You have "+total_selected_files+" file(s) with total size "+total_files_size+", Allowed size is " + max_file_size +", Try smaller file!"); //push error text
            proceed = false; //set proceed flag to false
        }
       
        var submit_btn  = $(this).find("input[type=submit]"); //form submit button 
       
        //if everything looks good, proceed with jQuery Ajax
        if(proceed){
            submit_btn.val("Please Wait...").prop( "disabled", true); //disable submit button
            var form_data = new FormData(this); //Creates new FormData object
            var post_url = $(this).attr("action"); //get action URL of form
           
            //jQuery Ajax to Post form data
            $.ajax({
                url : post_url,
                type: "POST",
                data : form_data,
                contentType: false,
                cache: false,
                processData:false,
                mimeType:"multipart/form-data"
            }).done(function(res){ //
                $(my_form_id)[0].reset(); //reset form
                $(result_output).html(res); //output response from server
                submit_btn.val("Upload").prop( "disabled", false); //enable submit button once ajax is done
            });
        }
    }
   
    $(result_output).html(""); //reset output
    $(error).each(function(i){ //output any error to output element
        $(result_output).append('<div class="error">'+error[i]+"</div>");
    });
       
});

Processing Image

The backbone of this uploader is this PHP file, this is where uploaded image files are resized and saved, then outputted back to browser. Below is the working PHP code which can handle multiple image files. You can go through the it and understand how this code really works. But if you still find it bit complicated, don’t worry I’ve converted following code in a separate PHP class in download section, which you can include in your project, play with it or even contribute if you can improve the code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
<?php
############ Configuration ##############
$config["image_max_size"]               = 500; //Maximum image size (height and width)
$config["thumbnail_size"]               = 200; //Thumbnails will be cropped to 200x200 pixels
$config["thumbnail_prefix"]             = "thumb_"; //Normal thumb Prefix
$config["destination_folder"]           = 'home/Website/ajax-image-upload/uploads/'; //upload directory ends with / (slash)
$config["thumbnail_destination_folder"] = 'home/Website/ajax-image-upload/uploads/'; //upload directory ends with / (slash)
$config["upload_url"]                   = "http://website/ajax-image-upload/uploads/";
$config["quality"]                      = 90; //jpeg quality


if(!isset($_SERVER['HTTP_X_REQUESTED_WITH'])) {
    exit;  //try detect AJAX request, simply exist if no Ajax
}

if(!isset($_FILES['__files']) || !is_uploaded_file($_FILES['__files']['tmp_name'][0])){
   die('Image file is Missing!');
}

//count total files in array
$file_count = count($_FILES["__files"]["name"]);

if($file_count > 0){ //there are more than one file? no problem let's handle multiple files

    for ($x = 0; $x < $file_count; $x++){   //Loop through each uploaded file
   
        //if there's file error, display it
        if ($_FILES["__files"]['error'][$x] > 0) {
            print get_upload_error($x);
            exit;
        }

        //Get image info from a valid image file
        $im_info = getimagesize($_FILES["__files"]["tmp_name"][$x]);
        if($im_info){
            $im["image_width"]  = $im_info[0]; //image width
            $im["image_height"] = $im_info[1]; //image height
            $im["image_type"]   = $im_info['mime']; //image type
        }else{
            die("Make sure image <b>".$_FILES["__files"]["name"][$x]."</b> is valid image file!");
        }
       
        //create image resource using Image type and set the file extension
        switch($im["image_type"]){
            case 'image/png':
                $img_res =  imagecreatefrompng($_FILES["__files"]["tmp_name"][$x]);
                $file_extension = ".png";
                break;
            case 'image/gif':
               $img_res = imagecreatefromgif($_FILES["__files"]["tmp_name"][$x]);    
               $file_extension = ".gif";
               break;
            case 'image/jpeg':
            case 'image/pjpeg':
                $img_res = imagecreatefromjpeg($_FILES["__files"]["tmp_name"][$x]);
                $file_extension = ".jpg";
                break;
            default:
                $img_res = 0;
        }
       
        //set our file variables
        $unique_id =  uniqid(); //unique id for random filename
        $new_file_name = $unique_id . $file_extension;
        $destination_file_save = $config["destination_folder"] . $new_file_name; //file path to destination folder
        $destination_thumbnail_save = $config["thumbnail_destination_folder"] . $config["thumbnail_prefix"]. $new_file_name; //file path to destination thumb folder

        if($img_res){
            ###### resize Image ########
            //Construct a proportional size of new image
            $image_scale    = min($config["image_max_size"]/$im["image_width"], $config["image_max_size"]/$im["image_height"]);
            $new_width      = ceil($image_scale * $im["image_width"]);
            $new_height     = ceil($image_scale * $im["image_height"]);
   
            //Create a new true color image
            $canvas  = imagecreatetruecolor($new_width, $new_height);
            $resample = imagecopyresampled($canvas, $img_res, 0, 0, 0, 0, $new_width, $new_height, $im["image_width"], $im["image_height"]);
            if($resample){
                $save_image = save_image_file($im["image_type"], $canvas, $destination_file_save, $config["quality"]); //save image
                if($save_image){
                    print '<img src="'.$config["upload_url"] . $new_file_name. '" />'; //output image to browser
                }
            }
           
            if(is_resource($canvas)){
              imagedestroy($canvas);  //free any associated memory
            }

           
            ###### Generate Thumbnail ########
           
            //Offsets
            if( $im["image_width"] > $im["image_height"]){
                $y_offset = 0;
                $x_offset = ($im["image_width"] - $im["image_height"]) / 2;
                $s_size     = $im["image_width"] - ($x_offset * 2);
            }else{
                $x_offset = 0;
                $y_offset = ($im["image_height"] - $im["image_width"]) / 2;
                $s_size = $im["image_height"] - ($y_offset * 2);
            }
           
            //Create a new true color image
            $canvas = imagecreatetruecolor($config["thumbnail_size"], $config["thumbnail_size"]);
            $resample = imagecopyresampled($canvas, $img_res, 0, 0, $x_offset, $y_offset, $config["thumbnail_size"], $config["thumbnail_size"], $s_size, $s_size);
            if($resample){
                $save_image = save_image_file($im["image_type"], $canvas, $destination_thumbnail_save, $config["quality"] );
                if($save_image){
                    print '<img src="'.$config["upload_url"] . $config["thumbnail_prefix"]. $new_file_name. '" />';
                }
            }
           
            if(is_resource($canvas)){
              imagedestroy($canvas);  //free any associated memory
            }
           
           
        }
       
    }
}
 
 //funcion to save image file
function save_image_file($image_type, $canvas, $destination, $quality){
    switch(strtolower($image_type)){
        case 'image/png':
            return imagepng($canvas, $destination); //save png file
        case 'image/gif':
            return imagegif($canvas, $destination); //save gif file                
        case 'image/jpeg': case 'image/pjpeg':
            return imagejpeg($canvas, $destination, $quality);  //save jpeg file
        default:
            return false;
    }
}

function get_upload_error($err_no){
    switch($err_no){
        case 1 : return 'The uploaded file exceeds the upload_max_filesize directive in php.ini.';
        case 2 : return 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.';
        case 3 : return 'The uploaded file was only partially uploaded.';
        case 4 : return 'No file was uploaded.';
        case 5 : return 'Missing a temporary folder. Introduced in PHP 5.0.3';
        case 6 : return 'Failed to write file to disk. Introduced in PHP 5.1.0';
    }
}

That’s all you need to create an Ajax based image upload and resize script. The downloadable file contains sample script. Hope it will help you create interesting upload form for your website.

Next :Add Progressbar to your Upload form.

Ajax Image Upload and Resize with ImageMagick and Ajax File Upload (Progressbar) Good luck!

Download Demo

  1. this article Ajax Image Upload and Resize with jQuery and PHP is very useful for me. Thanks for have sharing this post :)

     Reply
  2. Helo,
    I use does not work on IE11, Windown10 ( is unsupported file type! ). Test demo online errors still occur.
    Other web browsers work fine.
    please check help.
    thank you.

     Reply
  3. Hello,
    i’m looking to extract the link of thumbail in “process.php” for update my sql
    help me thanks

     Reply
  4. HI,
    Great script! I must of missed something – I don’t see the EXIF code that you reference? I would like to maintain the exif data upon resizing if possible.

    Thanks!

     Reply
  5. Kindly provide file upload in php with max file upload 300mb or more within .htacess file(Kindly am running application in live have to fix it soon).

     Reply
  6. How do I get the image URL and save it to Mysql?

     Reply
  7. Umm.. how to turn off the thumbnail creation? I like the resize part and all but thumbnails are pretty useless for my needs and they eat up my server’s disc space. Something like
    $conf[‘create_thumbnail’] = false;
    would be nice to have.

     Reply
  8. Hello,

    very useful code! I have one query in that, Will it work for bmp image extension? If yes, How?

     Reply
  9. Hey – great code! However, maybe you can help me extend it. I’m looking to;

    1. Add the option to upload an IMAGE via its URL, i.e. img->src = http://www.mysite.com/myimage.jpg
    2. Output multiple image sizes, i.e thumbs of 300×300, 150×150 & 90×90.
    3. Crop rectangular billboard images of 2:1 ratios from the center out to the smallest width or height, i.e. always output a size of 640×320, 300×150 & 180×90 regardless of the original image ratio.

    Any help would be MUCH APPRECIATED!!!

    Thank you!

     Reply
  10. I’ve tried posting to database. However, it won’t work.
    I can display the thumb, but using the exact same variable for DB isn’t working.
    Check out my question on stackoverflow:
    http://stackoverflow.com/questions/30539060/img-dir-cant-be-stored-in-db-but-viewed-from-the-same-variables-used-in-query

     Reply
  11. Thanks, this saved me a fair bit of time. It is well commented and works like it should. :-)

     Reply
  12. Hey friend, can i limit iamge type upload?

     Reply
  13. how can I auto upload images, instead of click upload button

     Reply
  14. hey thanks for sharing,
    keep up the good post!

     Reply
  15. When I set a bigger size

    1
    2
    3
    4
    5
    if(fsize>10485760)
    {
        $("#output").html(""+bytesToSize(fsize) +" Too big Image file! Please reduce the size of your photo using an image editor.");
        return false
    }

    then it can’t upload in the browser: ‘Image file is Missing!’

    1
    2
    3
    if(!isset($_FILES['image_file']) || !is_uploaded_file($_FILES['image_file']['tmp_name'])){
        die('Image file is Missing!'); // output error when above checks fail.
    }

    How can I upload the bigger file?
    Thanks

     Reply
  16. Hi again
    Testing your file “processupload.php”
    at line
    imagejpeg($source, $destination, $quality); return true; //save jpeg file
    it seems that there are no variables $source end $destination are not present
    Thanks, regards

     Reply
  17. Hi
    thank you for your wonderful program!!!
    I get error:
    Warning: imagejpeg() [function.imagejpeg]: Unable to open ‘http://overstudi.com/public/uploads/bebe6_581015110.jpg’ for writing: Invalid argument in D:\Inetpub\webs\overstudicom\Bassanella\processupload.php on line 144

    why??
    please can you help me
    thank you, best regards

     Reply
  18. hi
    thanks for your codes
    I want to have two Image size 940*400 and 250*200 after upload without any crop and by just resize!!! In your code, in square mode, images croped but I wanted just resize

     Reply
  19. I get the downloaded to work perfectly but the browser always gets submitted to processupload.php when I put the code in my own page.
    html:

    The “return false;” for $(‘#MyUploadForm’).submit(function () doesnt seem to work for me.
    Can you please advice? thx.

     Reply
  20. Nice work ;)
    I suggest small correction in processupload.php [#71,#73]
    echo ‘<img src="uploads/'.
    to
    echo '<img src='",$destination_folder, …

     Reply
  21. I would like to know how i could save the new file name to the database as i’ve tried saving $new_file_name to the database but its telling me the variable is undefined :/

     Reply
  22. This code is really a good.
    Can it be possible that you upload image using link.

     Reply
  23. Thanks for your tutorial.

     Reply
  24. Thanks for the problem solved. Just had to tweak a few items to make it my own but your solution is easy to understand, well commented, and easy to use.

     Reply
  25. thanks for upload this scrip its great .

     Reply
  26. hey thanx for the good work you are doing, you have changed the world and made it a better place by teaching and assisting us. long live

     Reply
  27. Can it be possible that you add so you can upload video also

     Reply
  28. Barrak Hussein Bombama

    ugly + progress bar get out of the frame

     Reply
  29. I really like this uploader, but when used on a live site, it runs into this “FakePath” issue. http://martinivanov.net/2009/06/09/the-mystery-of-cfakepath-unveiled/

    Please advise if you have a workaround for this problem cause the code becomes pretty useless if I can’t use it on a live website.

     Reply
Message Type : Question Comment ?
  • Question : Can include code, jsFiddle, codePen etc using Markdown Syntax.
  • Comment : Short comments and questions.

Ask a QuestionIf you have issue related to this topic, Please ask here.
socket_recv() throws a warning when clien quits
calvicius asked 3 days ago
10 views0 answers0 votes
Integrated with chosen multiselect
sulung asked 5 days ago
8 views0 answers0 votes
Error
Barrur Rhozi asked 6 days ago
14 views0 answers0 votes
On Focus Add/Remove Input Fields Dynamically (jQuery)
Saran answered 4 days ago
24 views1 answers0 votes
Adding textboxes horizontally
Saran commented 4 days ago
43 views0 answers0 votes
Error: err_connection_timed_out
Gabriel asked 1 week ago
15 views0 answers0 votes
decrease speed of processbar
priyal asked 1 week ago
14 views0 answers0 votes
How to use rss directory ?
Saran answered 2 weeks ago
27 views1 answers0 votes