PHP中使用 TUS 协议来实现可恢复文件上传

曾经尝试过用PHP上传大文件吗?想知道您是否能够从上次中断的地方继续上传,而不会在遇到任何中断的状况下再次从新上传整个数据?若是您以为这个场景很熟悉,请接着往下阅读。php

文件上传是咱们几乎全部现代Web项目中的一项很常见的任务。在任何语言中,有了可用的工具,实现文件上传功能都不难。可是,对于大文件上传,这个事情仍是有些让人头疼。html

假设您正在尝试上传至关大的文件。您已经等待了一个多小时,上传率为90%。而后忽然,您的链接断开或浏览器崩溃。上传被停止,您须要从头开始上传。这很使人沮丧,不是吗?更糟糕的是,若是您的链接速度较慢,就像世界上许多地方同样,不管尝试多少次,每次都只能上传第一部份内容。不管你重来多少次,你都不可能上传成功。你的心态扛得住嘛?!?!nginx

                                    

在这篇文章中,咱们将尝试经过使用tus协议以可恢复块的形式上传文件来解决PHP中的此问题。laravel

首先什么是tus?

Tus是用于可恢复文件上传的基于HTTP的开放协议。可恢复意味着能够在中断的地方继续工做,而不会在遇到任何中断的状况下再次从新上传整个数据。若是用户但愿暂停,则中断可能会发生,或者在网络问题或服务器中断的状况下,偶然发生。git

Vimeo于2017年5月 采用了 Tus协议。

为何是tus?

引用Vimeo的博客github

咱们之因此决定在上载堆栈中使用tus,是由于tus协议以简洁明了的方式标准化了上载文件的过程。这种标准化将使API开发人员能够将更多的精力放在其特定于应用程序的代码上,而没必要将精力放在上传过程自己上。

经过这种方式上传文件的另外一个主要好处是,您能够从笔记本电脑开始上传,甚至能够继续从移动设备或任何其余设备上载相同的文件,这能够极大地提高用户体验。redis

基本的Tus架构

入门

从添加咱们的依赖关系开始sql

$ composer require ankitpokhrel/tus-php复制代码

tus-php是用于tus可断续上传协议v1.0.0的纯PHP框架 服务器和客户端实现
tus-php-for用于tus可恢复上载协议v1.0.0的纯PHP服务器和客户端 github.comshell

更新:Vimeo如今在其 官方PHP库的 v3 中将TusPHP 用于Vimeo API

建立一个服务器来处理咱们的请求

这就是简单服务器的外观。vim

// server.php

$server   = new \TusPhp\Tus\Server('redis');
$response = $server->serve();

$response->send();

exit(0); // 从当前的PHP进程退出.复制代码

您须要配置服务器以响应特定的端点。例如,在Nginx中,您能够执行如下操做:

# nginx.conf

location /files {
    try_files $uri $uri/ /path/to/server.php?$query_string;
}复制代码

假设服务器的URL是http://server.tus.local。 所以,基于上面的nginx配置,咱们可使用http://server.tus.local/files访问tus端点。

如今,咱们可使用如下RESTful端点。

# 收集有关服务器当前配置的信息\
OPTIONS /files

# 检查指定的上传\
HEAD /files/{upload-key}

# 建立一个新的上传\
POST /files

# 建立一个新的上传\
PATCH /files/{upload-key}

# 建立一个新的上传\
DELETE /files/{upload-key}复制代码

查看协议详细信息以获取有关端点的更多信息。

若是您使用的是Laravel之类的框架,则不须要修改服务器配置,而能够在框架路由文件中定义到全部基于tus端点的路由。这个咱们将在另外一个教程中对此进行详细介绍。

使用 tus-php 客户端处理上传

一旦服务器就位,就可使用客户端上载文件。让咱们首先建立一个简单的HTML表单以获取用户输入。

<form action="upload.php" method="post" enctype="multipart/form-data">
    <input type="file" name="tus_file" id="tus-file" />
    <input type="submit" value="Upload" />
</form>复制代码

提交表单后,咱们须要按照几个步骤来处理上传。

  1. 建立一个tus-php客户端对象
// Tus client

$client = new \TusPhp\Tus\Client('http://server.tus.local');复制代码
上面代码中的第一个参数是您的 tus 服务器端点。

2. 使用文件元数据初始化客户端

为了确保上传文件的惟一性,咱们须要使用一些标识符来识别即将到来的请求中的上传。为此,咱们将必须生成一个惟一的上传密钥,该密钥可在之后用于恢复上传。您能够提供一个上传密钥,也可让系统本身生成一个密钥。

// 设置上传密钥和文件元数据

$client->setKey($uploadKey)
    ->file($_FILES['tus_file']['tmp_name'], 'your file name');复制代码

若是您未明确提供上传密钥,能够这样写,系统会自动生成:

$client->file($_FILES['tus_file']['tmp_name'], 'your file name');

$uploadKey = $client->getKey(); // Unique upload key复制代码

3. 分块上传文件

// $chunkSize 是以字节为单位的,例如 5000000 等于 5 MB

$bytesUploaded = $client->upload($chunkSize);复制代码

下次,当您要上传另外一个块时,可使用相同的上传密钥继续。

// 在下一个请求中恢复文件

$bytesUploaded = $client->setKey($uploadKey)->upload($chunkSize);复制代码

文件所有上传完成后,默认状况下,服务器会使用 sha256 来校验文件总和,以确保不会有丢失的文件。

使用 tus-js-client 客户端处理文件上传

tus 协议的团队还开发了一个模块化的文件上传插件 Uppy。您可使用uppy将正式的tus-js-clienttus-php服务器无缝集成。这意味着咱们正在使用服务器的php实现和客户端的js实现。

uppy.use(Tus, {
  endpoint: 'https://server.tus.local/files/', // 你的 tus 服务器
  resume: true,
  autoRetry: true,
  retryDelays: [0, 1000, 3000, 5000]
})复制代码

更多细节能够查看uppy的文档,还有些例子能够供你参考。

分块上传

tus-php 服务器支持 concatenation 扩展,而且能够把屡次上传的文件合为一个文件。所以,咱们能够在客户端支持并行上传以及非连续的分块文件上传。

使用 tus-php 实现分块上传

tus-partial-upload.php

<?php

// 文件惟一标识码
$uploadKey = uniqid();

$client->setKey($uploadKey)->file('/path/to/file', 'chunk_a.ext');

// 从第 1000  个字节开始上传 10000 字节
$bytesUploaded = $client->seek(1000)->upload(10000);
$chunkAkey     = $client->getKey();

// 从 第 0 个字节开始上传 10000 字节
$bytesUploaded = $client->setFileName('chunk_b.ext')->seek(0)->upload(1000);
$chunkBkey     = $client->getKey();

// 从第 11000 个字节  (10000 +  1000) 开始上传剩余的字节
$bytesUploaded = $client->setFileName('chunk_c.ext')->seek(11000)->upload();
$chunkCkey     = $client->getKey();

// 把分块上传的文件组合起来
$client->setFileName('actual_file.ext')->concat($uploadKey, $chunkAkey, $chunkBkey, $chunkCkey);复制代码

分块上传的完整例子 在这里.

最后说一下TUS 协议

核心协议

核心协议描述如何继续中断的上传。这里假定你已经有一个用于上传的 RUL ,这个 URL 一般是由扩展协议 Creation建立。

全部客户端和服务端必须实现核心协议。

协议没有描述 RUL 的结构,而是留给协议的实现来决定。本文中全部展现的 URL 仅用于举例。

此外,认证和受权的实现也留给服务端来决定。

示例

用一个请求头指明应当从什么地方开始续传上传。

如下示例展现中断位置由70变为100

请求

HEAD /files/24e533e02ec3bc40c387f1a0e460e216 HTTP/1.1

Host: http://tus.example.org

Tus-Resumable: 1.0.0

响应

HTTP/1.1 200 OK

Upload-Offset: 70

Tus-Resumable: 1.0.0

对于给定的中断位置,客户端使用 PATCH 方法来续传。

请求

PATCH /files/24e533e02ec3bc40c387f1a0e460e216 HTTP/1.1

Host: http://tus.example.org

Content-Type: application/offset+octet-stream

Content-Length: 30

Upload-Offset: 70

Tus-Resumable: 1.0.0

[remaining 30 bytes]

响应

HTTP/1.1 204 No Content

Tus-Resumable: 1.0.0

Upload-Offset: 100

因为 tus-php 项目 自己还出于初级阶段,某些部分未来可能会有改动。在 example 文件夹里,有三个不一样的例子供你参考。若是任何问题或者建议,欢迎留言交流。

Happy Coding!

更多学习内容请访问从码农成为架构师的修炼之路

以上内容但愿帮助到你们,不少PHPer在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提高,对此我整理了一些资料,包括但不限于:分布式架构、高可扩展、高性能、高并发、服务器性能调优、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点高级进阶干货须要的能够免费分享给你们,须要的能够加入个人官方群点击此处

相关文章
相关标签/搜索