HTML5切片,结果文件已损坏

时间:2012-03-13 18:49:57

标签: php html5 file-upload

我有一个文件上传功能,并使用html5中的slice api,我将每个文件切成1MB块,但最终结果导致文件被破坏。有时,最终结果比原始文件小,有时即使它的大小正确,我仍然无法打开它。有谁有任何想法?或解决方案? 这是切片的部分

        var uploaders = [];
        var i = 0;
        $(document).ready(function() {
            var progress = document.querySelector('progress');
            var bars = document.querySelector('#bars'); 
        });        

        //function for after the button is clicked, slice the file 
        //and call upload function
        function sendRequest() {       
            //clean the screen
            bars.innerHTML = '';
            var blob = document.getElementById('fileToUpload').files[0];
            var originalFileName = blob.name;
            const BYTES_PER_CHUNK = 1 * 1024 * 1024; // 10MB chunk sizes.
            const SIZE = blob.size;

            var start = 0;
            var end = BYTES_PER_CHUNK;

            while( start < SIZE ) {                    
                if (blob.webkitSlice) {
                  var chunk = blob.webkitSlice(start, end);
                } else if (blob.mozSlice) {
                  var chunk = blob.mozSlice(start, end);
                }       

                uploadFile(chunk, originalFileName);
                start = end;
                end = start + BYTES_PER_CHUNK;
            }
        }

        function uploadFile(blobFile, fileName) {
            var progress = document.createElement('progress');
            progress.min = 0;
            progress.max = 100;
            progress.value = 0;
            bars.appendChild(progress);   

            var fd = new FormData();
            fd.append("fileToUpload", blobFile);

            var xhr = new XMLHttpRequest();                
            xhr.open("POST", "upload.php"+"?"+"file="+fileName + i, true);
            i++;

            xhr.onload = function(e) {
                //make sure if finish progress bar at 100%
                progress.value = 100;

                //counter if everything is done using stack
                uploaders.pop();

                if (!uploaders.length) {
                    bars.appendChild(document.createElement('br'));
                    bars.appendChild(document.createTextNode('DONE :)'));
                }                  
            };

            // Listen to the upload progress for each upload.   
            xhr.upload.onprogress = function(e) {;
                if (e.lengthComputable) {
                    progress.value = (e.loaded / e.total) * 100;
                }
            };                 

            uploaders.push(xhr);
            xhr.send(fd);
        }      

这是用于接受二进制块的php文件

<?php

$target_path = "uploads/";
$tmp_name = $_FILES['fileToUpload']['tmp_name'];
$size = $_FILES['fileToUpload']['size'];
$name = $_FILES['fileToUpload']['name'];

$originalName = $_GET['file1'];

print_r("*******************************************\n");

print_r($originalName);
print_r("\n");

print_r($_FILES);
print_r("\n");

print_r("*******************************************\n");
$target_file = $target_path . basename($name);

//Result File
$complete = $originalName;
$com = fopen("uploads/".$complete, "ab");
error_log($target_path);

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


?>

我认为我在使用我的PHP代码将文件放在服务器上时做错了(比如我没有按顺序或其他东西),但是有人知道如何做到这一点或者最佳做法可能吗?而不是上传文件然后将其组合,可能先将其保存在内存中,然后再将其写入文件中。

1 个答案:

答案 0 :(得分:8)

一次上传文件的多个块,然后在最后合并。

const BYTES_PER_CHUNK = 1024 * 1024; // 1MB chunk sizes.
var slices;
var slices2;

function sendRequest() {
    var xhr;
    var blob = document.getElementById('fileToUpload').files[0];

    var start = 0;
    var end;
    var index = 0;

    // calculate the number of slices we will need
    slices = Math.ceil(blob.size / BYTES_PER_CHUNK);
    slices2 = slices;

    while(start < blob.size) {
        end = start + BYTES_PER_CHUNK;
        if(end > blob.size) {
            end = blob.size;
        }

        uploadFile(blob, index, start, end);

        start = end;
        index++;
    }
}

function uploadFile(blob, index, start, end) {
    var xhr;
    var end;
    var fd;
    var chunk;
    var url;

    xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function() {
        if(xhr.readyState == 4) {
            if(xhr.responseText) {
                alert(xhr.responseText);
            }

            slices--;

            // if we have finished all slices
            if(slices == 0) {
                mergeFile(blob);
            }
        }
    };

    if (blob.webkitSlice) {
        chunk = blob.webkitSlice(start, end);
    } else if (blob.mozSlice) {
        chunk = blob.mozSlice(start, end);
    }

    fd = new FormData();
    fd.append("file", chunk);
    fd.append("name", blob.name);
    fd.append("index", index);

    xhr.open("POST", "upload.php", true);
    xhr.send(fd);
}

function mergeFile(blob) {
    var xhr;
    var fd;

    xhr = new XMLHttpRequest();

    fd = new FormData();
    fd.append("name", blob.name);
    fd.append("index", slices2);

    xhr.open("POST", "merge.php", true);
    xhr.send(fd);
}

使用upload.php收集碎片:

if(!isset($_REQUEST['name'])) throw new Exception('Name required');
if(!preg_match('/^[-a-z0-9_][-a-z0-9_.]*$/i', $_REQUEST['name'])) throw new Exception('Name error');

if(!isset($_REQUEST['index'])) throw new Exception('Index required');
if(!preg_match('/^[0-9]+$/', $_REQUEST['index'])) throw new Exception('Index error');

if(!isset($_FILES['file'])) throw new Exception('Upload required');
if($_FILES['file']['error'] != 0) throw new Exception('Upload error');

$target = "uploads/" . $_REQUEST['name'] . '-' . $_REQUEST['index'];

move_uploaded_file($_FILES['file']['tmp_name'], $target);

// Might execute too quickly.
sleep(1);

使用merge.php合并碎片:

if(!isset($_REQUEST['name'])) throw new Exception('Name required');
if(!preg_match('/^[-a-z0-9_][-a-z0-9_.]*$/i', $_REQUEST['name'])) throw new Exception('Name error');

if(!isset($_REQUEST['index'])) throw new Exception('Index required');
if(!preg_match('/^[0-9]+$/', $_REQUEST['index'])) throw new Exception('Index error');

$target = "uploads/" . $_REQUEST['name'];
$dst = fopen($target, 'wb');

for($i = 0; $i < $_REQUEST['index']; $i++) {
    $slice = $target . '-' . $i;
    $src = fopen($slice, 'rb');
    stream_copy_to_stream($src, $dst);
    fclose($src);
    unlink($slice);
}

fclose($dst);