inflection-points / tus-php
纯PHP服务器和客户端,用于tus可暂停上传协议v1.0.0
资助包维护!
paypal.me/pokharelankit
Requires
- php: ^7.2.5 || ^8.0
- ext-json: *
- guzzlehttp/guzzle: ^6.3 || ^7.0
- nesbot/carbon: ^1.26.3 || ^2.0
- predis/predis: ^1.1 || ^2.0
- ramsey/uuid: ^3.7 || ^4.0
- symfony/console: ^5.0 || ^6.0
- symfony/event-dispatcher: ^5.0 || ^6.0
- symfony/http-foundation: ^5.0.7 || ^6.0
- symfony/mime: ^5.0.9 || ^6.0
Requires (Dev)
- ext-pcntl: *
- friendsofphp/php-cs-fixer: ^3.0
- mockery/mockery: ^1.3.4 || ^1.4.2
- phpunit/phpunit: ^8.5.19 || ^9.4
This package is auto-updated.
Last update: 2022-10-07 21:12:44 UTC
README
使用tus可暂停上传协议v1.0.0在PHP中进行可暂停文件上传
Medium文章 ⚡ Laravel & Lumen集成 ⚡ Symfony集成 ⚡ CakePHP集成 ⚡ WordPress集成
tus 是一种基于HTTP的可暂停文件上传协议。可暂停意味着在出现中断的情况下,您可以继续上传而无需重新上传整个数据。中断可能是用户有意识地暂停,也可能是由于网络问题或服务器故障而意外发生。
目录
安装
通过composer获取此包。
$ composer require inflection-points/tus-php
// Use v1 for php7.1, Symfony 3 or 4.
$ composer require inflection-points/tus-php:^1.2
用法
基本的Tus架构 |
服务器
这是一个简单服务器的样子。
// server.php $server = new \TusPhp\Tus\Server('redis'); // Either redis, file or apcu. Leave empty for file based cache. $response = $server->serve(); $response->send(); exit(0); // Exit from current PHP process.
您需要重写您的服务器以响应特定端点。例如
Nginx
# nginx.conf location /files { try_files $uri $uri/ /server.php?$query_string; }
从nginx 1.7.11开始,有一个新的配置选项 fastcgi_request_buffering。当启用缓冲时,整个请求体将从客户端读取,然后发送到FastCGI服务器。禁用此选项可能有助于解决上传过程中的超时问题。此外,如果您系统tmp分区的磁盘空间不足,这也有帮助。
如果您不关闭 fastcgi_request_buffering
并使用 fastcgi
,您将无法恢复上传,因为nginx不会在文件完全上传之前将请求返回给PHP。
location ~ \.php$ { # ... fastcgi_request_buffering off; # Disable request buffering # ... }
可以在这里找到nginx配置示例 这里。
Apache
# .htaccess RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^files/?(.*)?$ /server.php?$1 [QSA,L]
默认最大上传大小为0,表示没有限制。您可以按以下说明设置最大上传大小。
$server->setMaxUploadSize(100000000); // 100 MB in bytes
默认情况下,服务器和客户端的redis和文件配置可以在config/server.php
和config/client.php
中找到。要覆盖默认配置,您可以简单地将文件复制到您喜欢的位置并更新参数。然后您需要在进行其他任何操作之前设置配置。
\TusPhp\Config::set('<path to your config>'); $server = new \TusPhp\Tus\Server('redis');
或者,您可以在服务器上设置环境变量REDIS_HOST
、REDIS_PORT
和REDIS_DB
以覆盖服务器和客户端的redis设置。
客户端
客户端可用于创建、恢复和/或删除上传。
$client = new \TusPhp\Tus\Client($baseUrl); // Key is mandatory. $key = 'your unique key'; $client->setKey($key)->file('/path/to/file', 'filename.ext'); // Create and upload a chunk of 1MB $bytesUploaded = $client->upload(1000000); // Resume, $bytesUploaded = 2MB $bytesUploaded = $client->upload(1000000); // To upload whole file, skip length param $client->file('/path/to/file', 'filename.ext')->upload();
要检查文件之前是否已部分上传,您可以使用getOffset
方法。如果没有上传或上传无效,则返回false,否则返回已上传的总字节数。
$offset = $client->getOffset(); // 2000000 bytes or 2MB
从缓存中删除部分上传。
$client->delete($key);
默认情况下,客户端使用/files
作为API路径。您可以使用setApiPath
方法更改它。
$client->setApiPath('/api');
默认情况下,服务器将使用sha256
算法来验证上传的完整性。如果您想使用不同的哈希算法,可以使用setChecksumAlgorithm
方法。要获取支持的哈希算法列表,可以向服务器发送OPTIONS
请求。
$client->setChecksumAlgorithm('crc32');
第三方客户端库
Uppy
Uppy是由tus协议背后的同一团队开发的一个简洁的模块化文件上传插件。您可以使用Uppy无缝地将官方tus-js-client与tus-php服务器集成。有关更多详细信息,请参阅Uppy文档。
uppy.use(Tus, { endpoint: 'https://tus-server.yoursite.com/files/', // use your tus endpoint here resume: true, autoRetry: true, retryDelays: [0, 1000, 3000, 5000] })
Tus-JS-Client
tus-php服务器与官方tus-js-client JavaScript库兼容。
var upload = new tus.Upload(file, { endpoint: "/tus", retryDelays: [0, 3000, 5000, 10000, 20000], metadata: { name: file.name, type: file.type } }) upload.start()
云服务提供商
许多云服务提供商实现了PHP streamWrapper接口,使我们能够使用内置的PHP函数将这些提供商的数据存储和检索。由于tus-php依赖于PHP的内置文件系统函数,因此我们可以轻松地使用它将文件上传到像Amazon S3这样的服务提供商,如果它们的API支持以追加二进制模式写入。将文件直接上传到S3存储桶的示例实现如下
// server.php // composer require aws/aws-sdk-php use Aws\S3\S3Client; use TusPhp\Tus\Server; use Aws\Credentials\Credentials; $awsAccessKey = 'AWS_ACCESS_KEY'; // YOUR AWS ACCESS KEY $awsSecretKey = 'AWS_SECRET_KEY'; // YOUR AWS SECRET KEY $awsRegion = 'eu-west-1'; // YOUR AWS BUCKET REGION $basePath = 's3://your-bucket-name'; $s3Client = new S3Client([ 'version' => 'latest', 'region' => $awsRegion, 'credentials' => new Credentials($awsAccessKey, $awsSecretKey) ]); $s3Client->registerStreamWrapper(); $server = new Server('file'); $server->setUploadDir($basePath); $response = $server->serve(); $response->send(); exit(0);
扩展支持
- 创建扩展基本上已实现,并用于创建上传。目前无法延迟上传的长度。
- 终止扩展已实现,用于终止已完成和未完成的上传,允许服务器释放使用的资源。
- 已实现校验和扩展,服务器默认使用
sha256
算法来验证上传。 - 已实现过期扩展,详情见下文。
- 此连接扩展已实现,但服务器无法处理未完成的连接。
过期
服务器可以移除已过期但未完成的上传。您可以使用以下命令手动或在cron作业中移除它们。请注意,此命令会检查您的缓存存储以查找已过期的上传。因此,请确保在缓存过期之前运行它,否则它将找不到所有需要清除的文件。
$ ./vendor/bin/tus tus:expired --help Usage: tus:expired [<cache-adapter>] [options] Arguments: cache-adapter Cache adapter to use: redis, file or apcu [default: "file"] Options: -c, --config=CONFIG File to get config parameters from. eg: $ ./vendor/bin/tus tus:expired redis Cleaning server resources ========================= 1. Deleted 1535888128_35094.jpg from /var/www/uploads
您可以使用--config
选项覆盖默认的redis或文件配置。
$ ./vendor/bin/tus tus:expired redis --config=<path to your config file>
连接
服务器可以将多个上传连接成一个,使客户端能够执行并行上传并上传非连续块。
// Actual file key $uploadKey = uniqid(); $client->setKey($uploadKey)->file('/path/to/file', 'chunk_a.ext'); // Upload 10000 bytes starting from 1000 bytes $bytesUploaded = $client->seek(1000)->upload(10000); $chunkAkey = $client->getKey(); // Upload 1000 bytes starting from 0 bytes $bytesUploaded = $client->setFileName('chunk_b.ext')->seek(0)->upload(1000); $chunkBkey = $client->getKey(); // Upload remaining bytes starting from 11000 bytes (10000 + 1000) $bytesUploaded = $client->setFileName('chunk_c.ext')->seek(11000)->upload(); $chunkCkey = $client->getKey(); // Concatenate partial uploads $client->setFileName('actual_file.ext')->concat($uploadKey, $chunkBkey, $chunkAkey, $chunkCkey);
此外,服务器将对合并后的文件进行校验和验证,以确保文件未损坏。
事件
通常,您可能希望在上传完成后或创建后执行某些操作。例如,您可能希望在上传后裁剪图像或转码文件并将其电子邮件发送给用户。您可以使用tus事件执行这些操作。以下事件在执行的不同点由服务器发出。
事件名称 | 发出 |
---|---|
tus-server.upload.created |
在创建上传时在POST 请求之后。 |
tus-server.upload.progress |
在PATCH 请求中上传块之后。 |
tus-server.upload.complete |
在上传完成后并完成校验和验证之后。 |
tus-server.upload.merged |
在连接请求中将所有部分上传合并之后。 |
响应事件
要监听事件,您可以将监听器附加到事件名称。创建一个TusEvent
实例并将其传递给所有监听器。
$server->event()->addListener('tus-server.upload.complete', function (\TusPhp\Events\TusEvent $event) { $fileMeta = $event->getFile()->details(); $request = $event->getRequest(); $response = $event->getResponse(); // ... });
或者,您还可以绑定自定义类的一些方法。
/** * Listener can be method from any normal class. */ class SomeClass { public function postUploadOperation(\TusPhp\Events\TusEvent $event) { // ... } } $listener = new SomeClass(); $server->event()->addListener('tus-server.upload.complete', [$listener, 'postUploadOperation']);
中间件
您可以使用中间件来操纵服务器的请求和响应。中间件可以在服务器调用实际处理方法之前运行一段代码。您可以使用中间件来验证请求、处理CORS、允许/禁止IP等。
创建中间件
为了创建中间件,您需要实现TusMiddleware
接口。handle方法为您提供了请求和响应对象,以便您可以对其进行操作。
<?php namespace Your\Namespace; use TusPhp\Request; use TusPhp\Response; use TusPhp\Middleware\TusMiddleware; class Authenticated implements TusMiddleware { // ... /** * {@inheritDoc} */ public function handle(Request $request, Response $response) { // Check if user is authenticated if (! $this->user->isLoggedIn()) { throw new UnauthorizedHttpException('User not authenticated'); } $request->getRequest()->headers->set('Authorization', 'Bearer ' . $this->user->token()); } // ... }
添加中间件
要添加中间件,从服务器获取中间件对象,然后简单传递中间件类。
$server->middleware()->add(Authenticated::class, AnotherMiddleware::class);
或者,您也可以传递中间件类对象。
$authenticated = new Your\Namespace\Authenticated(new User()); $server->middleware()->add($authenticated);
跳过中间件
如果您希望跳过或忽略任何中间件,可以使用skip
方法。
$server->middleware()->skip(Cors::class, AnotherMiddleware::class);
设置开发环境和/或本地运行示例
该实现的基于ajax的示例可以在examples/
文件夹中找到。您可以使用以下说明使用docker构建和运行它。
Docker
确保系统中已安装docker和docker-compose。然后,从项目根目录运行docker脚本。
# PHP7 $ make dev # PHP8 $ make dev8 # or, without make # PHP7 $ bin/docker.sh # PHP8 $ PHP_VERSION=8 bin/docker.sh
现在,客户端可以通过http://0.0.0.0:8080访问,服务器可以通过http://0.0.0.0:8081访问。默认API端点设置为/files
,上传的文件可以在uploads
文件夹内找到。所有Docker配置都可以在docker/
文件夹内找到。
如果您想从零开始,可以使用以下命令。这将删除并重新创建所有容器、镜像和上传文件夹。
# PHP7 $ make dev-fresh # PHP8 $ make dev8-fresh # or, without make # PHP7 $ bin/clean.sh && bin/docker.sh # PHP8 $ bin/clean.sh && PHP_VERSION=8 bin/docker.sh
我们还提供了一些实用脚本,可以帮助您简化本地开发体验。请参阅Makefile以获取所有可用命令的列表。如果您不使用make,则可以使用这里提供的shell脚本。
贡献
- 如果您还没有安装,请安装PHPUnit和composer。
- 安装依赖
$ make vendor # or $ composer install
- 使用phpunit运行测试
$ make test # or $ composer test # or $ ./vendor/bin/phpunit
- 根据PSR2编码标准验证更改
# fix lint issues $ make lint # dry run $ make lint-dry
您可以使用xdebug enable
和xdebug disable
在容器内启用和禁用Xdebug。
关于这个项目的问题?
请随时报告发现的任何错误。拉取请求、问题和项目建议都备受欢迎!