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+
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.HTML
- 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:JQUERY
- 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 :JQUERY
- 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;
}
}
})
JQUERY
- 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.PHP
- 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';
}
}
Next :Add Progressbar to your Upload form.Ajax Image Upload and Resize with ImageMagick and Ajax File Upload (Progressbar) Good luck!