1

Basically i have to upload file by chunks as the file is very big,i tried using this solution uploading a file in chunks using html5 but the file is corrupt because the file reconstructed is not in order.

I tried to implement the answer given in the link but i really confused how can i implement it on my php page and my html page. If you guys could give me an advice or a way of doing it, that would be great. Thank you for your time.

The code :

upload.php

 <?php 

    $target_path = "/home/imagesdcard/www/";
    $tmp_name = $_FILES['fileToUpload']['tmp_name'];
    $size = $_FILES['fileToUpload']['size'];
    $name = $_FILES['fileToUpload']['name'];


    $target_file = $target_path . basename($name);
    $complete = "test.txt";
    $com = fopen("/home/imagesdcard/www/".$complete, "ab");
    error_log($target_path);

    // Open temp file
    $out = fopen($target_file, "wb");

    if ( $out ) {
        // Read binary input stream and append it to temp file
        $in = fopen($tmp_name, "rb");
        if ( $in ) {
            while ( $buff = fread( $in, 1024) ) {
            fwrite($out, $buff);
            fwrite($com, $buff);
        }   
    }
    fclose($in);
    fclose($out);
}
fclose($com);

?>

html

<!DOCTYPE html>
<html>
    <head>
        <title>Upload Files using XMLHttpRequest</title>
        <script type="text/javascript">

            window.BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder;

            function sendRequest() {
                var blob = document.getElementById('fileToUpload').files[0];
                const BYTES_PER_CHUNK = 1048576; // 1MB chunk sizes.
                const SIZE = blob.size;
                var i=0;
                var start = 0;
                var end = BYTES_PER_CHUNK;
                while( start < SIZE ) {
                    var chunk = blob.slice(start, end);
                    uploadFile(chunk,i);
                    i++;
                    start = end;
                    end = start + BYTES_PER_CHUNK;
                }
            }

            function fileSelected() {
                var file = document.getElementById('fileToUpload').files[0];
                if (file) {
                    var fileSize = 0;
                    if (file.size > 1024 * 1024)
                        fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
                    else
                        fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';

                    document.getElementById('fileName').innerHTML = 'Name: ' + file.name;
                    document.getElementById('fileSize').innerHTML = 'Size: ' + fileSize;
                    document.getElementById('fileType').innerHTML = 'Type: ' + file.type;
                }
            }

            function uploadFile(blobFile,part) {
                //var file = document.getElementById('fileToUpload').files[0];  
                var fd = new FormData();
                fd.append("fileToUpload", blobFile);

                var xhr = new XMLHttpRequest();
                xhr.upload.addEventListener("progress", uploadProgress, false);
                xhr.addEventListener("load", uploadComplete, false);
                xhr.addEventListener("error", uploadFailed, false);
                xhr.addEventListener("abort", uploadCanceled, false);
                xhr.open("POST", "upload.php?num="+part);
                xhr.onload = function(e) {
                  alert("loaded!");
                  };

                xhr.send(fd);
                //alert("oen over");
            }

            function uploadProgress(evt) {
                if (evt.lengthComputable) {
                    var percentComplete = Math.round(evt.loaded * 100 / evt.total);
                    document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';
                }
                else {
                    document.getElementById('progressNumber').innerHTML = 'unable to compute';
                }
            }

            function uploadComplete(evt) {
                /* This event is raised when the server send back a response */
                alert(evt.target.responseText);
            }

            function uploadFailed(evt) {
                alert("There was an error attempting to upload the file.");
            }

            function uploadCanceled(evt) {
                xhr.abort();
                xhr = null;
                //alert("The upload has been canceled by the user or the browser dropped the connection.");
            }
        </script>
    </head>
    <body>
        <form id="form1" enctype="multipart/form-data" method="post" action="upload.php">
            <div class="row">
                <label for="fileToUpload">Select a File to Upload</label><br />
                <input type="file" name="fileToUpload" id="fileToUpload" onchange="fileSelected();"/>
                <input type="button" value="cancel"  onClick="uploadCanceled();"/>
            </div>
            <div id="fileName"></div>
            <div id="fileSize"></div>
            <div id="fileType"></div>
            <div class="row">
                <input type="button" onclick="sendRequest();" value="Upload" />
            </div>
            <div id="progressNumber"></div>
        </form>
    </body>
</html>

1 Answers1

0

Your script doesn't work because js is async. You should change your code to:

xhr.open("POST", "upload.php?num="+part, false);

and file save fine.

My solution for upload big files by chunk.

upload.php (php part)

<?php
    session_start();
    
    if($_SERVER["REQUEST_METHOD"] == "POST")
    {
        $chunk = $_FILES["chunk"]["tmp_name"];
        $filename = $_POST['filename'];
    
        if(!isset($_SESSION[$filename]))
        {
            $_SESSION[$filename] = tempnam(sys_get_temp_dir(), 'upl');
        }
    
        $tmpfile = $_SESSION[$filename];
    
        if(isset($chunk))
        {
            file_put_contents($tmpfile, file_get_contents($chunk), FILE_APPEND);
        }
        else
        {
            rename($tmpfile, $filename);
        }
        exit();
    }
?>

upload.php (html\js part)

<!DOCTYPE html>
<html>
    <head>
        <title>Upload Files using XMLHttpRequest</title>
        <script src="https://code.jquery.com/jquery-3.6.0.js"></script>
        <script type="text/javascript">
            function sendRequest() {
                // 1MB chunk sizes.
                var chunk_size = 1048570;
                var file = document.getElementById('file').files[0];
                var filesize = file.size;
                var filename = file.name;
                var pos = 0;
                while(pos < filesize) {
                    let chunk = file.slice(pos, pos+chunk_size);
                    pos += chunk_size;

                    var data = new FormData();
                    data.append('chunk', chunk);
                    data.append('filename', filename);

                    $.ajax({url:'upload.php',type: 'post',async:false,data: data,processData: false,contentType: false});

                    let percentComplete = Math.round(pos * 100 / filesize);
                    document.getElementById('progressNumber').innerHTML = (percentComplete > 100 ? 100 : percentComplete) + '%';
                }
                $.post('upload.php',{filename:filename});
            }
        </script>
    </head>
    <body>
        <form>
            <div class="row">
                <label for="file">Select a File to Upload</label><br />
                <input type="file" name="file" id="file" onchange="sendRequest();"/>
            </div>
            <div id="progressNumber"></div>
        </form>
    </body>
</html>

but this code have one bug - progress bar don't work in chrome because sync request used, work only in firefox.

alex
  • 11
  • 2