HTML5 upload tutorial: today we will develop a great HTML5 file upload form with progress bar and preview (at client-side). We have already gave you jQuery based solution, but today’s application don’t require jQuery at all. All made in pure HTML5 Javascript. I’m going to use FileReader (html5) to implement live preview (without uploading to server), and, going to use XMLHttpRequest to send data to server.
Here are our demo and downloadable package:
[sociallocker]
[/sociallocker]
Ok, download the sources and lets begin !
Step 1. HTML
At this page you can see out form for upload images
index.html
03 |
< meta charset = "utf-8" /> |
04 |
< title >Pure HTML5 file upload | Script Tutorials</ title > |
05 |
< link href = "css/main.css" rel = "stylesheet" type = "text/css" /> |
06 |
< script src = "js/script.js" ></ script > |
10 |
< h2 >Pure HTML5 file upload</ h2 > |
13 |
< div class = "container" > |
14 |
< div class = "contr" >< h2 >You can select the file (image) and click Upload button</ h2 ></ div > |
15 |
< div class = "upload_form_cont" > |
16 |
< form id = "upload_form" enctype = "multipart/form-data" method = "post" action = "upload.php" > |
18 |
< div >< label for = "image_file" >Please select image file</ label ></ div > |
19 |
< div >< input type = "file" name = "image_file" id = "image_file" onchange = "fileSelected();" /></ div > |
22 |
< input type = "button" value = "Upload" onclick = "startUploading()" /> |
25 |
< div id = "filename" ></ div > |
26 |
< div id = "filesize" ></ div > |
27 |
< div id = "filetype" ></ div > |
28 |
< div id = "filedim" ></ div > |
30 |
< div id = "error" >You should select valid image files only!</ div > |
31 |
< div id = "error2" >An error occurred while uploading the file</ div > |
32 |
< div id = "abort" >The upload has been canceled by the user or the browser dropped the connection</ div > |
33 |
< div id = "warnsize" >Your file is very big. We can't accept it. Please select more small file</ div > |
34 |
< div id = "progress_info" > |
35 |
< div id = "progress" ></ div > |
36 |
< div id = "progress_percent" > </ div > |
37 |
< div class = "clear_both" ></ div > |
39 |
< div id = "speed" > </ div > |
40 |
< div id = "remaining" > </ div > |
41 |
< div id = "b_transfered" > </ div > |
42 |
< div class = "clear_both" ></ div > |
44 |
< div id = "upload_response" ></ div > |
Step 2. CSS
css/main.css
I have selected all necessary styles for our html5 upload form
css/main.css
002 |
background : -moz-linear-gradient( #ffffff , #f2f2f2 ); |
003 |
background : -ms-linear-gradient( #ffffff , #f2f2f2 ); |
004 |
background : -webkit-gradient(linear, left top , left bottom , color-stop( 0% , #ffffff ), color-stop( 100% , #f2f2f2 )); |
005 |
background : -webkit-linear-gradient( #ffffff , #f2f2f2 ); |
006 |
background : -o-linear-gradient( #ffffff , #f2f2f2 ); |
007 |
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr= '#ffffff' , endColorstr= '#f2f2f2' ); |
008 |
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f2f2f2')" ; |
009 |
background : linear-gradient( #ffffff , #f2f2f2 ); |
019 |
background-color : #fff ; |
040 |
-moz-border-radius: 10px ; |
041 |
-ms-border-radius: 10px ; |
042 |
-o-border-radius: 10px ; |
043 |
-webkit-border-radius: 10px ; |
044 |
border : 1px solid #ccc ; |
049 |
background : -moz-linear-gradient( #ffffff , #dfdfdf ); |
050 |
background : -ms-linear-gradient( #ffffff , #dfdfdf ); |
051 |
background : -webkit-gradient(linear, left top , left bottom , color-stop( 0% , #ffffff ), color-stop( 100% , #dfdfdf )); |
052 |
background : -webkit-linear-gradient( #ffffff , #dfdfdf ); |
053 |
background : -o-linear-gradient( #ffffff , #dfdfdf ); |
054 |
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr= '#ffffff' , endColorstr= '#dfdfdf' ); |
055 |
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dfdfdf')" ; |
056 |
background : linear-gradient( #ffffff , #dfdfdf ); |
064 |
#fileinfo,#error,#error 2 ,#abort,#warnsize { |
072 |
border : 1px solid #ccc ; |
077 |
-moz-border-radius: 10px ; |
078 |
-ms-border-radius: 10px ; |
079 |
-o-border-radius: 10px ; |
080 |
-webkit-border-radius: 10px ; |
081 |
background : -moz-linear-gradient( #66cc00 , #4b9500 ); |
082 |
background : -ms-linear-gradient( #66cc00 , #4b9500 ); |
083 |
background : -webkit-gradient(linear, left top , left bottom , color-stop( 0% , #66cc00 ), color-stop( 100% , #4b9500 )); |
084 |
background : -webkit-linear-gradient( #66cc00 , #4b9500 ); |
085 |
background : -o-linear-gradient( #66cc00 , #4b9500 ); |
086 |
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr= '#66cc00' , endColorstr= '#4b9500' ); |
087 |
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#66cc00', endColorstr='#4b9500')" ; |
088 |
background : linear-gradient( #66cc00 , #4b9500 ); |
098 |
border : 1px solid #ccc ; |
100 |
-moz-border-radius: 10px ; |
101 |
-ms-border-radius: 10px ; |
102 |
-o-border-radius: 10px ; |
103 |
-webkit-border-radius: 10px ; |
104 |
box-shadow: 0 0 5px #ccc ; |
105 |
background : -moz-linear-gradient( #bbb , #eee ); |
106 |
background : -ms-linear-gradient( #bbb , #eee ); |
107 |
background : -webkit-gradient(linear, left top , left bottom , color-stop( 0% , #bbb ), color-stop( 100% , #eee )); |
108 |
background : -webkit-linear-gradient( #bbb , #eee ); |
109 |
background : -o-linear-gradient( #bbb , #eee ); |
110 |
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr= '#bbb' , endColorstr= '#eee' ); |
111 |
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#bbb', endColorstr='#eee')" ; |
112 |
background : linear-gradient( #bbb , #eee ); |
Step 3. HTML5 JS
js/script.js
002 |
var iBytesUploaded = 0; |
004 |
var iPreviousBytesLoaded = 0; |
005 |
var iMaxFilesize = 1048576; |
007 |
var sResultFileSize = '' ; |
008 |
function secondsToTime(secs) { |
009 |
var hr = Math.floor(secs / 3600); |
010 |
var min = Math.floor((secs - (hr * 3600))/60); |
011 |
var sec = Math.floor(secs - (hr * 3600) - (min * 60)); |
012 |
if (hr < 10) {hr = "0" + hr; } |
013 |
if (min < 10) {min = "0" + min;} |
014 |
if (sec < 10) {sec = "0" + sec;} |
016 |
return hr + ':' + min + ':' + sec; |
018 |
function bytesToSize(bytes) { |
019 |
var sizes = [ 'Bytes' , 'KB' , 'MB' ]; |
020 |
if (bytes == 0) return 'n/a' ; |
021 |
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); |
022 |
return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i]; |
024 |
function fileSelected() { |
026 |
document.getElementById( 'upload_response' ).style.display = 'none' ; |
027 |
document.getElementById( 'error' ).style.display = 'none' ; |
028 |
document.getElementById( 'error2' ).style.display = 'none' ; |
029 |
document.getElementById( 'abort' ).style.display = 'none' ; |
030 |
document.getElementById( 'warnsize' ).style.display = 'none' ; |
032 |
var oFile = document.getElementById( 'image_file' ).files[0]; |
034 |
var rFilter = /^(image\/bmp|image\/gif|image\/jpeg|image\/png|image\/tiff)$/i; |
035 |
if (! rFilter.test(oFile.type)) { |
036 |
document.getElementById( 'error' ).style.display = 'block' ; |
040 |
if (oFile.size > iMaxFilesize) { |
041 |
document.getElementById( 'warnsize' ).style.display = 'block' ; |
045 |
var oImage = document.getElementById( 'preview' ); |
047 |
var oReader = new FileReader(); |
048 |
oReader.onload = function (e){ |
050 |
oImage.src = e.target.result; |
051 |
oImage.onload = function () { |
053 |
sResultFileSize = bytesToSize(oFile.size); |
054 |
document.getElementById( 'fileinfo' ).style.display = 'block' ; |
055 |
document.getElementById( 'filename' ).innerHTML = 'Name: ' + oFile.name; |
056 |
document.getElementById( 'filesize' ).innerHTML = 'Size: ' + sResultFileSize; |
057 |
document.getElementById( 'filetype' ).innerHTML = 'Type: ' + oFile.type; |
058 |
document.getElementById( 'filedim' ).innerHTML = 'Dimension: ' + oImage.naturalWidth + ' x ' + oImage.naturalHeight; |
062 |
oReader.readAsDataURL(oFile); |
064 |
function startUploading() { |
066 |
iPreviousBytesLoaded = 0; |
067 |
document.getElementById( 'upload_response' ).style.display = 'none' ; |
068 |
document.getElementById( 'error' ).style.display = 'none' ; |
069 |
document.getElementById( 'error2' ).style.display = 'none' ; |
070 |
document.getElementById( 'abort' ).style.display = 'none' ; |
071 |
document.getElementById( 'warnsize' ).style.display = 'none' ; |
072 |
document.getElementById( 'progress_percent' ).innerHTML = '' ; |
073 |
var oProgress = document.getElementById( 'progress' ); |
074 |
oProgress.style.display = 'block' ; |
075 |
oProgress.style.width = '0px' ; |
078 |
var vFD = new FormData(document.getElementById( 'upload_form' )); |
080 |
var oXHR = new XMLHttpRequest(); |
081 |
oXHR.upload.addEventListener( 'progress' , uploadProgress, false ); |
082 |
oXHR.addEventListener( 'load' , uploadFinish, false ); |
083 |
oXHR.addEventListener( 'error' , uploadError, false ); |
084 |
oXHR.addEventListener( 'abort' , uploadAbort, false ); |
085 |
oXHR.open( 'POST' , 'upload.php' ); |
088 |
oTimer = setInterval(doInnerUpdates, 300); |
090 |
function doInnerUpdates() { |
091 |
var iCB = iBytesUploaded; |
092 |
var iDiff = iCB - iPreviousBytesLoaded; |
096 |
iPreviousBytesLoaded = iCB; |
098 |
var iBytesRem = iBytesTotal - iPreviousBytesLoaded; |
099 |
var secondsRemaining = iBytesRem / iDiff; |
101 |
var iSpeed = iDiff.toString() + 'B/s' ; |
102 |
if (iDiff > 1024 * 1024) { |
103 |
iSpeed = (Math.round(iDiff * 100/(1024*1024))/100).toString() + 'MB/s' ; |
104 |
} else if (iDiff > 1024) { |
105 |
iSpeed = (Math.round(iDiff * 100/1024)/100).toString() + 'KB/s' ; |
107 |
document.getElementById( 'speed' ).innerHTML = iSpeed; |
108 |
document.getElementById( 'remaining' ).innerHTML = '| ' + secondsToTime(secondsRemaining); |
110 |
function uploadProgress(e) { |
111 |
if (e.lengthComputable) { |
112 |
iBytesUploaded = e.loaded; |
113 |
iBytesTotal = e.total; |
114 |
var iPercentComplete = Math.round(e.loaded * 100 / e.total); |
115 |
var iBytesTransfered = bytesToSize(iBytesUploaded); |
116 |
document.getElementById( 'progress_percent' ).innerHTML = iPercentComplete.toString() + '%' ; |
117 |
document.getElementById( 'progress' ).style.width = (iPercentComplete * 4).toString() + 'px' ; |
118 |
document.getElementById( 'b_transfered' ).innerHTML = iBytesTransfered; |
119 |
if (iPercentComplete == 100) { |
120 |
var oUploadResponse = document.getElementById( 'upload_response' ); |
121 |
oUploadResponse.innerHTML = '<h1>Please wait...processing</h1>' ; |
122 |
oUploadResponse.style.display = 'block' ; |
125 |
document.getElementById( 'progress' ).innerHTML = 'unable to compute' ; |
128 |
function uploadFinish(e) { |
129 |
var oUploadResponse = document.getElementById( 'upload_response' ); |
130 |
oUploadResponse.innerHTML = e.target.responseText; |
131 |
oUploadResponse.style.display = 'block' ; |
132 |
document.getElementById( 'progress_percent' ).innerHTML = '100%' ; |
133 |
document.getElementById( 'progress' ).style.width = '400px' ; |
134 |
document.getElementById( 'filesize' ).innerHTML = sResultFileSize; |
135 |
document.getElementById( 'remaining' ).innerHTML = '| 00:00:00' ; |
136 |
clearInterval(oTimer); |
138 |
function uploadError(e) { |
139 |
document.getElementById( 'error2' ).style.display = 'block' ; |
140 |
clearInterval(oTimer); |
142 |
function uploadAbort(e) { |
143 |
document.getElementById( 'abort' ).style.display = 'block' ; |
144 |
clearInterval(oTimer); |
Most of code is already commented. So I will hope that you will understand all this code. Anyway – how it working: when we select file – function ‘fileSelected’ is executing. We filter all unnecessary formats (allow to upload next formats: bmp, gif, jpg, png, tif), in case of huge file – we will draw warning message. Then, through FileReader::readAsDataURL we will draw live preview of selected file. Plus, we will display another information about image: its name, size, type, and dimensions. Process of uploading is a little complicated. But generally, we have to prepare XMLHttpRequest object, add event listeners to next events: progress, load, error and abort. And after – post form data (I have used FormData class) to our ‘upload.php’ receiver.
Step 4. PHP
upload.php
02 |
function bytesToSize1024($bytes, $precision = 2) { |
03 |
$unit = array( 'B' , 'KB' , 'MB' ); |
04 |
return @round($bytes / pow(1024, ($i = floor(log($bytes, 1024)))), $precision). ' ' .$unit[$i]; |
06 |
$sFileName = $_FILES[ 'image_file' ][ 'name' ]; |
07 |
$sFileType = $_FILES[ 'image_file' ][ 'type' ]; |
08 |
$sFileSize = bytesToSize1024($_FILES[ 'image_file' ][ 'size' ], 1); |
10 |
<p>Your file: {$sFileName} has been successfully received.</p> |
11 |
<p>Type: {$sFileType}</p> |
12 |
<p>Size: {$sFileSize}</p> |
As you can see – I’m not uploading file. But, ‘echo’ back all info about accepted file. This information will appear in our <div id=”upload_response”></div> element.
Conclusion
Welcome back to read new awesome and unique articles about HTML5. Good luck!