PHP中使用 TUS 協議來實現可恢復文件上傳

曾經嘗試過用PHP上傳大文件嗎?想知道您是否能夠從上次中斷的地方繼續上傳,而不會在遇到任何中斷的狀況下再次從新上傳整個數據?若是您以爲這個場景很熟悉,請接着往下閱讀。php

文件上傳是咱們幾乎全部現代Web項目中的一項很常見的任務。在任何語言中,有了可用的工具,實現文件上傳功能都不難。可是,對於大文件上傳,這個事情仍是有些讓人頭疼。html

假設您正在嘗試上傳至關大的文件。您已經等待了一個多小時,上傳率爲90%。而後忽然,您的鏈接斷開或瀏覽器崩潰。上傳被停止,您須要從頭開始上傳。這很使人沮喪,不是嗎?更糟糕的是,若是您的鏈接速度較慢,就像世界上許多地方同樣,不管嘗試多少次,每次都只能上傳第一部份內容。不管你重來多少次,你都不可能上傳成功。你的心態扛得住嘛?!?!nginx


在這篇文章中,咱們將嘗試經過使用tus協議以可恢復塊的形式上傳文件來解決PHP中的此問題。git

首先什麼是tus?

Tus是用於可恢復文件上傳的基於HTTP的開放協議。可恢復意味着能夠在中斷的地方繼續工做,而不會在遇到任何中斷的狀況下再次從新上傳整個數據。若是用戶但願暫停,則中斷可能會發生,或者在網絡問題或服務器中斷的狀況下,偶然發生。github

Vimeo於2017年5月 採用了 Tus協議。

爲何是tus?

引用Vimeo的博客redis

咱們之因此決定在上載堆棧中使用tus,是由於tus協議以簡潔明瞭的方式標準化了上載文件的過程。這種標準化將使API開發人員能夠將更多的精力放在其特定於應用程序的代碼上,而沒必要將精力放在上傳過程自己上。

經過這種方式上傳文件的另外一個主要好處是,您能夠從筆記本電腦開始上傳,甚至能夠繼續從移動設備或任何其餘設備上載相同的文件,這能夠極大地提高用戶體驗。vim

圖片:基本的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>

提交表單後,咱們須要按照幾個步驟來處理上傳。

  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!

相關文章
相關標籤/搜索