Pure HTML5 file upload

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:

Live Demo

[sociallocker]

download in package

[/sociallocker]


Ok, download the sources and lets begin !


Step 1. HTML

At this page you can see out form for upload images

index.html

01 <html lang="en" >
02     <head>
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>
07     </head>
08     <body>
09         <header>
10             <h2>Pure HTML5 file upload</h2>
11             <a href="https://www.script-tutorials.com/pure-html5-file-upload/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a>
12         </header>
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">
17                     <div>
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>
20                     </div>
21                     <div>
22                         <input type="button" value="Upload" onclick="startUploading()" />
23                     </div>
24                     <div id="fileinfo">
25                         <div id="filename"></div>
26                         <div id="filesize"></div>
27                         <div id="filetype"></div>
28                         <div id="filedim"></div>
29                     </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">&nbsp;</div>
37                         <div class="clear_both"></div>
38                         <div>
39                             <div id="speed">&nbsp;</div>
40                             <div id="remaining">&nbsp;</div>
41                             <div id="b_transfered">&nbsp;</div>
42                             <div class="clear_both"></div>
43                         </div>
44                         <div id="upload_response"></div>
45                     </div>
46                 </form>
47                 <img id="preview" />
48             </div>
49         </div>
50     </body>
51 </html>

Step 2. CSS

css/main.css

I have selected all necessary styles for our html5 upload form

css/main.css

001 .upload_form_cont {
002     background: -moz-linear-gradient(#ffffff#f2f2f2);
003     background: -ms-linear-gradient(#ffffff#f2f2f2);
004     background: -webkit-gradient(linear, left topleft 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);
010     color:#000;
011     overflow:hidden;
012 }
013 #upload_form {
014     float:left;
015     padding:20px;
016     width:700px;
017 }
018 #preview {
019     background-color:#fff;
020     display:block;
021     float:right;
022     width:200px;
023 }
024 #upload_form > div {
025     margin-bottom:10px;
026 }
027 #speed,#remaining {
028     float:left;
029     width:100px;
030 }
031 #b_transfered {
032     float:right;
033     text-align:right;
034 }
035 .clear_both {
036     clear:both;
037 }
038 input {
039     border-radius:10px;
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;
045     font-size:14pt;
046     padding:5px 10px;
047 }
048 input[type=button] {
049     background: -moz-linear-gradient(#ffffff#dfdfdf);
050     background: -ms-linear-gradient(#ffffff#dfdfdf);
051     background: -webkit-gradient(linear, left topleft 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);
057 }
058 #image_file {
059     width:400px;
060 }
061 #progress_info {
062     font-size:10pt;
063 }
064 #fileinfo,#error,#error2,#abort,#warnsize {
065     color:#aaa;
066     display:none;
067     font-size:10pt;
068     font-style:italic;
069     margin-top:10px;
070 }
071 #progress {
072     border:1px solid #ccc;
073     display:none;
074     float:left;
075     height:14px;
076     border-radius:10px;
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 topleft 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);
089 }
090 #progress_percent {
091     float:right;
092 }
093 #upload_response {
094     margin-top10px;
095     padding20px;
096     overflowhidden;
097     displaynone;
098     border1px solid #ccc;
099     border-radius:10px;
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 topleft 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);
113 }

Step 3. HTML5 JS

js/script.js

001 // common variables
002 var iBytesUploaded = 0;
003 var iBytesTotal = 0;
004 var iPreviousBytesLoaded = 0;
005 var iMaxFilesize = 1048576; // 1MB
006 var oTimer = 0;
007 var sResultFileSize = '';
008 function secondsToTime(secs) { // we will use this function to convert seconds in normal time format
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;}
015     if (hr) {hr = "00";}
016     return hr + ':' + min + ':' + sec;
017 };
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];
023 };
024 function fileSelected() {
025     // hide different warnings
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';
031     // get selected file element
032     var oFile = document.getElementById('image_file').files[0];
033     // filter for image files
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';
037         return;
038     }
039     // little test for filesize
040     if (oFile.size > iMaxFilesize) {
041         document.getElementById('warnsize').style.display = 'block';
042         return;
043     }
044     // get preview element
045     var oImage = document.getElementById('preview');
046     // prepare HTML5 FileReader
047     var oReader = new FileReader();
048         oReader.onload = function(e){
049         // e.target.result contains the DataURL which we will use as a source of the image
050         oImage.src = e.target.result;
051         oImage.onload = function () { // binding onload event
052             // we are going to display some custom image information here
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;
059         };
060     };
061     // read selected file as DataURL
062     oReader.readAsDataURL(oFile);
063 }
064 function startUploading() {
065     // cleanup all temp states
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';
076     // get form data for POSTing
077     //var vFD = document.getElementById('upload_form').getFormData(); // for FF3
078     var vFD = new FormData(document.getElementById('upload_form'));
079     // create XMLHttpRequest object, adding few event listeners, and POSTing our data
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');
086     oXHR.send(vFD);
087     // set inner timer
088     oTimer = setInterval(doInnerUpdates, 300);
089 }
090 function doInnerUpdates() { // we will use this function to display upload speed
091     var iCB = iBytesUploaded;
092     var iDiff = iCB - iPreviousBytesLoaded;
093     // if nothing new loaded - exit
094     if (iDiff == 0)
095         return;
096     iPreviousBytesLoaded = iCB;
097     iDiff = iDiff * 2;
098     var iBytesRem = iBytesTotal - iPreviousBytesLoaded;
099     var secondsRemaining = iBytesRem / iDiff;
100     // update speed info
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';
106     }
107     document.getElementById('speed').innerHTML = iSpeed;
108     document.getElementById('remaining').innerHTML = '| ' + secondsToTime(secondsRemaining);
109 }
110 function uploadProgress(e) { // upload process in progress
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';
123         }
124     else {
125         document.getElementById('progress').innerHTML = 'unable to compute';
126     }
127 }
128 function uploadFinish(e) { // upload successfully finished
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);
137 }
138 function uploadError(e) { // upload error
139     document.getElementById('error2').style.display = 'block';
140     clearInterval(oTimer);
141 }
142 function uploadAbort(e) { // upload abort
143     document.getElementById('abort').style.display = 'block';
144     clearInterval(oTimer);
145 }

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

01 <?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];
05 }
06 $sFileName = $_FILES['image_file']['name'];
07 $sFileType = $_FILES['image_file']['type'];
08 $sFileSize = bytesToSize1024($_FILES['image_file']['size'], 1);
09 echo <<<EOF
10 <p>Your file: {$sFileName} has been successfully received.</p>
11 <p>Type: {$sFileType}</p>
12 <p>Size: {$sFileSize}</p>
13 EOF;

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.


Live Demo

Conclusion

Welcome back to read new awesome and unique articles about HTML5. Good luck!