合并PHP中的文件块

Col*_*ark 5 javascript file-upload chunks

出于教育目的,我想创建文件块上传。你们怎么知道什么时候全部块都上传了?

我尝试从中移出块temp并重命名它们,以便它们以正确的顺序排列,然后与最后一块合并在一起。但是,我想发送的最后一块不是收到的最后一块。因此fopen(),由于尚未创建块,因此块上失败了,我得到的最终文件的大小恰好是最后一个块的大小。

我相信我可以使用.onloadon事件逐个发送块xhr,这样我什至不必将它们从PHP temp移走,但是我想知道是否有不同的解决方案。

一些基本的代码可以取悦您:

function upload(file) {
  var BYTES_PER_CHUNK = parseInt(2097152, 10),
  size = file.size,
  NUM_CHUNKS = Math.max(Math.ceil(SIZE / BYTES_PER_CHUNK), 1),
  start = 0, end = BYTES_PER_CHUNK, num = 1;

  var chunkUpload = function(blob) {
    var fd = new FormData();
    var xhr = new XMLHttpRequest();

    fd.append('upload', blob, file.name);
    fd.append('num', num);
    fd.append('num_chunks', NUM_CHUNKS);
    xhr.open('POST', '/somedir/upload.php', true);
    xhr.send(fd);
  }

  while (start < size) {
    chunkUpload(file.slice(start, end));
    start = end;
    end = start + BYTES_PER_CHUNK;
    num++;
  }
}
Run Code Online (Sandbox Code Playgroud)

和PHP:

$target_path = ROOT.'/upload/';

$tmp_name = $_FILES['upload']['tmp_name'];
$filename = $_FILES['upload']['name'];
$target_file = $target_path.$filename;
$num = $_POST['num'];
$num_chunks = $_POST['num_chunks'];

move_uploaded_file($tmp_name, $target_file.$num);

if ($num === $num_chunks) {
  for ($i = 1; $i <= $num_chunks; $i++) {

    $file = fopen($target_file.$i, 'rb');
    $buff = fread($file, 2097152);
    fclose($file);

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

    unlink($target_file.$i);
  }
}
Run Code Online (Sandbox Code Playgroud)

Jai*_*now 5

抱歉我之前的评论,我误解了一个问题。这个问题很有趣,玩起来很有趣。

你要找的表达是这样的:

$target_path = ROOT.'/upload/';

$tmp_name = $_FILES['upload']['tmp_name'];
$filename = $_FILES['upload']['name'];
$target_file = $target_path.$filename;
$num = $_POST['num'];
$num_chunks = $_POST['num_chunks'];

move_uploaded_file($tmp_name, $target_file.$num);

// count ammount of uploaded chunks
$chunksUploaded = 0;
for ( $i = 1, i <= $num; $i++ ) {
    if ( file_exists( $target_file.$i ) ) {
         ++$chunksUploaded;
    }
}

// and THAT's what you were asking for
// when this triggers - that means your chunks are uploaded
if ($chunksUploaded === $num_chunks) {

    /* here you can reassemble chunks together */
    for ($i = 1; $i <= $num_chunks; $i++) {

      $file = fopen($target_file.$i, 'rb');
      $buff = fread($file, 2097152);
      fclose($file);

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

      unlink($target_file.$i);
    }
}
Run Code Online (Sandbox Code Playgroud)

并且必须提到这一点:

我的版本的脆弱点 - 是你期望文件的时候

  • 'tmp-1',

  • 'tmp-2',

  • 'tmp-3'

但是,让我们假设在发送 'tmp-2' 之后我们被打断了——tmp-2 污染了 tmp 文件夹,它会干扰以后使用相同文件名的上传——这将是一个睡眠炸弹。

为了解决这个问题 - 您必须找到一种方法将 tmp 更改为更原始的内容。

  • 'tmp-ABCew-1',

  • 'tmp-ABCew-2',

  • 'tmp-ABCew-3'

好一点 - 'ABCew' 可以被称为 'chunksSessionId' - 你在发送你的 POST 时提供它,你随机制作它。尽管如此,冲突还是可能的——因为随机名称的空间会耗尽。您可以在方程式中添加时间 - 例如 - 您可以看到

  • 'tmp-ABCew-2016-03-17-00-11-22--1',

  • 'tmp-ABCew-2016-03-17-00-11-22--2',

  • 'tmp-ABCew-2016-03-17-00-11-22--3'

更具抗冲突性,但难以实施 - 这里有一大堆蠕虫 - 客户端日期和时间由客户端控制并且可能被欺骗 - 这些数据是不可靠的。

因此,使 tmp-name 唯一是一项复杂的任务。设计一个使其可靠的系统 - 是一个有趣的问题 ^ ^ 你可以玩这个。