最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

php - Javascript large file uploader - Stack Overflow

programmeradmin1浏览0评论

I copied a code online to upload a large file to my server. It basically cut the large file into chunks and send then end them individually. So the first chunk get successfully sent to the server, but the rest just does not work. I am not sure which stage cause the problem, can someone please help.

<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 start = 0;
                var i =0;
                var part = 0;
                while( start < SIZE ) {
                    var chunk = blob.slice(start, BYTES_PER_CHUNK);
                    //alert(chunk.size());
                    uploadFile(chunk,part);
                    //alert("here");
                    start = start + BYTES_PER_CHUNK;
                    part++;
                }
            }

            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"+"?"+"file="+file.name+"&num=" + part);
                xhr.onload = function(e) {
                  //alert("loaded!");
                  };

                xhr.setRequestHeader('Cache-Control','no-cache');
                xhr.send(fd);
                return;
                //while(xhr.readyState!=4){}
                //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 pute';
                }
            }

            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>

the Code on the Server

$target_path = "uploads/";
$tmp_name = $_FILES['fileToUpload']['tmp_name'];
$size = $_FILES['fileToUpload']['size'];
$name = $_FILES['fileToUpload']['name'];
$sports = $_GET['file'];
$part =(string)$_GET['num'];
//$part = split("/\=/", $part);
$target_file = $target_path .$part. $sports;


// 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, 1048576 ) ) {
            fwrite($out, $buff);
        }   
    }
    fclose($in);
    fclose($out);
}

  ?>

I copied a code online to upload a large file to my server. It basically cut the large file into chunks and send then end them individually. So the first chunk get successfully sent to the server, but the rest just does not work. I am not sure which stage cause the problem, can someone please help.

<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 start = 0;
                var i =0;
                var part = 0;
                while( start < SIZE ) {
                    var chunk = blob.slice(start, BYTES_PER_CHUNK);
                    //alert(chunk.size());
                    uploadFile(chunk,part);
                    //alert("here");
                    start = start + BYTES_PER_CHUNK;
                    part++;
                }
            }

            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"+"?"+"file="+file.name+"&num=" + part);
                xhr.onload = function(e) {
                  //alert("loaded!");
                  };

                xhr.setRequestHeader('Cache-Control','no-cache');
                xhr.send(fd);
                return;
                //while(xhr.readyState!=4){}
                //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 pute';
                }
            }

            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>

the Code on the Server

$target_path = "uploads/";
$tmp_name = $_FILES['fileToUpload']['tmp_name'];
$size = $_FILES['fileToUpload']['size'];
$name = $_FILES['fileToUpload']['name'];
$sports = $_GET['file'];
$part =(string)$_GET['num'];
//$part = split("/\=/", $part);
$target_file = $target_path .$part. $sports;


// 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, 1048576 ) ) {
            fwrite($out, $buff);
        }   
    }
    fclose($in);
    fclose($out);
}

  ?>
Share Improve this question edited Dec 9, 2012 at 22:30 Charles 51.4k13 gold badges106 silver badges144 bronze badges asked Dec 9, 2012 at 22:28 user1890228user1890228 611 gold badge1 silver badge2 bronze badges
Add a ment  | 

6 Answers 6

Reset to default 2

There is a glitch in the code above. You are calling uploadFile in while loop like this..

            while( start < SIZE ) {
                var chunk = blob.slice(start, BYTES_PER_CHUNK);
                //alert(chunk.size());
                uploadFile(chunk,part);
                //alert("here");
                start = start + BYTES_PER_CHUNK;
                part++;
            }

You are not waiting for chunk to load successfully !! You keep on uploading the chunks until the end. You can wait for one chunk to upload successfully and then load the next.

I feel you can try the following ..

     var blob;
     var start;
     var part;
     var chunk;
     const SIZE = blob.size;
     var xhr;
     function sendRequest() {
            blob = document.getElementById('fileToUpload').files[0];
            const BYTES_PER_CHUNK = 1048576; // 1MB chunk sizes.
            const SIZE = blob.size;
            start = 0;                
            part = 0;
            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"+"?"+"file="+file.name+"&num=" + part);
            xhr.onload = function(e) {
              //alert("loaded!");
              };

            xhr.setRequestHeader('Cache-Control','no-cache');
            chunk = blob.slice(start, BYTES_PER_CHUNK);
            //alert(chunk.size());
            uploadFile(chunk,part);
            //alert("here");
            start = start + BYTES_PER_CHUNK;
            part++;                
        }
function uploadFile(blobFile,part) {
            var file = document.getElementById('fileToUpload').files[0];  
            var fd = new FormData();
            fd.append("fileToUpload", blobFile);


            xhr.send(fd);
            return;
            //while(xhr.readyState!=4){}
            //alert("oen over");
        }

function uploadComplete(evt) {
            /* This event is raised when the server send back a response */
            alert(evt.target.responseText);
            while( start < SIZE ) {
                chunk = blob.slice(start, BYTES_PER_CHUNK);
                //alert(chunk.size());
                uploadFile(chunk,part);
                //alert("here");
                start = start + BYTES_PER_CHUNK;
                part++;
            }
        }

The reason that the rest are not uploading is that your slice loop is not right. change it to the following and you should be golden.

var start = 0;
var end = BYTES_PER_CHUNK;
var part = 0;
while( start < SIZE ) {
    var chunk = blob.slice(start, end);
    uploadFile(chunk,part);
    start = end;
    end = start + BYTES_PER_CHUNK;
    part++;
}

The .JS script here, uploads the blob in chunks successfully.

window.BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder;
        var blob; var blob_1;
        var start; var end;
        var num; var part;
        var SIZE; var size; var fileSize = 0;
        var BYTES_PER_CHUNK; var NUM_CHUNKS; var chunk; var chunk_size = 0;
        var xhr; var counter = 0;
        
        function sendRequest() {

            blob = document.getElementById('file').files[0];
            // blob = new Blob(blob_1, {type: 'video/mp4'}); 
                const BYTES_PER_CHUNK = 1048576; // 1MB chunk sizes.
                const SIZE = blob.size;
                var i = 0;
                var start = 0;
                var end = BYTES_PER_CHUNK;
                var part = 0;
                var NUM_CHUNKS = Math.max(Math.ceil(SIZE / BYTES_PER_CHUNK), 1);
                
                while( start < SIZE ) {
                    var chunk = blob.slice(start, end);
                    uploadFile(chunk,part);
                    start = end;
                    end = start + BYTES_PER_CHUNK;
                    part++; counter++;
                }
        };

        function fileSelected() {
            var file = document.getElementById('file').files[0];
            if (file) {
                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('file').files[0];  
            var fd = new FormData();
            fd.append("file", blobFile);  fd.append("chunk_num", NUM_CHUNKS);  
            var xhr = new XMLHttpRequest();
            xhr.upload.addEventListener("progress", uploadProgress, false);
            
            xhr.open("POST", "uploadhandler.php"+"?"+"filen="+file.name+"&num="+part+"&counter="+counter);
            
            
            xhr.addEventListener("load", uploadComplete, false);
            xhr.addEventListener("error", uploadFailed, false);
            xhr.addEventListener("abort", uploadCanceled, false);

            
            xhr.onload = function(e) {
              //alert("loaded!");
              };

            xhr.setRequestHeader('Cache-Control','no-cache');
            xhr.send(fd);
            return;
        }
        
        function uploadProgress(evt) {
            if (evt.lengthComputable) {
                var percentComplete = Math.round(evt.loaded * 100 / evt.total);
                document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';
                document.getElementById('progressBar').style.backgroundColor="teal";                
            }else {
                document.getElementById('progressNumber').innerHTML = 'unable to pute';
            }
        }

    function uploadComplete(evt) {
            
            if( start < SIZE ) {
                chunk = blob.slice(start, end);

                uploadFile(chunk,part);

                start = end;
                end = start + BYTES_PER_CHUNK;
                part = part + 1;
                
            }
            document.getElementById("msgStatus").innerHTML = evt.target.responseText;
            //alert("plete");
            
        }

        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.");
        } 

The .PHP code here stores each chunk in the "uploads/" folder

session_start();

    $counter = 1;
    $_SESSION['counter'] = ($_REQUEST['num'] + 1);
  
  // changing the upload limits
   ini_set('upload_max_filesize', '100M');
   ini_set('post_max_size', '100M');
   ini_set('max_input_time', 300);
   ini_set('max_execution_time', 300);

    $filePath = "uploads/";
    if (!file_exists($filePath)) {
        if (!mkdir($filePath, 0777, true)) {
            echo "Failed to create $filePath";
        }
    }
    
    // $newfile = $newfile ."_". $_SESSION['counter'] .".mp4";
    $target_path = 'uploads/';
    $tmp_name = $_FILES['file']['tmp_name'];
    $filename = $_FILES['file']['name'];
    $newfile = substr(md5($_FILES['file']['name']), 0,10);
    $target_file = $target_path.$newfile;
    move_uploaded_file($tmp_name, $target_file.$_SESSION['counter'] );

B.U.T. the following .PHP code does not merge the chunks.

I do not really understand why it is not fopening for reading and writing... If you have any ways of merging the chunks into one whole video file, please post your response likewise here.

// count number of uploaded chunks
    $chunksUploaded = 0;
    for ( $i = 1; $i <= $_SESSION['counter']; $i++ ) {
        if ( file_exists( $target_file.$i ) ) {
             $chunksUploaded++;
        }
    }

    // if ($chunksUploaded === $num_chunks) {
    if ($chunksUploaded === $_SESSION['counter']) {

        // here you can reassemble chunks together 
        // for ($i = 1; $i <= $num_chunks; $i++) {
        for ($i = 1; $i <= $_SESSION['counter']; $i++) {
            // echo $i ."\n";
          $file = fopen($target_file.$i, 'rb');
          $buff = fread($file, 1048576);
          fclose($file);

          $final = fopen($target_file, 'ab');
          $write = fwrite($final, $buff);
          fclose($final);

          unlink($target_file.$i);
        }
        
    }

Hope you enjoy and thank you for your contribution too.

I have find the corect javascript code : (The PHP works fine)

window.BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder;
var blob;
var start;
var end;
var part;
var SIZE;
var BYTES_PER_CHUNK;
var xhr;
var chunk;

function sendRequest() {

    blob = document.getElementById('fileToUpload').files[0];
        BYTES_PER_CHUNK = 1048576; // 1MB chunk sizes.
        SIZE = blob.size;
        start = 0;                
        part = 0;
        end = BYTES_PER_CHUNK;

    chunk = blob.slice(start, end);
    uploadFile(chunk,part);
    start = end;
    end = start + BYTES_PER_CHUNK;
    part = part + 1;



};
//------------------------------------------------------------------------------------------------------------------------------------

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);


            var php_file =  "/upload.php"

            xhr.open("POST", php_file +"?"+"file="+file.name+"&num=" + parseInt(part) );
            xhr.onload = function(e) {
              //alert("loaded!");
              };

            xhr.setRequestHeader('Cache-Control','no-cache');
            xhr.send(fd);
            return;

};
//------------------------------------------------------------------------------------------------------------------------------------

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 pute';
            }
    };
//------------------------------------------------------------------------------------------------------------------------------------

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


    if( start < SIZE ) {
            chunk = blob.slice(start, end);

            uploadFile(chunk,part);

            start = end;
            end = start + BYTES_PER_CHUNK;
            part = part + 1;
            }
};
//------------------------------------------------------------------------------------------------------------------------------------


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.");
};
//------------------------------------------------------------------------------------------------------------------------------------

Change this:

       var blob;
    var start;
    var end;
    var part;
    var SIZE;
    var BYTES_PER_CHUNK;
    var xhr;


 function sendRequest() {

         blob = document.getElementById('fileToUpload').files[0];
      //  var file = document.getElementById('fileToUpload').files[0];

         BYTES_PER_CHUNK = 1048576; // 1MB chunk sizes.
         SIZE = blob.size;
        start = 0;                
        part = 0;
        end = BYTES_PER_CHUNK;



        while( start < SIZE ) {
                var chunk = blob.slice(start, end);
                //alert(chunk.size());
                 alert(start + ' - ' + end );
                uploadFile(chunk,part);
                //alert("here");

                 start = end;
                 end = start + BYTES_PER_CHUNK;
                part++;
            }

    }

I think the problem is with xhr.onload or fileareader.onload which are the asynchronous methods so you can not use them in a for/while loop that are synchronous events. if you want to then, you have to use recursive method and make sure you are streaming the data correctly. here is my answer, I tested it locally and it works fine for any large file. I used fetch instead of XMLHTTPRequest. I also will wait for the server to response with the "file is received" text and if after numberOfTries (which I considered 5 times) I don't receive the "file is received" then I will break the recursion. I am wondering if anyone else has other approaches tested. Please let me know for any better solution.

window.BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder;
const btnUpload= document.getElementById('button1')
var blob = document.getElementById('fileToUpload').files[0];
const BYTES_PER_CHUNK = 1048576; // 1MB chunk sizes.
const SIZE = blob.size;
const CHUNK_COUNT= parseInt(SIZE/BYTES_PER_CHUNK)
var start = 0;
var i =0;
var part = 0;
const numberOfTries=5



function uploadFile(start,chunkCount,CHUNK_SIZE,theFile,NumberofTry){
 // if you are done with recursive process then break
    if (start > chunkCount+1){
        fetch('/yourEndPoint',{
            // you don't need to send the body just header is enough to let the endpoint know that can close the stream pipeline 
            //"body":ev.target.result,
            "method":"POST",
            "headers":{
                "content-type":"application/octet-stream",
                "finished-stream":true
            }
        })
        return
    }

    var tmpBlob = theFile.slice(start*CHUNK_SIZE,(start+1)*CHUNK_SIZE)
    var newReader = new FileReader()
    newReader.onload = async ev=>{
        let fileName= start+'__'+ Math.random()*1000+'__'+theFile.name
         const serverResp= await fetch('/yourEndPoint',{
            "body":ev.target.result,
            "method":"POST",
            "headers":{
                "content-type":"application/octet-stream",
                "file-name":fileName
            }
        })
        let respText = await serverResp.text()
        if (respText!=='file is received' && NumberofTry<5){
            console.log('retry the upload again')
            uploadFile(start,chunkCount,CHUNK_SIZE,theFile,NumberofTry+1)
        }else if (respText!=='file is received' && NumberofTry===5){
            console.log('upload can not be plete...')
            return
        }
    
        uploadFile(start+1,chunkCount,CHUNK_SIZE,theFile,NumberofTry)
    
    }
    newReader.readAsArrayBuffer(tmpBlob)
}

btnUpload.addEventListener("click",()=>{
    uploadFile(i,CHUNK_COUNT,BYTES_PER_CHUNK,blob,numberOfTries)
})
发布评论

评论列表(0)

  1. 暂无评论