jobtech/laravel-chunky

一个用于处理分块文件上传的Laravel管理器

3.0.0 2024-02-07 09:29 UTC

README


Logo

本包用于处理分块文件上传请求,以安全地保存分块文件,并在上传完成后,将所有分块合并为一个文件。

报告错误 · 请求功能

MIT License Build status StyleCI GitHub stars GitHub issues LinkedIn

目录

Laravel 兼容性

入门

Laravel chunky 是一个可以处理 Laravel 6.x, 7.x 和 8.x 中大型文件分块上传的包。其主要目标是自动处理上传请求(见下文的使用部分)并将所有分块保存到指定的磁盘。

一旦上传完成,该包将调度一个任务,将所有文件合并为一个,并保存到同一分块磁盘或另一个磁盘。

主要功能

  • 使用自定义保存磁盘和文件夹处理分块上传。
  • 使用自定义保存磁盘和文件夹处理文件合并。
  • 合并完成后,分块文件夹将自动清理。

安装

要将 Laravel Chunky 安装到您的项目中,您必须通过 composer 依赖它。

$ composer require jobtech/laravel-chunky

Laravel 使用包自动发现,并将自动注册 ChunkyServiceProvider。如果您使用的是低于 5.5 的 Laravel 版本或您未使用自动发现,请手动注册服务提供者

// config/app.php
[
  // [...]
  'providers' => [
      // [...]
      Jobtech\LaravelChunky\ChunkyServiceProvider::class,
  ]
];

您还可以为 Chunky 门面注册别名

// config/app.php
[
  // [...]
  'aliases' => [
      // [...]
      'Chunky' => Jobtech\LaravelChunky\Facades\Chunky::class,
  ]
];

配置

要发布配置文件,请运行以下命令

$ php artisan vendor:publish --provider="Jobtech\LaravelChunky\ChunkyServiceProvider" --tag="config"

Lumen

此包也可以与 Lumen 一起使用,只需在 bootstrap/app.php 中注册服务提供者即可

$app->register(Jobtech\LaravelChunky\ChunkyServiceProvider::class);

由于 Lumen 不包含 vendor:publish 命令,因此为了配置此包,请将配置文件复制到您的配置文件夹中并启用它

$app->configure('chunky');

使用

此包旨在让您完全控制分块上传,并通过辅助方法简单处理文件合并,以及为处理大型文件上传的控制器快速搭建提供一站式解决方案。

目前,此包不包含任何用于前端表单文件上传的包装器,但在 config/chunky.php 配置文件中,您可以找到两种将包与 DropzoneResumableJs 集成的方案。

分块

Laravel Chunky 将分块处理为一个 有序文件列表。这是一个 必须的 条件,如果上传了错误的文件索引,将会抛出异常以保证合并文件的完整性。一旦所有分块都上传完毕,并且合并过程正在执行时,将对所有分块进行另一个完整性检查。如果每个文件大小的总和低于原始文件大小,将再次抛出异常。因此,分块请求必须包含分块以及这些属性

  • 一个 索引:表示正在上传的当前块。第一个索引可以在配置文件中设置。
  • 文件大小:原始文件大小。将用于完整性检查。
  • 块大小:块文件大小。将用于完整性检查。

配置

// config/chunky.php
[

    /*
    |--------------------------------------------------------------------------
    | Default disks
    |--------------------------------------------------------------------------
    |
    | This option defines the disks on which to store the chunks from an upload
    | request as well as the final merged file. If you don't need to save the
    | files into a sub folder just set null as value.
    |
    */

    'disks' => [
        'chunks' => [
            'disk'   => env('CHUNKY_CHUNK_DISK'),
            'folder' => 'chunks',
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Default index
    |--------------------------------------------------------------------------
    |
    | This option defines if chunky should start counting the chunks indexes
    | from 0 (ChunkySettings::INDEX_ZERO) or 1 (ChunkySettings::INDEX_ONE). You
    | can override this feature with any number, but the indexes must always
    | be index + n or the integrity check for the chunks folder will throw an
    | exception.
    |
    */

    'index' => \Jobtech\LaravelChunky\ChunkySettings::INDEX_ZERO,

    /*
    |--------------------------------------------------------------------------
    | Additional options
    |--------------------------------------------------------------------------
    |
    | This option defines the additional settings that chunky should pass to
    | the `storeAs` method while saving chunks or the merged file. This can be
    | useful, for example, when storing public files in S3 storage.
    |
    */

    'options' => [
        'chunks' => [
            // 'visibility' => 'public'
        ],
    ],
];

块方法

如果您想从请求中手动保存一个块,可以使用 addChunk 方法。它接收上传的文件、块索引以及可选的文件夹名。如果没有传递文件夹,块仍然会存储在块的根子文件夹中。此文件夹将命名为上传文件的基名的slug。

此方法将返回一个 Jobtech\LaravelChunky\Chunk 对象,该对象实现了 Illuminate\Contracts\Support\Responsable 合约,因此您可以轻松返回JSON响应。如果请求有 Accept application/json 标头,对象将自动转换为 Jobtech\LaravelChunky\Http\Resources\ChunkResource 对象。此外,每次添加块时,都会触发 Jobtech\LaravelChunky\Events\ChunkAdded 事件。

// ...
$chunk = Chunky::addChunk(
    $request->file('your-file-key'),
    $request->input('your-index-key'),
    'folder-is-optional'
); 

return $chunk->hideFileInfo()->toResponse();
// This will return
// {
//   "data": {
//     "name": "my-very-big-file.ext",
//     "extension": "ext",
//     "index": 0,
//     "last": false
//   }
// }

return $chunk->showFileInfo()->toResponse();
// This will return
// {
//   "data": {
//     "name": "my-very-big-file.ext",
//     "extension": "ext",
//     "index": 0,
//     "last": false,
//     "file": "/path/to/my-very-big-file.ext",
//     "path": "/path/to"
//   }
// }

每次添加块时,都会触发 Jobtech\LaravelChunky\Events\ChunkDeleted 事件。

如果您尝试添加一个违反块文件夹完整性的块,将会抛出异常。例如

|- chunks
   |- folder
      |- 0_chunk.ext
      |- 1_chunk.ext
      |- 2_chunk.ext

Chunk::addChunk($chunk, 4); 

这将抛出 Jobtech\LaravelChunky\Exceptions\ChunksIntegrityException

如果您使用,例如,Dropzone,您可以阻止上传操作,在这种情况下,您将删除当前上传的块

Chunky::deleteChunks('chunks-folder');

每次删除块时,都会触发 Jobtech\LaravelChunky\Events\ChunkDeleted 事件。

该包包含一个方法,给定块文件夹,将返回一个排序后的集合。每个项目包含相对块路径和索引。

$chunks = Chunky::listChunks('chunks-folder-name');

foreach($chunks as $chunk) {
  /** @var \Jobtech\LaravelChunky\Chunk $chunk */
  print_r($chunk->toArray());
}

//  [
//    'index' => 0,
//    'path'  => '/path/to/chunks-folder-name/0_chunk.ext',
//    [...]
//  ],
//  [
//    'index' => 1,
//    'path'  => '/path/to/chunks-folder-name/1_chunk.ext',
//    [...]
//  ],
//  [
//    'index' => 2,
//    'path'  => '/path/to/chunks-folder-name/2_chunk.ext',
//    [...]
//  ],
//  ...

块请求

如果您想自动化块的上传和合并(需要 auto_merge 配置键的值为 true),可以使用 Jobtech\LaravelChunky\Http\Requests\AddChunkRequest 类。有关表单请求的更多信息,请参阅 官方文档

将表单请求包含在您的函数中,并简单地调用Chunky外观的 handle 方法。该包将自动处理上传并返回一个 Jobtech\LaravelChunky\Chunk 对象。

// Example with `auto_merge = false`

use Jobtech\LaravelChunky\Http\Requests\AddChunkRequest;

class UploadController extends Controller {
    // [...]

    public function chunkUpload(AddChunkRequest $request) {
       $chunk = Chunky::handle($request, 'folder-is-optional');

       if($chunk->isLast()) {
           // See section below for merge or 
           // implement your own logic
       }

       return $chunk->toResponse();
    }
}

合并处理器

如果您需要将块合并成一个单独的文件,可以调用 merge 函数,该函数将使用配置的合并处理程序将所有上传的块连接成一个单独的文件。

public function chunkUpload(AddChunkRequest $request) {
   $chunk = Chunky::handle($request, 'folder-is-optional');

   if($chunk->isLast()) {
       Chunky::merge('upload-folder', 'your/merge/file.ext');
   }

   return $chunk->toResponse();
}

一旦上传了最后一个块,并且 auto_merge 配置键的值为 true,该包将自动合并块。如果设置了这些选项,将在指定的连接和队列上调度 Jobtech\LaravelChunky\Jobs\MergeChunks 任务。

// config/chunky.php
[
   // [...]

   /*
   |--------------------------------------------------------------------------
   | Merge settings
   |--------------------------------------------------------------------------
   |
   | This option defines the merge handler that should be used to perform the
   | chunks merge once the upload is completed (automagically depending on
   | `auto_merge` config value.
   |
   | `connection` and `queue` keys define which queue and which connection
   | should be used for the merge job. If connection is null, a synchronous
   | job will be dispatched
   */
   
   'merge' => [
       'handler' => \Jobtech\LaravelChunky\Handlers\MergeHandler::class,
   
       'connection' => env('CHUNKY_MERGE_CONNECTION', 'sync'),
   
       'queue' => env('CHUNKY_MERGE_QUEUE'),
   ],
];

您可以手动调度作业(或者如果您没有使用 Jobtech\LaravelChunky\Http\Requests\AddChunkRequest 表单请求创建自己的)

use Jobtech\LaravelChunky\Http\Requests\AddChunkRequest;
use Jobtech\LaravelChunky\Jobs\MergeChunks;

class UploadController extends Controller {
    // [...]

    public function chunkUpload(AddChunkRequest $request) {
       $chunk = Chunky::handle($request, 'folder-is-optional');

       if($chunk->isLast()) {
            $job = new MergeChunks($request, 'chunks-folder', 'destination/path/to/merge.ext');

            dispatch(
                $job->onConnection('your-connection')
                    ->onQueue('your-queue')
            );
       }

       return $chunk->toResponse();
    }
}

一旦作业完成,将触发 Jobtech\LaravelChunky\Events\ChunksMerged 事件,以及一旦合并文件移动到目的地,将触发 Jobtech\LaravelChunky\Events\MergeAdded 事件。

自定义处理程序

如果您想集成自己的处理程序,请记住在您的类中实现 Jobtech\LaravelChunky\Contracts\MergeHandler 合约(或至少实现相同的方法),并更新相关的 handler 配置选项

use Jobtech\LaravelChunky\Contracts\MergeHandler;

class MyHandler implements MergeHandler {
    private ChunkyManager $manager;

    /**
     * @param \Jobtech\LaravelChunky\Contracts\ChunkyManager $manager
     * @return \Jobtech\LaravelChunky\Handlers\MergeHandler
     */
    public function setManager(ChunkyManager $manager): MergeHandler 
    {
        $this->manager = $manager;

        return $this;
    }
    
    /**
     * @return \Jobtech\LaravelChunky\Contracts\ChunkyManager
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function manager(): ChunkyManager
    {
        return $this->manager;
    }
    
    /**
     * @param \Jobtech\LaravelChunky\Http\Requests\AddChunkRequest $request
     * @param string $folder
     *
     * @return \Illuminate\Foundation\Bus\PendingDispatch|string
     */
    public function dispatchMerge(AddChunkRequest $request, string $folder)
    {
        // Your logic here
    }
    
    /**
     * @param string $chunks_folder
     * @param string $merge_destination
     *
     * @return string
     */
    public function merge(string $chunks_folder, string $merge_destination): string
    {
        // Your logic here
    }
    
    /**
     * @return \Jobtech\LaravelChunky\Contracts\MergeHandler
     */
    public static function instance(): MergeHandler
    {
        return new static();
    }
}       

测试

您可以使用PHP单元运行测试

$ vendor/bin/phpunit

如果您想设置自定义环境变量,可以添加一个 .env 文件用于自定义磁盘、队列或您需要的任何内容。测试默认设置一个临时本地磁盘。

CHUNKY_CHUNK_DISK=s3
CHUNKY_MERGE_DISK=public
CHUNKY_AUTO_MERGE=false
CHUNKY_MERGE_CONNECTION=redis
CHUNKY_MERGE_QUEUE=my-custom-queue

路线图

请参阅 开放问题,以获取功能建议(和已知问题的列表)。

我们正在努力工作

  • 集成前端块上传(不确定是否必要...有这么多包都做了这件事)。
  • 自定义连接,目前我们使用第三方包。
  • 更好的测试。
  • Laravel 5.5+ 兼容性。

变更日志

请参阅CHANGELOG.md了解最近有哪些变更。

贡献

此软件包包含基于php 8.1和composer 2.2的Docker容器。要启动它,只需运行make start。要进入容器shell,可以使用make shell

请参阅CONTRIBUTING.md获取更多详细信息。

许可证

本软件包遵循MIT许可。有关更多信息,请参阅LICENSE

联系方式

Jobtech dev团队 - dev@jobtech.it

致谢

Laravel Chunky是一个由JT极客团队用❤️制作的Laravel软件包。

感谢

我们使用了以下软件包来进行块连接

以及这个仓库的readme模板