загрузка чанков в Dropzone: какие обратные вызовы я должен использовать для вызова ajax и обработки файлов / чанков? - PullRequest
0 голосов
/ 16 октября 2018

Я пытаюсь правильно реализовать загрузку чанка с помощью dropzone js и php.Моя главная проблема: где мне делать вызовы ajax?Обычно (без чанков) вы просто указываете параметр URL.Но я думаю, что с чанками этого недостаточно, потому что будет только 1 ajax-вызов, но в идеале чанков будет несколько, и нам придется ждать всех, прежде чем собирать весь файл с помощью php.Итак, по вашему опыту, каково правильное место для вызова ajax или вызовов?(Может быть, это способ сделать только один звонок?).Вот простой фрагмент моего текущего кода:

window['dropzone' + panel_index] = new Dropzone(
  selector,
  {
    url: ajax_url + '?action=uploadfile'
    ,addRemoveLinks: true
    ,maxFiles: 5
    ,maxFilesize: maxfilesize
    ,uploadMultiple:false
    ,parallelUploads: 1
    ,chunking:true
    ,forceChunking:true
    ,chunkSize:10485760 // 10Mb
    ,retryChunks: true   // retry chunks on failure
    ,retryChunksLimit: 3
    ,chunksUploaded:function(file, done){
      // called only once, when chunks are finished > do something ajax > php to reassemble the file?
      done();
    }
    ,params: function(file, xhr, chunk){

      // called once per every chunk > do something ajax > php?

      if(chunk){
        $.extend(true, p, {
          dzuuid: chunk.file.upload.uuid,
          dzchunkindex: chunk.index,
          dztotalfilesize: chunk.file.size,
          dzchunksize: this.options.chunkSize,
          dztotalchunkcount: chunk.file.upload.totalChunkCount,
          dzchunkbyteoffset: chunk.index * this.options.chunkSize
        });
      }

      return p;
    }// params


    ,init: function(){
      this.on('success', function(newfile){
        // called after chunksUploaded > do something ajax > php?
      });// onsuccess

      this.on('uploadprogress', function(file, progress, bytesent){
        // called continuously
      })
    }// dropzone init option
  }// dropzone options
);

Ответы [ 2 ]

0 голосов
/ 22 мая 2019

Я делаю это внутри опции chunksUploaded.После того, как Dropzone загрузил для меня все чанки, я выполняю еще один ajax-вызов внутри chunksUploaded для отдельного сценария PHP из моего загрузчика, который объединяет все загруженные файлы.

Итак, каждая загрузка чанкавызывает тот же URL-адрес Dropzone, который загружает порцию в PHP:

<?php

/* ========================================
  VARIABLES
======================================== */

// chunk variables
$fileId = $_POST['dzuuid'];
$chunkIndex = $_POST['dzchunkindex'] + 1;
$chunkTotal = $_POST['dztotalchunkcount'];

// file path variables
$ds = DIRECTORY_SEPARATOR;
$targetPath = dirname( __FILE__ ) . "{$ds}uploads{$ds}";
$fileType = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
$fileSize = $_FILES["file"]["size"];
$filename = "{$fileId}-{$chunkIndex}.{$fileType}";
$targetFile = $targetPath . $filename;

/* ========================================
  DEPENDENCY FUNCTIONS
======================================== */

$returnResponse = function ($info = null, $filelink = null, $status = "error") {
  die (json_encode( array(
    "status" => $status,
    "info" => $info,
    "file_link" => $filelink
  )));
};

/* ========================================
  VALIDATION CHECKS
======================================== */

// I deleted a bunch of validation that goes here to keep the code short

/* ========================================
  CHUNK UPLOAD
======================================== */

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

// Be sure that the file has been uploaded
if ( !file_exists($targetFile) ) $returnResponse("An error occurred and we couldn't upload the requested file.");
chmod($targetFile, 0777) or $returnResponse("Could not reset permissions on uploaded chunk.");

$returnResponse(null, null, "success");

Затем chunksUploaded выполняет еще один ajax-вызов для сценария php-конкатенации (обратите внимание, как я использую идентификатор загрузки Drop Zone каксерийный номер для определения, какие куски файлов принадлежат друг другу):

<?php

// get variables
$fileId = $_GET['dzuuid'];
$chunkTotal = $_GET['dztotalchunkcount'];

// file path variables
$ds = DIRECTORY_SEPARATOR;
$targetPath = dirname( __FILE__ ) . "{$ds}uploads{$ds}";
//$fileType = strtolower(pathinfo($_GET['fileName'], PATHINFO_EXTENSION));
$fileType = $_GET['fileName'];

/* ========================================
  DEPENDENCY FUNCTIONS
======================================== */

$returnResponse = function ($info = null, $filelink = null, $status = "error") {
  die (json_encode( array(
    "status" => $status,
    "info" => $info,
    "file_link" => $filelink
  )));
};

/* ========================================
  CONCATENATE UPLOADED FILES
======================================== */

// loop through temp files and grab the content
for ($i = 1; $i <= $chunkTotal; $i++) {

  // target temp file
  $temp_file_path = realpath("{$targetPath}{$fileId}-{$i}.{$fileType}") or $returnResponse("Your chunk was lost mid-upload.");

  // copy chunk
  $chunk = file_get_contents($temp_file_path);
  if ( empty($chunk) ) $returnResponse("Chunks are uploading as empty strings.");

  // add chunk to main file
  file_put_contents("{$targetPath}{$fileId}.{$fileType}", $chunk, FILE_APPEND | LOCK_EX);

  // delete chunk
  unlink($temp_file_path);
  if ( file_exists($temp_file_path) ) $returnResponse("Your temp files could not be deleted.");

}

// and by the time you get here you should have your concatenated file in the "uploads" folder to do with what you want
0 голосов
/ 16 октября 2018

Короче говоря, единственный обратный вызов, необходимый для обработки фрагмента на стороне обслуживания, - это функция, переданная в params.Примерно так (извлекать из моего кода):

,params: function(files, xhr, chunk){

  var p = { // $_POST
    app_type: 'configurator'
    ,app_code: manager.code
    ,file_types: filetypes
    ,max_filesize: maxfilesize
    ,upf: upf
  }

  if(chunk){
    $.extend(true, p, {
      dzuuid: chunk.file.upload.uuid,
      dzchunkindex: chunk.index,
      dztotalfilesize: chunk.file.size,
      dzchunksize: this.options.chunkSize,
      dztotalchunkcount: chunk.file.upload.totalChunkCount,
      dzchunkbyteoffset: chunk.index * this.options.chunkSize
    });
  }

  return p;
}// params

Вызываемый url - это просто общий URL-адрес в dropzone.Он вызывается один раз для каждого чанка.

В php вы можете использовать $ _POST ['dzchunkindex'] для сохранения чанков с измененным именем, например.

// do all the sanitisation tasks, then:
$target_chunk = $this->target_path . DS . $filename . $chunk_index;
// and then do the file saving tasks

После того, как все чанкиобработано, у вас будет столько же файлов, сколько порций на вашем сервере.Затем в той же функции проверьте, равен ли индекс чанка dztotalchunkcount - 1 (в других мирах, если текущий чанк является последним), и в этом случае также объедините все чанки в одном файле.Пример:

if($chunk_index == $total_chunks - 1){
  $final = fopen($target_file, 'wb');   // Open for write and start from beginning of file
  for ($i = 0; $i < $total_chunks; $i++) {
    $file = fopen($target_file.$i, 'rb');
    while($buff = fread($file, 4096)){ fwrite($final, $buff); }
    fclose($file);
    unlink($target_file.$i);
  }
  fclose($final);
}
...