PHP中使用 TUS 协议来实现可恢复文件上传
曾经尝试过用PHP上传大文件吗?想知道您是否可以从上次中断的地方继续上传,而不会在遇到任何中断的情况下再次重新上传整个数据?如果您觉得这个场景很熟悉,请接着往下阅读。
文件上传是我们几乎所有现代Web项目中的一项很常见的任务。在任何语言中,有了可用的工具,实现文件上传功能都不难。但是,对于大文件上传,这个事情还是有些让人头疼。
假设您正在尝试上传相当大的文件。您已经等待了一个多小时,上传率为90%。然后突然,您的连接断开或浏览器崩溃。上传被中止,您需要从头开始上传。这很令人沮丧,不是吗?更糟糕的是,如果您的连接速度较慢,就像世界上许多地方一样,无论尝试多少次,每次都只能上传第一部分内容。无论你重来多少次,你都不可能上传成功。你的心态扛得住嘛?!?!
在这篇文章中,我们将尝试通过使用tus协议以可恢复块的形式上传文件来解决PHP中的此问题。
首先什么是tus?
Tus是用于可恢复文件上传的基于HTTP的开放协议。可恢复意味着可以在中断的地方继续工作,而不会在遇到任何中断的情况下再次重新上传整个数据。如果用户希望暂停,则中断可能会发生,或者在网络问题或服务器中断的情况下,偶然发生。
为什么是tus?
引用Vimeo的博客:
我们之所以决定在上载堆栈中使用tus,是因为tus协议以简洁明了的方式标准化了上载文件的过程。这种标准化将使API开发人员可以将更多的精力放在其特定于应用程序的代码上,而不必将精力放在上传过程本身上。
通过这种方式上传文件的另一个主要好处是,您可以从笔记本电脑开始上传,甚至可以继续从移动设备或任何其他设备上载相同的文件,这可以极大地提升用户体验。
图片:基本的Tus架构
入门
从添加我们的依赖关系开始
$ composer require ankitpokhrel/tus-php
tus-php是用于tus可断续上传协议v1.0.0的纯PHP框架 服务器和客户端实现。
tus-php-for用于tus可恢复上载协议v1.0.0的纯PHP服务器和客户端 github.com
更新:Vimeo现在在其官方PHP库的v3中将TusPHP用于Vimeo API。
创建一个服务器来处理我们的请求
这就是简单服务器的外观。
// 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。您可以使用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]
})
更多细节可以查看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!
PHP中使用 TUS 协议来实现可恢复文件上传的更多相关文章
- django中使用FastDFS分布式文件系统接口代码实现文件上传、下载、更新、删除
运维使用docker部署好之后FastDFS分布式文件系统之后,提供给我接口如下: fastdfs tracker 192.168.1.216 192.168.1.217 storage 192.16 ...
- java中TCP两个例子大写服务器和文件上传
大写服务器的实例: package com.core.net; import java.io.BufferedReader; import java.io.BufferedWriter; import ...
- 【翻译】tus----一个可续传文件上传的开放协议
tus tus是一个可续穿文件上传协议,它以Http协议为载体,统一了一个文件断点续传的标准. 这篇文章翻译自https://tus.io/ 目前该协议版本信息如下: Version: 1.0.0 ( ...
- spring mvc中的文件上传
使用commons-fileupload上传文件所需要的架包有:commons-fileupload 和common-io两个架包支持,可以到Apache官网下砸. 在配置文件spring-mvc.x ...
- 【SpringMVC学习08】SpringMVC中实现文件上传
之前有写过一篇struts2实现的文件上传,这一篇博文主要来总结下springmvc实现文件上传的步骤.首先来看一下单个文件的上传,然后再来总结下多个文件上传. 1. 环境准备 springmvc上传 ...
- ASP.NET CORE RAZOR :将文件上传至 ASP.NET Core 中的 Razor 页面
本部分演示使用 Razor 页面上传文件. 本教程中的 Razor 页面 Movie 示例应用使用简单的模型绑定上传文件,非常适合上传小型文件. 有关流式传输大文件的信息,请参阅通过流式传输上传大文件 ...
- 在WebBrowser中通过模拟键盘鼠标操控网页中的文件上传控件(转)
引言 这两天沉迷了Google SketchUp,刚刚玩够,一时兴起,研究了一下WebBrowser. 我在<WebBrowser控件使用技巧分享>一文中曾谈到过“我现在可以通过WebBr ...
- RPC基于http协议通过netty支持文件上传下载
本人在中间件研发组(主要开发RPC),近期遇到一个需求:RPC基于http协议通过netty支持文件上传下载 经过一系列的资料查找学习,终于实现了该功能 通过netty实现文件上传下载,主要在编解码时 ...
- 转:【专题十一】实现一个基于FTP协议的程序——文件上传下载器
引言: 在这个专题将为大家揭开下FTP这个协议的面纱,其实学习知识和生活中的例子都是很相通的,就拿这个专题来说,要了解FTP协议然后根据FTP协议实现一个文件下载器,就和和追MM是差不多的过程的,相信 ...
随机推荐
- 查看日志文件常用命令:tail,cat,tac,head,echo
linux查看日志文件内容命令tail.cat.tac.head.echo tail -f test.log你会看到屏幕不断有内容被打印出来. 这时候中断第一个进程Ctrl-C, ---------- ...
- python用直方图规定化实现图像风格转换
以下内容需要直方图均衡化.规定化知识 均衡化:https://blog.csdn.net/macunshi/article/details/79815870 规定化:https://blog.csdn ...
- Python实用笔记 (18)面向对象编程——类和实例
类和实例 面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各 ...
- 从数据库中取时间值,遇到:java.sql.Timestamp cannot be cast to java.lang.Long
将 java.sql.Timestamp 类型转换为 java.util.Date 类型.二者其实是父子关系,直接 Date d = (Date)时间戳 就可以了. Date d = (Date)时间 ...
- TypeScript学习——数组、元组、接口(2)
数组 数组类型注解 const numberArr: (number | string)[] = [1, '2', 3]; //既可以是number 也可以是string const stringAr ...
- tableau入门学习笔记--分页功能
最近在使用tableau来制作报表,对于tableau也是第一次接触并使用,每天学习些新的功能来记录在博客里,给他人方便,也给自己方便 tableau分页功能 很多时候由于工作表过长而出现拖拽条,如果 ...
- 资深阿里程序员一一为你解刨Web前端知识体系结构,付出与收获成正比!
只要接触过前端,都会指导web前端的知识主要由三部分组成:分别为静态html,样式css,动态javascript(简称js)这三大部分组成.其三部分组成的一个体系的复杂程度不亚于其他一门技术的复杂程 ...
- Centos 6.4 安装/卸载 Adobe Reader 9(.bin .tar.bz2 rpm 包)
一.To install Adobe Reader 9.1 using a tarball installer 1. Open a terminal window. 2. Change directo ...
- Vmware - 安装并启动 Centos 8
下载 Linux 安装包 https://mirrors.aliyun.com/centos/8.1.1911/isos/x86_64/ 不同版本的 Centos https://mirrors.al ...
- js 图片压缩上传(base64位)以及上传类型分类
一.input file上传类型 1.指明只需要图片 <input type="file" accept='image/*'> 2.指明需要多张图片 <input ...