首页 > 编程语言 >PHP 中使用 TUS 协议来实现大文件的断点续传

PHP 中使用 TUS 协议来实现大文件的断点续传

时间:2022-11-25 12:38:24浏览次数:72  
标签:断点续传 tus 文件 TUS upload client PHP 上传 php


在现代网站应用中,上传文件是非常常见的。在任何语言中,通过使用一些工具,都可以实现文件上传的功能。但是,如果处理大文件上传的需求,还是有点麻烦的。

 

假如你此时正在上传一个很大的文件,大约一个小时过去了,进度是 90%。突然断网了或者浏览器崩溃了,上传的程序退出,你要再全部重新来过。真的很不爽,对不对?还有更让人郁闷的是,如果你的网速很慢,那么,无论你重来多少次,你都不可能上传成功。

 

在 PHP 中,我们可以尝试利用 tus 协议的断点续传功能来解决这个问题。

什么是 tus?

Tus 是一个基于 HTTP 的 文件断点续传开放协议。断点续传的意思是不管是用户自行中断,还是由于网络等原因的意外中断,都可以从中断的地方继续上传,而不用重新开始。

 

Tus 协议是在 2017 年5月被 Vimeo 采用的。

 

为什么用 tus?

引用 Vimeo 的博客:

 

我们之所以决定用 tus,是因为它能以简洁开放的形式,将文件上传的过程标准化。这种标准化有利于 API 的开发者更加专注于应用本身的逻辑,而非文件上传的过程。

 

使用这种方式上传的另一个好处是,你可以在笔记本上开始上传文件,然后又转到手机或者其他设备继续上传同一个文件,这可以极大地提升用户体验。

PHP 中使用 TUS 协议来实现大文件的断点续传_断点续传

 

开始

第一步,加载依赖。

$ composer require ankitpokhrel/tus-php

 

tus-php 是用于 tus 断点续传协议 v1.0.0 的一个的纯 PHP 框架,完美实现了 服务端与客户端的交互 。

更新: 现在 Vimeo 官方 PHP 库 的 v3 用的是 TusPHP。

 

创建一个处理请求的服务端

你可以像下面这样创建一个服务端.

// 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>

 

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

 

创建一个 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。这个插件可以在官方 tus-js-client 和 tus-php 服务器之间建立连接。也就是说我们可以使用 php 配合 js 来实现文件上传了。

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

 

 

分块上传

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

 

分块上传的完整例子

​https://github.com/ankitpokhrel/tus-php/tree/master/example/partial​

标签:断点续传,tus,文件,TUS,upload,client,PHP,上传,php
From: https://blog.51cto.com/u_13940603/5886323

相关文章

  • 深入了解PHP-FPM
    PHP-FPM(PHPFastCGIProcessManager)意:PHPFastCGI进程管理器,用于管理PHP进程池的软件,用于接受web服务器的请求。PHP-FPM提供了更好的PHP进程管理方式,可以有效控制内存......
  • php的对象传值与引用传值
    变量赋值与对象赋值对比<?php//声明一个变量并赋值$a=1;//将数据类型的值赋值给一个变量$b=$a;//修改$a的值$a=2;//$a和$b......
  • PHP字符逃逸导致的对象注入详解
    产生原因:序列化的字符串在经过过滤函数不正确的处理而导致对象注入,目前看到都是因为过滤函数放在了serialize函数之后,要是放在序列化之前应该就不会产生这个问题<?phpfuncti......
  • 令牌桶限流思路分享(PHP+Redis实现机制)
    一、场景描述 在开发接口服务器的过程中,为了防止客户端对于接口的滥用,保护服务器的资源,通常来说我们会对于服务器上的各种接口进行调用次数的限制。比如对于某个用户,他......
  • PHP 数组占用内存分析
    下面的做法会占用多大的内存?list($appid,$openid)=["testcontent","test"];测试:$m0=memory_get_usage();$k=range(1,200000);$m1=memory_get_usage();echoround((......
  • PHP高并发和大流量的解决方案
    PHP高并发和大流量的解决方案一、高并发的概念在互联网时代,并发,高并发通常是指并发访问。也就是在某个时间点,有多少个访问同时到来。二、高并发架构相关概念1、QPS(每秒......
  • php调取摄像头实现拍照功能
    最近做的商户后台要实现调取摄像头拍摄用户打卡照片的功能,找资料研究了下,终于黄天不负有心人,成功了,下面我分步骤将代码贴出来,希望能有帮助。代码有点多,但是每一步都很好理解......
  • 四种PHP异步执行的常用方式
    客户端与服务器端是通过HTTP协议进行连接通讯,客户端发起请求,服务器端接收到请求后执行处理,并返回处理结果。有时服务器需要执行很耗时的操作,这个操作的结果并不需要返回给客......
  • php与Redis实现一个100万用户的投票项目,实现实时查看投票情况?
    微信分享里总是有一些亲子活动,或者参加某些大赛需要进行投票,而面向的是所有人都可以参与,或者有限制一个人每天能投票同一个参与者3票之类的。。。这些应用场景有很多。假如......
  • PHP操作Redis
    redis的基本操作方法1.redis的连接://实例化redis$redis=newRedis();//连接$redis->connect('127.0.0.1',6379);//检测是否连接成功echo"Serverisrunning:".$r......