2012-03-13 99 views
4

我有一個文件上傳功能,並使用html5的切片api,我將每個文件切片爲1MB塊,但最終的結果導致文件被破壞。有時,最終結果會比原始文件小,有時即使是正確的大小,我仍然無法打開它。任何人有任何想法?或解決方案? 這是切片HTML5切片,結果文件損壞

 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代碼把文件時一起在服務器上我做錯了什麼(就像我沒有把它整理一下),但是任何人都知道如何做到這一點或最佳做法?除了上傳文件並將其合併之外,也可以在將文件寫入文件之前先將其保存在內存中。

+0

請提供您的上傳進度的功能。什麼是bars變量(一個div?)它沒有在腳本中定義。您還忽略了上傳變量是什麼(是一個數組?) – Martin 2012-03-15 20:34:25

+0

@Martin我剛剛更新了代碼,這幾乎是我有的所有代碼..減去HTML文件上傳的正常HTML標記的部分 – Harts 2012-03-15 22:02:58

回答

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

「我重寫了函數來上傳第一個塊,然後上傳第二個塊作爲對xhr.onreadystatechange等的響應」,如果我們這樣做了,是不是失去了一些分塊的目的,而不是同時上傳它們..你一個一個上傳。這會導致上傳速度變慢。 – Harts 2012-03-15 22:24:02

+0

如果您打算一次上傳同一文件的多個部分,您還需要告訴服務器哪個部分是哪個部分,因爲它們可能同時到達或不同步。服務器需要持有每件東西,直到它可以放在一起。這有點複雜。 – Martin 2012-03-15 22:34:54

+0

這是我正在尋找的答案類型。我需要同時上傳同一個文件的多個部分,或者更復雜的是我的項目,多個部分的不同文件一次..我正在尋找的是如何將這些部分按順序組合起來,並且無論如何,它在服務器內存第一或什麼.. – Harts 2012-03-15 22:57:48