Showing posts with label file upload. Show all posts
Showing posts with label file upload. Show all posts

Sunday, December 17, 2023

Using JavaScript to Upload Large Files in Chunks as Parts and Avoid Server Limits

We know that PHP config files has the limit to upload files to server, you know that uploading large files can be a real pain. You have to find the loaded php.ini file, edit the upload_max_filesize and post_max_size settings, and hope that you never have to change servers and do all of this over again.
We will do some trick to upload very very large file to server without manipulate any configuration, does not matter how small the limit is. We actually will send files from browser chunk by chunk. Chunk can be as small as our demand. Suppose if our server accept max 1mb request limit, we will send 1mb per request and many more.
This will include two parts (1) is to send files chunk by chunk from browser to server and the other part (2) is save file parts into single file. I will use PHP example at backend to save file into server.
So below is Javascript parts with description:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>File Upload Chunk</title>
</head>
<body>
    <div class="form">
        <input type="file" id="file"/>
        <button type="button" id="upload">Upload</button>
    </div>
    <div class="toast">
        <div id="toast"></div>
    </div>
    <script type="text/javascript">
        document.getElementById("upload").addEventListener("click", () => {
            let files = document.getElementById("file").files;
            if (files.length === 0) {
                alert("File required");
            }
            else {
                showToast("Uploading");
                doUploadFileChunk(files[0], 1);
            }
        });

        function doUploadFileChunk(file, chunk) {
            let chunkLimit = 1024 * 50; // Limit of file chunk send to server is 50 KB for test purpose

            // Blob from position
            let fromSlice = (chunk - 1) * chunkLimit;
            // Blob to position
            let nextSlice = fromSlice + chunkLimit - 1;
            // new FormData()
            let formData = new FormData();
            formData.append("file_number", chunk);
            formData.append("file_name", file.name);
            formData.append("file_part", file.slice(fromSlice, nextSlice + 1)); // Processing small part of file

            console.log(`Sending from ${fromSlice} to ${nextSlice} KB`);

            // Sending to server
            let xhr = new XMLHttpRequest();
            xhr.open("POST", "upload.php", true);
            xhr.setRequestHeader("Accept", "application/json");
            xhr.onreadystatechange = () => {
                if (xhr.readyState === 4) {
                    console.log("Status = " + xhr.status);
                    try {
                        let response = JSON.parse(xhr.responseText);
                        console.log(response);
                        if (response.uploaded) {
                            let percent = Math.floor((nextSlice / file.size) * 100);
                            if (nextSlice < file.size) {
                                showToast(`Uploading file - ${percent}% completed`);
                                setTimeout(() => {
                                    doUploadFileChunk(file, chunk + 1);
                                }, 200);
                            }
                            else {
                                showToast(`Upload completed, processing started`);
                            }
                        }
                        else {
                            alert("Failed to upload file");
                        }
                    }
                    catch (e) {
                        console.log("Complete = " + xhr.responseText);
                        console.log(e);
                        alert("Failed to upload file");
                    }
                }
            };
            xhr.send(formData);
        }

        function showToast(text) {
            document.getElementById("toast").innerHTML = text;
        }
    </script>
    <style type="text/css">
        div.form {
            padding: 20px;
        }
        div.toast {
            padding: 20px;
            background-color: green;
            color: white;
            font-size: 31px;
        }
    </style>
</body>
</html>
And respective PHP file is as below:
<?php
$output = ["uploaded" => true, "file" => $_FILES["file_part"]];

$uploadFile = sprintf("storage/%s", $_POST['file_name']);
if ($_POST["file_number"] == 1) {
    if (file_exists($uploadFile)) {
        unlink($uploadFile);
    }
}

$destination = fopen($uploadFile, "a+");
if (FALSE === $destination) die("Failed to open destination");

$handle = fopen($_FILES["file_part"]["tmp_name"], "rb");
if (FALSE === $handle) die("Failed to open blob");

$BUFFER_SIZE=1*1024*1024; // 1MB, bigger is faster
while( !feof($handle) ) {
    fwrite($destination, fread($handle, $BUFFER_SIZE) );
}
fclose($handle);
fclose($destination);

echo json_encode($output);

Monday, August 19, 2013

How can I upload files asynchronously with jQuery


With HTML5 you CAN make file uploads with Ajax and jQuery. Not only that, you can do file validations (name, size, and MIME-type) or handle the progress eventwith the HTML5 progress tag (or a div).

<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<form enctype="multipart/form-data">
    <input name="file" type="file" />
    <input type="button" value="Upload" />
</form>

<div class="progress_bar"
     style="width: 300px; height: 20px; background-color: blue; position: relative;">
    <div class="full" style="width: 0%;
    height: 20px; background-color: red;"></div>
    <div class="text"
         style="color: #ffffff; font-weight: bold; text-align: center;
         position: absolute; left: 109px; top: 0;">Uploading...</div>
</div>
<script type="text/javascript">
    jQuery(document).ready(function() {
        $(':button').click(function(){
            var formData = new FormData($('form')[0]);
            $.ajax({
                url: 'upload.php',  //Server script to process data
                type: 'POST',
                xhr: function() {  // Custom XMLHttpRequest
                    var myXhr = $.ajaxSettings.xhr();
                    if(myXhr.upload){ // Check if upload property exists
                        myXhr.upload.addEventListener('progress',progressHandlingFunction, false); // For handling the progress of the upload
                    }
                    return myXhr;
                },
                //Ajax events
                beforeSend: function() {
                    console.log("Before send...");
                    var $div = jQuery("div.progress_bar");
                    $div.find("div.full").css({
                        width: "0%"
                    });
                },
                success: function(data) {
                    console.log(data);
                    console.log("Success...");
                    var $div = jQuery("div.progress_bar");
                    $div.find("div.text").html("Uploaded.");
                },
                error: function() {
                    console.log("Error...");
                },
                // Form data
                data: formData,
                //Options to tell jQuery not to process data or worry about content-type.
                cache: false,
                contentType: false,
                processData: false
            });
        });
    });
    function progressHandlingFunction(e){
        console.log(e);
        if(e.lengthComputable){
            var $div = jQuery("div.progress_bar");
            var p = e.loaded / e.total * 100;
            $div.find("div.full").css({
                width: p + "%"
            });
            console.log(p);
        }
    }
</script>


As you can see, with HTML5 (and some research) file uploading not only becomes possible but super easy. Try it with Google Chrome as some of the HTML5 components of the examples aren't available in every browser. 

Sunday, August 11, 2013

File upload using ExtJS and Grails

/* ExtJS code to create a form */
    var customerEditMainFormParent = new Ext.FormPanel({
        labelAlign: 'top',
        header:false,
        style: "height: 200px;",
        border:false,
        renderTo: 'updateCustomer',
        id: "customer-form2",
        name: "customer-form2",
        fileUpload:true,
        isUpload: true,
        enctype:'multipart/form-data',
        url: Ext.SERVER_URL + 'save_file_data',
        items: [
            {
                xtype: 'fileuploadfield',
                id: 'filedata',
                emptyText: 'Select a document to upload...',
                fieldLabel: 'File',
                buttonText: 'Browse'
            }
        ]
    )};

/* Grails code */
if(params.containsKey("filedata") && bankAccountDetails != null) {
    try {
        String path = System.getProperty("java.io.tmpdir");
        /* Temporary directory */
        CommonsMultipartFile uploadFile = request.getFile("filedata");
        println uploadFile.getOriginalFilename();
        println uploadFile.getContentType();
        println uploadFile.getStorageDescription();
        uploadFile.transferTo(new File(path+"a.png"));
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

Wednesday, June 12, 2013

SCRIPT5 Access denied on form submit in IE if file is triggered

SCRIPT5 access denied is a problem when you want to trigger a input[type='file'] element on internet explorer(ie). Most of the browsers like mozilla, opera working by just triggering click on the file input field. But internet explorer(ie) does not like this and think this it as violation of access. So we just can put the file inside a div and make the input area whole around as div area. So when one click on the div, actually it clicks on the input element and open file selection dialog. And ie is now happy with it.
See the full result in jsFiddle.

jsFiddle view


Html and css

<div class="file_upload_section">
    <span>Click to upload</span>
    <input type="file" name="upload_file" />
</div>

<style type="text/css">
    div.file_upload_section {
        position: relative;
        background-color: yellow;
        padding: 20px
        font-weight: bold
        overflow: hidden;
    }
    
    div.file_upload_section input[type=file] {
        position: absolute;
        right: 0px;
        top: 0px;
        font-size: 2000px;
        height: 100%;
        opacity: 0;
        z-index: 1000;
        width: 100%;
    }
</style>

Additional jQuery code


$("div.file_upload_section").click(function() {
    var file = $(this).find("input[name='upload_file']");
    file.change(function() {
        var fileName = "Uploading: " + $(this).val().split("\\").pop();
        file.closest("div.file_upload_section").find("span").html(fileName);
    });
});