163

Ajax Image Upload and Resize with jQuery and PHP

You may find plenty of great image uploader scripts on the net, but they are also complicated to configure and to implement without the help of professionals, especially if you are novice one. Those uploader(s) come with additional functions which you may not even need, so sometimes your best bet is to code your own image uploader script, which will serve the purpose and keep things simple.

5.2.0+1.10.2+

Today we are going to create an Ajax based image uploader, which means the image file will be uploaded to server using Ajax request, without reloading the page. 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 re-sized image and square thumbnail out of the original file. The examples you’ll find here are pretty basic and easy to understand.

Ajax Image Uploader

HTML Image Upload Form

Our upload form contains a file input field, submit button, a loading image and <div> element to output any messages or errors from server. Loading image should only be displayed when upload process starts, otherwise it should remain hidden from users. I have also created a CSS file to make this form little stylish, which you’ll find in the sample file.

 
1
2
3
4
5
6
<form action="process.php" method="post" enctype="multipart/form-data" id="upload_form">
<input name="image_file" type="file" required="true" />
<input type="submit" value="Upload" id="submit-btn" />
<img src="images/ajax-loader.gif" id="loading-img" style="display:none;" alt="Please Wait"/>
</form>
<div id="output"></div>

jQuery

This tutorial uses jQuery Form plugin to make things easier, its a great plugin and allows us to submit forms using Ajax, without having to write additional code. It also supports numerous options that can easily adjust the behavior of the form. We just have to include this plugin in our form page and it takes care of everything. Have a look at the code below, see how simple it is to Ajax submit our form data using this form plugin? the amount of code required for jQuery Ajax is reduced to just $(this).ajaxSubmit(options); . We can now stop worrying about errors and start focusing on other areas that need attention.

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script type="text/javascript" src="js/jquery.form.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
    var options = {
            target:   '#output',   // target element(s) to be updated with server response
            beforeSubmit:  beforeSubmit,  // pre-submit callback
            resetForm: true        // reset the form after successful submit
        };
       
     $('#MyUploadForm').submit(function() {
            $(this).ajaxSubmit(options);  //Ajax Submit form           
            // return false to prevent standard browser submit and page navigation
            return false;
        });
});</script>

Checking file size/type with HTML5 File API

Our form is ready to upload the image, but there’s one more thing we need to do with our image upload form. Thanks to HTML5 for introducing new File API, we can now check file size and type before even uploading it to the server. Earlier things like these weren’t simple to achieve, because old browsers do not support File API, and alternative methods like Java or flash uploader were used, and those came with whole different baggage.

Have a look at code below, it simply checks empty text fields, file size and allowed file type using HTML5 File API support, in-case client is using old browsers such as internet explorer 6, it just outputs error asking to upgrade the browser, which I think is a good thing to do!

 
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
function before_submit(formData, jqForm, options){
var proceed = true;
var error = [];
   
    /* validation --iterate though each input field  
    if you add extra text or email fields just add "required=true" attribute for validation. */

    $(formData).each(function(){
   
        //check any empty required file input
        if(this.type == "file" && this.required == true && !$.trim(this.value)){ //check empty file fields if available
            error.push( this.name + " is empty!");
            proceed = false;
        }
       
        //check any empty required text input
        if(this.type == "text" && this.required == true && !$.trim(this.value)){ //check empty text fields if available
            error.push( this.name + " is empty!");
            proceed = false;
        }
       
        //check any invalid email field
        var email_reg = /^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/;
        if(this.type == "email" && !email_reg.test($.trim(this.value))){
            error.push( this.name + " contains invalid email!");
            proceed = false;          
        }

        //check invalid file types and maximum size of a file
        if(this.type == "file"){
            if(window.File && window.FileReader && window.FileList && window.Blob){
                if(this.value !== ""){
                    if(allowed_file_types.indexOf(this.value.type) === -1){
                        error.push( "<b>"+ this.value.type + "</b> is unsupported file type!");
                        proceed = false;
                    }
       
                    //allowed file size. (1 MB = 1048576)
                    if(this.value.size > max_file_size){
                        error.push( "<b>"+ bytes_to_size(this.value.size) + "</b> is too big! Allowed size is " + bytes_to_size(max_file_size));
                        proceed = false;
                    }
                }
            }else{
                error.push( "Please upgrade your browser, because your current browser lacks some new features we need!");
                proceed = false;
            }
        }
    });
   
    $(error).each(function(i){ //output any error to element
        $('#output').html('<div class="error">'+error[i]+"</div>");
    });
   
    if(!proceed){
        return false;
    }
}

We just need to attach above function to form plugin beforeSubmit callback, this function will then be invoked before the form is submitted, if image file size is too big or file type is not correct, the function will return false and then the form will not be submitted.

You can add additional text fields to your form and add required=”true” attribute if you want script to check for empty fields, this way we can avoid server side validation.

Processing Image

The backbone of this uploader is this PHP file, this is where uploaded image files are resized and then outputs are sent back to main page as Ajax response. In PHP script there are mainly two functions resize_image() and gen_thumbnail(). First one resize_image() will proportionally resize image depending on the original size, and the second one gen_thumbnail() will generate thumbnails by cropping images to exact size.

 
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
<?php
############ Configuration ##############
$img_info["image_max_size"]                 = 500; //Maximum image size (height and width)
$img_info["thumbnail_size"]                 = 150; //Thumbnails will be cropped and resized to 200x200 pixels
$img_info["thumbnail_prefix"]               = "thumb_"; //thumb Prefix
$img_info["destination_folder"]             = 'home/Websites/ajax-img-upload/ajax-image-upload/uploads/'; //Image directory ends with / (slash)
$img_info["thumbnail_destination_folder"]   = 'home/Websites/ajax-img-upload/ajax-image-upload/uploads/thumbs/'; //Thumbnail directory ends with / (slash)
$img_info["quality"]                        = 90; //jpeg quality
$img_info["random_file_name"]               = true; //randomize each file name
##########################################


//Accept HTTP POST comming as Ajax request
if(isset($_POST) && isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'){

    //Check empty file field
    if(!isset($_FILES['image_file']) || !is_uploaded_file($_FILES['image_file']['tmp_name'])){
       die('Image file is Missing!');
    }

    $img_info["image_data"] = $_FILES['image_file']; //file input  
    $img_info["unique_id"]  = uniqid(); //unique id for random filename

    //Check destination dir
    if(!file_exists($img_info["destination_folder"])){
        die( $img_info["destination_folder"]. " - (Folder doesn't exist!)");
    }

    //Check thumbnail destination dir
    if(!file_exists($img_info["thumbnail_destination_folder"])){
        die( $img_info["thumbnail_destination_folder"]. " - (Folder doesn't exist!)");
    }

    //Get image size info from a valid image file  
    $im_info = getimagesize($img_info["image_data"]["tmp_name"]);
    if($im_info){
        $img_info["image_width"]    = $im_info[0]; //image width
        $img_info["image_height"]   = $im_info[1]; //image height
        $img_info["image_type"]     = $im_info['mime']; //image type
    }else{
        die("Make sure image file is valid!");
    }

    $img_info["img_res"] = get_image_resource($img_info);
   
    //Resize image file
    if($img_info["img_res"]){
        $resize_image = resize_image($img_info); //call image resize function
        $generate_thumb = gen_thumbnail($img_info); //call thumbnail generator function

        if($resize_image && $generate_thumb){
            echo "<img src=\"uploads/$resize_image\"><br />";
            echo "<img src=\"uploads/thumbs/$generate_thumb\">";
        }
    }else{
        die("Error creating image resource!");
    }
}
#####  Function to proportionally resize images #####
function resize_image($img_info){
    if($img_info["image_width"] <= 0 || $img_info["image_height"] <= 0){
        return false; //return false if nothing to resize
    }

    //Path for saving resized images
    if($img_info["random_file_name"]){
        $new_image_name = $img_info["unique_id"] . get_extention($img_info);
    }else{
        $new_image_name = $img_info["image_data"]["name"];
    }

    $img_info["save_dir"] = $img_info["destination_folder"] . $new_image_name;

    //Do not resize if image is smaller than max size
    if($img_info["image_width"] <= $img_info["image_max_size"] && $img_info["image_height"] <= $img_info["image_max_size"]){
       if(save_image($img_info)){
           return $new_image_name;
       }
    }

    //Construct a proportional size of new image
    $image_scale    = min($img_info["image_max_size"]/$img_info["image_width"], $img_info["image_max_size"]/$img_info["image_height"]);
    $new_width      = ceil($image_scale * $img_info["image_width"]);
    $new_height     = ceil($image_scale * $img_info["image_height"]);
   
    //Create a new true color image
    $img_info["canvas"]  = imagecreatetruecolor($new_width, $new_height);
 
    //Copy and resize part of an image with resampling
    if(imagecopyresampled($img_info["canvas"], $img_info["img_res"], 0, 0, 0, 0, $new_width, $new_height, $img_info["image_width"], $img_info["image_height"])){
       if(save_image($img_info)){
           return $new_image_name;
       }
    }
}


##### Function to create thumbnails! images will be cropped and exact size ######
function gen_thumbnail($img_info){
    if($img_info["image_width"] <= 0 || $img_info["image_height"] <= 0){
        return false; //return false if nothing to resize
    }
 
    //Path for saving resized images
    if($img_info["random_file_name"]){
        $new_image_name = $img_info["thumbnail_prefix"].$img_info["unique_id"] . get_extention($img_info);
    }else{
        $new_image_name = $img_info["thumbnail_prefix"] . $img_info["image_data"]["name"];
    }
   
    $img_info["save_dir"] = $img_info["thumbnail_destination_folder"] . $new_image_name;

   //Offsets
    if( $img_info["image_width"] > $img_info["image_height"]){
        $y_offset = 0;
        $x_offset = ($img_info["image_width"] - $img_info["image_height"]) / 2;
        $s_size     = $img_info["image_width"] - ($x_offset * 2);
    }else{
        $x_offset = 0;
        $y_offset = ($img_info["image_height"] - $img_info["image_width"]) / 2;
        $s_size = $img_info["image_height"] - ($y_offset * 2);
    }
   
    //Create a new true color image
    $img_info["canvas"] = imagecreatetruecolor($img_info["thumbnail_size"], $img_info["thumbnail_size"]);
   
    //Copy and resize part of an image with resampling
    if(imagecopyresampled($img_info["canvas"], $img_info["img_res"], 0, 0, $x_offset, $y_offset, $img_info["thumbnail_size"], $img_info["thumbnail_size"], $s_size, $s_size)){
       if(save_image($img_info)){
           return $new_image_name;
       }
    }
}

##### Saves images to destination directory ######
function save_image($img_info){
    switch(strtolower($img_info["image_type"])){
        case 'image/png':
            imagepng($img_info["canvas"], $img_info["save_dir"]); //save png file
            break;
       
        case 'image/gif':
            imagegif($img_info["canvas"], $img_info["save_dir"]); //save gif file
            break;
                   
        case 'image/jpeg': case 'image/pjpeg':
            imagejpeg($img_info["canvas"], $img_info["save_dir"], $img_info["quality"]);  //save jpeg file
            break;

        default:
            return false;
    }
   
    imagedestroy($img_info["canvas"]); //free-up memory
    return true;
}

##### Create a new image resource from file #####
function get_image_resource($img_info){
   
    switch($img_info["image_type"]){
        case 'image/png':
            return imagecreatefrompng($img_info["image_data"]["tmp_name"]);
        case 'image/gif':
           return imagecreatefromgif($img_info["image_data"]["tmp_name"]);    
        case 'image/jpeg':
        case 'image/pjpeg':
            return imagecreatefromjpeg($img_info["image_data"]["tmp_name"]);
        default:
            return false;
        }
}

##### Returns file extension from given image type ######
function get_extention($img_info){
   switch($img_info["image_type"]){
       case 'image/gif':
            return ".gif";
       case 'image/jpeg':
       case 'image/pjpeg':
            return ".jpg";
       case 'image/png':
            return ".png";
   }
}

That’s all you need to create a Ajax based image uploader, which will resize and create thumbnail for you. The downloadable file contains PHP files, css, jQuery form plugin and may be some images. Hope it will help you create interesting upload form for your website and don’t forget to checkout my other similar articles here :
Ajax Image Upload and Resize with ImageMagick, Ajax Image Upload/Resize (Progressbar) and Ajax File Upload (Progressbar) Good luck!

Download Demo

Related Articles:

163 Comments Add Comment

  1. 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!

    Add Reply
  2. 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).

    Add Reply
  3. 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.

    Add Reply
  4. 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!

    Add Reply
  5. 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

    Add Reply
  6. 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

    Add Reply
  7. 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

    Add Reply
  8. 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

    Add Reply
  9. 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.

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

    Add Reply
  11. 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 :/

    Add Reply
  12. 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.

    Add Reply

 

Use Gravatar for Comment Pic | Start a topic for crucial discussion.


 Notify me of followup comments via e-mail. You can also subscribe without commenting.

Go Top ↑