Pure HTML5 file upload

Pure HTML5 file upload

117 778
Pure HTML5 file upload
Pure HTML5 file upload

Pure HTML5 file upload

Today we will be developing 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

Ok, download the sources and lets begin !


Step 1. HTML

At this page you can see out form for upload images

index.html


<html lang="en" >
    <head>
        <meta charset="utf-8" />
        <title>Pure HTML5 file upload | Script Tutorials</title>
        <link href="css/main.css" rel="stylesheet" type="text/css" />
        <script src="js/script.js"></script>
    </head>
    <body>
        <header>
            <h2>Pure HTML5 file upload</h2>
            <a href="http://www.script-tutorials.com/pure-html5-file-upload/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a>
        </header>
        <div class="container">
            <div class="contr"><h2>You can select the file (image) and click Upload button</h2></div>

            <div class="upload_form_cont">
                <form id="upload_form" enctype="multipart/form-data" method="post" action="upload.php">
                    <div>
                        <div><label for="image_file">Please select image file</label></div>
                        <div><input type="file" name="image_file" id="image_file" onchange="fileSelected();" /></div>
                    </div>
                    <div>
                        <input type="button" value="Upload" onclick="startUploading()" />
                    </div>
                    <div id="fileinfo">
                        <div id="filename"></div>
                        <div id="filesize"></div>
                        <div id="filetype"></div>
                        <div id="filedim"></div>
                    </div>
                    <div id="error">You should select valid image files only!</div>
                    <div id="error2">An error occurred while uploading the file</div>
                    <div id="abort">The upload has been canceled by the user or the browser dropped the connection</div>
                    <div id="warnsize">Your file is very big. We can't accept it. Please select more small file</div>

                    <div id="progress_info">
                        <div id="progress"></div>
                        <div id="progress_percent">&nbsp;</div>
                        <div class="clear_both"></div>
                        <div>
                            <div id="speed">&nbsp;</div>
                            <div id="remaining">&nbsp;</div>
                            <div id="b_transfered">&nbsp;</div>
                            <div class="clear_both"></div>
                        </div>
                        <div id="upload_response"></div>
                    </div>
                </form>

                <img id="preview" />
            </div>
        </div>
    </body>
</html>

Step 2. CSS

css/main.css

I have selected all necessary styles for our html5 upload form

css/main.css

.upload_form_cont {
    background: -moz-linear-gradient(#ffffff, #f2f2f2);
    background: -ms-linear-gradient(#ffffff, #f2f2f2);
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #f2f2f2));
    background: -webkit-linear-gradient(#ffffff, #f2f2f2);
    background: -o-linear-gradient(#ffffff, #f2f2f2);
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f2f2f2');
    -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f2f2f2')";
    background: linear-gradient(#ffffff, #f2f2f2);

    color:#000;
    overflow:hidden;
}
#upload_form {
    float:left;
    padding:20px;
    width:700px;
}
#preview {
    background-color:#fff;
    display:block;
    float:right;
    width:200px;
}
#upload_form > div {
    margin-bottom:10px;
}
#speed,#remaining {
    float:left;
    width:100px;
}
#b_transfered {
    float:right;
    text-align:right;
}
.clear_both {
    clear:both;
}
input {
    border-radius:10px;
    -moz-border-radius:10px;
    -ms-border-radius:10px;
    -o-border-radius:10px;
    -webkit-border-radius:10px;

    border:1px solid #ccc;
    font-size:14pt;
    padding:5px 10px;
}
input[type=button] {
    background: -moz-linear-gradient(#ffffff, #dfdfdf);
    background: -ms-linear-gradient(#ffffff, #dfdfdf);
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #dfdfdf));
    background: -webkit-linear-gradient(#ffffff, #dfdfdf);
    background: -o-linear-gradient(#ffffff, #dfdfdf);
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dfdfdf');
    -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dfdfdf')";
    background: linear-gradient(#ffffff, #dfdfdf);
}
#image_file {
    width:400px;
}
#progress_info {
    font-size:10pt;
}
#fileinfo,#error,#error2,#abort,#warnsize {
    color:#aaa;
    display:none;
    font-size:10pt;
    font-style:italic;
    margin-top:10px;
}
#progress {
    border:1px solid #ccc;
    display:none;
    float:left;
    height:14px;

    border-radius:10px;
    -moz-border-radius:10px;
    -ms-border-radius:10px;
    -o-border-radius:10px;
    -webkit-border-radius:10px;

    background: -moz-linear-gradient(#66cc00, #4b9500);
    background: -ms-linear-gradient(#66cc00, #4b9500);
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #66cc00), color-stop(100%, #4b9500));
    background: -webkit-linear-gradient(#66cc00, #4b9500);
    background: -o-linear-gradient(#66cc00, #4b9500);
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#66cc00', endColorstr='#4b9500');
    -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#66cc00', endColorstr='#4b9500')";
    background: linear-gradient(#66cc00, #4b9500);
}
#progress_percent {
    float:right;
}
#upload_response {
    margin-top: 10px;
    padding: 20px;
    overflow: hidden;
    display: none;
    border: 1px solid #ccc;

    border-radius:10px;
    -moz-border-radius:10px;
    -ms-border-radius:10px;
    -o-border-radius:10px;
    -webkit-border-radius:10px;

    box-shadow: 0 0 5px #ccc;
    background: -moz-linear-gradient(#bbb, #eee);
    background: -ms-linear-gradient(#bbb, #eee);
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #bbb), color-stop(100%, #eee));
    background: -webkit-linear-gradient(#bbb, #eee);
    background: -o-linear-gradient(#bbb, #eee);
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#bbb', endColorstr='#eee');
    -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#bbb', endColorstr='#eee')";
    background: linear-gradient(#bbb, #eee);
}

Step 3. HTML5 JS

js/script.js

// common variables
var iBytesUploaded = 0;
var iBytesTotal = 0;
var iPreviousBytesLoaded = 0;
var iMaxFilesize = 1048576; // 1MB
var oTimer = 0;
var sResultFileSize = '';

function secondsToTime(secs) { // we will use this function to convert seconds in normal time format
    var hr = Math.floor(secs / 3600);
    var min = Math.floor((secs - (hr * 3600))/60);
    var sec = Math.floor(secs - (hr * 3600) -  (min * 60));

    if (hr < 10) {hr = "0" + hr; }
    if (min < 10) {min = "0" + min;}
    if (sec < 10) {sec = "0" + sec;}
    if (hr) {hr = "00";}
    return hr + ':' + min + ':' + sec;
};

function bytesToSize(bytes) {
    var sizes = ['Bytes', 'KB', 'MB'];
    if (bytes == 0) return 'n/a';
    var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
    return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i];
};

function fileSelected() {

    // hide different warnings
    document.getElementById('upload_response').style.display = 'none';
    document.getElementById('error').style.display = 'none';
    document.getElementById('error2').style.display = 'none';
    document.getElementById('abort').style.display = 'none';
    document.getElementById('warnsize').style.display = 'none';

    // get selected file element
    var oFile = document.getElementById('image_file').files[0];

    // filter for image files
    var rFilter = /^(image\/bmp|image\/gif|image\/jpeg|image\/png|image\/tiff)$/i;
    if (! rFilter.test(oFile.type)) {
        document.getElementById('error').style.display = 'block';
        return;
    }

    // little test for filesize
    if (oFile.size > iMaxFilesize) {
        document.getElementById('warnsize').style.display = 'block';
        return;
    }

    // get preview element
    var oImage = document.getElementById('preview');

    // prepare HTML5 FileReader
    var oReader = new FileReader();
        oReader.onload = function(e){

        // e.target.result contains the DataURL which we will use as a source of the image
        oImage.src = e.target.result;

        oImage.onload = function () { // binding onload event

            // we are going to display some custom image information here
            sResultFileSize = bytesToSize(oFile.size);
            document.getElementById('fileinfo').style.display = 'block';
            document.getElementById('filename').innerHTML = 'Name: ' + oFile.name;
            document.getElementById('filesize').innerHTML = 'Size: ' + sResultFileSize;
            document.getElementById('filetype').innerHTML = 'Type: ' + oFile.type;
            document.getElementById('filedim').innerHTML = 'Dimension: ' + oImage.naturalWidth + ' x ' + oImage.naturalHeight;
        };
    };

    // read selected file as DataURL
    oReader.readAsDataURL(oFile);
}

function startUploading() {
    // cleanup all temp states
    iPreviousBytesLoaded = 0;
    document.getElementById('upload_response').style.display = 'none';
    document.getElementById('error').style.display = 'none';
    document.getElementById('error2').style.display = 'none';
    document.getElementById('abort').style.display = 'none';
    document.getElementById('warnsize').style.display = 'none';
    document.getElementById('progress_percent').innerHTML = '';
    var oProgress = document.getElementById('progress');
    oProgress.style.display = 'block';
    oProgress.style.width = '0px';

    // get form data for POSTing
    //var vFD = document.getElementById('upload_form').getFormData(); // for FF3
    var vFD = new FormData(document.getElementById('upload_form')); 

    // create XMLHttpRequest object, adding few event listeners, and POSTing our data
    var oXHR = new XMLHttpRequest();        
    oXHR.upload.addEventListener('progress', uploadProgress, false);
    oXHR.addEventListener('load', uploadFinish, false);
    oXHR.addEventListener('error', uploadError, false);
    oXHR.addEventListener('abort', uploadAbort, false);
    oXHR.open('POST', 'upload.php');
    oXHR.send(vFD);

    // set inner timer
    oTimer = setInterval(doInnerUpdates, 300);
}

function doInnerUpdates() { // we will use this function to display upload speed
    var iCB = iBytesUploaded;
    var iDiff = iCB - iPreviousBytesLoaded;

    // if nothing new loaded - exit
    if (iDiff == 0)
        return;

    iPreviousBytesLoaded = iCB;
    iDiff = iDiff * 2;
    var iBytesRem = iBytesTotal - iPreviousBytesLoaded;
    var secondsRemaining = iBytesRem / iDiff;

    // update speed info
    var iSpeed = iDiff.toString() + 'B/s';
    if (iDiff > 1024 * 1024) {
        iSpeed = (Math.round(iDiff * 100/(1024*1024))/100).toString() + 'MB/s';
    } else if (iDiff > 1024) {
        iSpeed =  (Math.round(iDiff * 100/1024)/100).toString() + 'KB/s';
    }

    document.getElementById('speed').innerHTML = iSpeed;
    document.getElementById('remaining').innerHTML = '| ' + secondsToTime(secondsRemaining);        
}

function uploadProgress(e) { // upload process in progress
    if (e.lengthComputable) {
        iBytesUploaded = e.loaded;
        iBytesTotal = e.total;
        var iPercentComplete = Math.round(e.loaded * 100 / e.total);
        var iBytesTransfered = bytesToSize(iBytesUploaded);

        document.getElementById('progress_percent').innerHTML = iPercentComplete.toString() + '%';
        document.getElementById('progress').style.width = (iPercentComplete * 4).toString() + 'px';
        document.getElementById('b_transfered').innerHTML = iBytesTransfered;
        if (iPercentComplete == 100) {
            var oUploadResponse = document.getElementById('upload_response');
            oUploadResponse.innerHTML = '<h1>Please wait...processing</h1>';
            oUploadResponse.style.display = 'block';
        }
    } else {
        document.getElementById('progress').innerHTML = 'unable to compute';
    }
}

function uploadFinish(e) { // upload successfully finished
    var oUploadResponse = document.getElementById('upload_response');
    oUploadResponse.innerHTML = e.target.responseText;
    oUploadResponse.style.display = 'block';

    document.getElementById('progress_percent').innerHTML = '100%';
    document.getElementById('progress').style.width = '400px';
    document.getElementById('filesize').innerHTML = sResultFileSize;
    document.getElementById('remaining').innerHTML = '| 00:00:00';

    clearInterval(oTimer);
}

function uploadError(e) { // upload error
    document.getElementById('error2').style.display = 'block';
    clearInterval(oTimer);
}  

function uploadAbort(e) { // upload abort
    document.getElementById('abort').style.display = 'block';
    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

<?php

function bytesToSize1024($bytes, $precision = 2) {
    $unit = array('B','KB','MB');
    return @round($bytes / pow(1024, ($i = floor(log($bytes, 1024)))), $precision).' '.$unit[$i];
}

$sFileName = $_FILES['image_file']['name'];
$sFileType = $_FILES['image_file']['type'];
$sFileSize = bytesToSize1024($_FILES['image_file']['size'], 1);

echo <<<EOF
<p>Your file: {$sFileName} has been successfully received.</p>
<p>Type: {$sFileType}</p>
<p>Size: {$sFileSize}</p>
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!

SIMILAR ARTICLES


117 COMMENTS

  1. I have read your previous comments about where the uploaded files go, but I am still confused. can you give me an example of a directory that I can change for the files to go there? I tried changing the script to
    $sFileName = $_FILES['http://coolf2a.com/uploaded']['name']
    $sFileType = $_FILES['http://coolf2a.com/uploaded']['type']
    $sFileSize = bytesToSize1024($_FILES['http://coolf2a.com/uploaded']['size'], 1)
    I also created a uploaded folder in my server.
    Thanks

  2. It would be most sensible and save over half the comments here to just complete the code with example path to save. It would probably take less writing on your part to edit the post than continually answer how simple it is. – simple when you know how. – otherwise great tut, thanks

  3. Thanks for nice solution, bat ja script dont have coopirate. Please mail me is it possible, like name, mail, autor, etc.

  4. Hi,
    i uploaded the script to my webspace. When i upload a file it says “successfully uploaded file..:” but i cant find it in the folder? Where will the file be uploaded?

    • Hi Joe, all the uploaded files should be in the folder where you dropped them. I don’t know where exactly you uploaded it.

  5. I modified the uploads.php like you mentioned, but it does not work:

    <?php

    function bytesToSize1024($bytes, $precision = 2) {
    $unit = array('B','KB','MB');
    return @round($bytes / pow(1024, ($i = floor(log($bytes, 1024)))), $precision).' '.$unit[$i];
    }

    $sFileName = $_FILES['image_file']['name'];
    $sFileType = $_FILES['image_file']['type'];
    $sFileSize = bytesToSize1024($_FILES['image_file']['size'], 1);

    echo <<<EOF
    Your file: {$sFileName} wurde hochgeladen JONGE!
    Type: {$sFileType}
    Size: {$sFileSize}
    EOF;

    /////////////////////// CONFIGURATION OF FILE FOLDER
    $uploads_dir = ‘/uploads’;
    foreach ($_FILES['image_file']['type'] as $key => $error) {
    if ($error == UPLOAD_ERR_OK) {
    $tmp_name = $_FILES["pictures"]["tmp_name"][$key];
    $name = $_FILES["pictures"]["name"][$key];
    move_uploaded_file($tmp_name, “$uploads_dir/$name”);
    }
    }
    ?>

    • Hello Joe, your code has few mistakes. Pay attention, that in the beginning you used the correct variable: $_FILES['image_file']
      but, why did you change you plans after, you you started using $_FILES['pictures'] ?
      Actually, you could use the already defined
      $sFileName = $_FILES['image_file']['name'];
      for ‘move_uploaded_file’ function, for instance:
      move_uploaded_file($sFileName, ‘uploads/new_file’);

      • i got the foreach statement error: do you know what this could be?
        Warning: Invalid argument supplied for foreach() in xxxxxx/upload.php on line 21

        /////////////////////// CONFIGURATION OF FILE FOLDER
        $uploads_dir = “/uploads”;
        foreach ($_FILES['image_file']['type'] as $key => $error) {
        if ($error == UPLOAD_ERR_OK)
        {
        $tmp_name = $_FILES["pictures"]["tmp_name"][$key];
        $name = $_FILES["pictures"]["name"][$key];
        move_uploaded_file($sFileName, “uploads/new_file”);
        }
        }

      • Hi Jos,
        $_FILES['image_file']['type'] is not array, you don’t need to ‘foreach’ it. Better- if you use ‘IF’ statement instead

  6. Hi everyone,
    i wonder if you could help me make the uploader to display the picture in it’s page after uploading is finished ,i must say i’m not very experienced.Thanx.

    $(‘#submit_form’)click(function(){
    $.ajax({
    type: ‘POST’,
    url: path/phpfile.php,
    data: image_input_name
    });

    //after submitting, get the url of the image form the server

    $(‘#div_to_display_image’).html(“”);

    });

  7. To help many of you, here is what I simply needed to put in the PHP file for the upload to work:

    move_uploaded_file($_FILES['image_file']['tmp_name'], $_FILES["image_file"]["name"]);

    Simply put this new line before the line saying ECHO <<EOF.
    It will let the file to upload itself in the same directory as the directory where your htm and php files are, if same. And you also need to ensure that your directory is 777 regarding the permissions.
    Also check that your PHP.ini says ON to file uploads.

    • Hello Vinc, yes, sure, your directory should be writable (777), and, just remember, that when we copy or move something, firstly – we define a place ‘From’. As you already noticed, this is our uploaded image: $_FILES['image_file']['tmp_name'], but the second param is ‘To’ – a place to put this image, it can be a certain path on your server (but not the same image: $_FILES['image_file']['tmp_name']).

  8. Great article! This worked well in desktop’s devices, but do not worked in mobile’s device. Do you know how can i make this upload’s system work with mobile (android and/or ios)?

      • It work’s fine for mobile phones. However, you cannot upload any file you want. Android lets you upload files from gallery, music camera and voice recorder

      • Hello George,
        Yes, of course you can not upload ANY files. Do not forget about custom restrictions which we added into our code.

  9. great look and feel for your upload form..

    Question: How do I change file type to doc,docx,pdf,txt and also how to get the files emailed to a specified email address ??

    Thanks

    • Hi Ben,
      You can use any available mime types:
      .doc application/msword
      .docx application/vnd.openxmlformats-officedocument.wordprocessingml.document
      .pdf application/pdf
      .txt text/plain
      .html text/html

  10. Everytime i try to upload.

    I get error

    An error occurred while uploading the file

    Please help me on this.

    I have apc install and everything works fine Just it doesnt upload.

    Thanks

  11. Hi,

    the upload.php file is going ok width my parameters (the uploaded files are going in the correct file) BUT
    I want to redirect my user on another page and it redirect him in a frame on the same (base) page.
    Any advice ? Oo

    Regards
    Benoît

  12. Great post. It helped me a lot.
    I am facing one problem .
    Its taking more time to select file and showing file attributes such as filename,filetype etc , especially for large file in GB. i have removed file type restriction and tried with video file. sometimes browser gets corrupted or taking very long time to show file attributes. I think its depend on the memory. any suggestion to solve this. please guide me.

    • Hi Rajeev,
      To tell the truth, I have no idea why it so. Do you load video files as images (our image with id=preview) ?

  13. This thing works like a charm (including FF for Android [rest not tested]), but I found 1 small thing:
    If you select a file and click the select file again and select cancel there will not be a file selected, but in the preview there is.
    I fixed this by moving
    // get preview element
    var oImage = document.getElementById(‘preview’);
    to just after the opening of de function
    fileSelected
    and adding this line
    oImage.src = ”;
    to the hide warnings part.
    This clears the preview showing that you can not upload a file.

    Besides this minor inconvenience this thing works like a charm.

    P.S. You might want to put ‘max-width: 720px;’ in the CSS for the textarea’s of this site, the new resize functionality of browsers breaks the page.

    • Hello Wouter,
      In general, when we click the ‘cancel’ button, it will not call the onchange event handler (fileSelected function). But thank you for your other valuable remarks.

  14. Very Good Script Thank you :)

    I have a question. i want to have 3 Uploads in one index. Is it possible?

    Kind Regards :)

    • Hi Sasch,
      There is no reason to limit your imagination. Yes, of course you can have any desired amount of uploads at your index page. You just need to modify the script in accordance with the new forms.

  15. The code says its completed the transfer, even though no upload file was selected, anyway to change this to force user to select a file?

    • Hi Dom,
      I can advise to check whether the file fits all the requirements before calling the ‘startUploading’ function. For instance, define a new variable (var bCanSubmit = false), and after, assign the ‘true’ in case if a file is selected and valid (in ‘fileSelected’ function). And finally, add a check for this variable into the ‘startUploading’ function

  16. Hello Andrey,thanks for your demos. it helps me a lot. But i have a question, why i can’t use it in the mobile? i mean that i cant upload the images in my mobile. Can you help me?

    • Hi Suhaphy,
      Doesn’t it work at mobile devices? Have you already tried? Was your question about uploading files onto mobile phone?

  17. hy,
    great script.
    I need help with the upload.
    The pic was not uploaded in the uploads dir.
    So i missed a function with the uploaddir path.
    Can you help me?
    thx

  18. Master! i will try to use your code, but, i get a message:

    “alerta de seguridad el archivo que intenta subir ha sido rechazado”

    i need to pay for use?? or is a fre code?

  19. Hi.

    Is it possibel to set the directory for the file browser when the user press the select file button.

    I need alwas to start in c:\filetoupload\images\custinfo\4711

    thx

    • Hi Flemming,
      Hmm, I am not sure if this is possible, because only the browser saves this information (every time you select a file)

  20. hello admin,thanks a lot for your script! I want to your help ,how I change for jsp?and How i know where the upload file in my server’s path ?

  21. Great script.. Thank you.. I\’ve done lots of testing on the file uploader and I have used with your other facebook like gallery… Works just fine… In your js file for the uploader you defined the acceptable file formats, when you select a different file format it gives you a message to use a correct file format but if you hit upload the file will be uploaded…. Is it necessary to set some acceptable file extensions in upload.php or what would you recommend …

    • Hi Sidney,
      Yes, I agree, for the better protection, you may add this verification into the upload.php file. If you upload images, you can use ‘getimagesize’ function to get info about images, or, you can rely on the file extension.

Leave a Reply