【相關(guān)學(xué)習(xí)推薦:php圖文教程】
你是否曾經(jīng)為大文件上傳而苦惱?如果文件上傳的過(guò)程中,因?yàn)槟撤N原因中斷了,是否可以從中斷的位置繼續(xù)上傳,而不用重新上傳整個(gè)文件?如果你有這樣的困惑,那么請(qǐng)繼續(xù)閱讀下面的內(nèi)容。
在現(xiàn)代網(wǎng)站應(yīng)用中,上傳文件是非常常見(jiàn)的。在任何語(yǔ)言中,通過(guò)使用一些工具,都可以實(shí)現(xiàn)文件上傳的功能。但是,如果處理大文件上傳的需求,還是有點(diǎn)麻煩的。
假如你此時(shí)正在上傳一個(gè)很大的文件,大約一個(gè)小時(shí)過(guò)去了,進(jìn)度是 90%。突然斷網(wǎng)了或者瀏覽器崩潰了,上傳的程序退出,你要再全部重新來(lái)過(guò)。真的很不爽,對(duì)不對(duì)?還有更讓人郁悶的是,如果你的網(wǎng)速很慢,那么,無(wú)論你重來(lái)多少次,你都不可能上傳成功。
在 PHP 中,我們可以嘗試?yán)?tus 協(xié)議的斷點(diǎn)續(xù)傳功能來(lái)解決這個(gè)問(wèn)題。
Tus 是一個(gè)基于 HTTP 的 文件斷點(diǎn)續(xù)傳開(kāi)放協(xié)議。 斷點(diǎn)續(xù)傳的意思是不管是用戶自行中斷,還是由于網(wǎng)絡(luò)等原因的意外中斷,都可以從中斷的地方繼續(xù)上傳,而不用重新開(kāi)始。
Tus 協(xié)議是在 2017年5月被 Vimeo 采用的。
引用 Vimeo 的博客:
我們之所以決定用 tus,是因?yàn)樗芤院?jiǎn)潔開(kāi)放的形式,將文件上傳的過(guò)程標(biāo)準(zhǔn)化。這種標(biāo)準(zhǔn)化有利于 API 的開(kāi)發(fā)者更加專注于應(yīng)用本身的邏輯,而非文件上傳的過(guò)程。
使用這種方式上傳的另一個(gè)好處是,你可以在筆記本上開(kāi)始上傳文件,然后又轉(zhuǎn)到手機(jī)或者其他設(shè)備繼續(xù)上傳同一個(gè)文件,這可以極大地提升用戶體驗(yàn)。
圖片: Tus 大致的工作流程
第一步,加載依賴。
$ composer require ankitpokhrel/tus-php
tus-php 是用于 tus 斷點(diǎn)續(xù)傳協(xié)議 v1.0.0 的一個(gè)的純 PHP 框架,完美實(shí)現(xiàn)了 服務(wù)端與客戶端的交互 。
更新: 現(xiàn)在 Vimeo 官方 PHP 庫(kù) 的 v3 用的是 TusPHP。
你可以像下面這樣創(chuàng)建一個(gè)服務(wù)端.
// server.php $server = new TusPhpTusServer('redis'); $response = $server->serve(); $response->send(); exit(0); // 退出當(dāng)前 PHP 進(jìn)程
你需要配置你的服務(wù)器以便能對(duì)特定的終端進(jìn)行響應(yīng). 如果使用 Nginx 的話你可以像下面這樣配置:
# nginx.conf location /files { try_files $uri $uri/ /path/to/server.php?$query_string; }
假設(shè)我們服務(wù)端的 URL 是 http://server.tus.local. 因此, 基于我們上面的 Nginx 配置,我們可以通過(guò) http://server.tus.local/files. 來(lái)訪問(wèn)到我們的 tus 終端.
基于 RESTful 風(fēng)格的端點(diǎn)配置:
# 獲取有關(guān)服務(wù)器目前配置的信息 OPTIONS /files # 檢查上傳的文件是否合法 HEAD /files/{upload-key} # 創(chuàng)建 POST /files # 修改 PATCH /files/{upload-key} # 刪除 DELETE /files/{upload-key}
查看 協(xié)議細(xì)則 獲取更多關(guān)于路由的信息。
如果你是用類似于 Laravel 的框架,那么你就不需要在配置文件里定義這些了, 可以直接定義路由來(lái)訪問(wèn) tus 的基礎(chǔ)端點(diǎn)。我們會(huì)在另外的教程里介紹相關(guān)細(xì)節(jié)。
服務(wù)器到位后,客戶端可以塊的形式上傳文件。 讓我們首先創(chuàng)建一個(gè)簡(jiǎn)單的HTML表單來(lái)獲取用戶的輸入。
<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>
提交表單后,我們需要按照幾個(gè)步驟來(lái)處理上傳。
// Tus client $client = new TusPhpTusClient('http://server.tus.local');
上面代碼中的第一個(gè)參數(shù)是你的tus服務(wù)器地址。
2. 使用文件元數(shù)據(jù)初始化客戶端
為了確保上傳文件的唯一性,我們需要給每個(gè)上傳的文件以唯一標(biāo)識(shí)。這樣在文件中斷后續(xù)傳的時(shí)候,服務(wù)器就可以很清晰地辨識(shí)出,哪幾個(gè)片段是屬于同一個(gè)文件得。這個(gè)標(biāo)識(shí)碼可以自己指定,也可以由系統(tǒng)生成。
// 設(shè)置標(biāo)識(shí)碼和文件元數(shù)據(jù) $client->setKey($uploadKey) ->file($_FILES['tus_file']['tmp_name'], 'your file name');
如果不想指定標(biāo)識(shí)碼,可以這樣寫(xiě),由系統(tǒng)會(huì)自動(dòng)生成:
$client->file($_FILES['tus_file']['tmp_name'], 'your file name'); $uploadKey = $client->getKey(); // Unique upload key
3. 分塊上傳文件
// $chunkSize 是以字節(jié)為單位的,例如 5000000 等于 5 MB $bytesUploaded = $client->upload($chunkSize);
當(dāng)你想要續(xù)傳下一塊的時(shí)候,就可以帶上同樣的標(biāo)識(shí)碼參數(shù)來(lái)續(xù)傳。
// 在下一個(gè)請(qǐng)求中續(xù)傳文件 $bytesUploaded = $client->setKey($uploadKey)->upload($chunkSize);
文件全部上傳完成后,默認(rèn)情況下,服務(wù)器會(huì)使用 sha256
來(lái)校驗(yàn)文件總和,以確保不會(huì)有丟失的文件。
tus 協(xié)議的團(tuán)隊(duì)還開(kāi)發(fā)了一個(gè)模塊化的文件上傳插件 Uppy。這個(gè)插件可以在官方 tus-js-client 和 tus-php 服務(wù)器之間建立連接。也就是說(shuō)我們可以使用 php 配合 js 來(lái)實(shí)現(xiàn)文件上傳了。
uppy.use(Tus, { endpoint: 'https://server.tus.local/files/', // 你的 tus 服務(wù)器 resume: true, autoRetry: true, retryDelays: [0, 1000, 3000, 5000] })
更多細(xì)節(jié)可以查看 uppy 的文檔, 這里 還有些例子可以供你參考。
tus-php 服務(wù)器支持 concatenation 擴(kuò)展,可以把多次上傳的文件合為一個(gè)文件。因此,我們可以在客戶端支持并行上傳以及非連續(xù)的分塊文件上傳。
使用 tus-php 實(shí)現(xiàn)分塊上傳
tus-partial-upload.php
<?php // 文件唯一標(biāo)識(shí)碼 $uploadKey = uniqid(); $client->setKey($uploadKey)->file('/path/to/file', 'chunk_a.ext'); // 從第 1000 個(gè)字節(jié)開(kāi)始上傳 10000 字節(jié) $bytesUploaded = $client->seek(1000)->upload(10000); $chunkAkey = $client->getKey(); // 從 第 0 個(gè)字節(jié)開(kāi)始上傳 10000 字節(jié) $bytesUploaded = $client->setFileName('chunk_b.ext')->seek(0)->upload(1000); $chunkBkey = $client->getKey(); // 從第 11000 個(gè)字節(jié) (10000 + 1000) 開(kāi)始上傳剩余的字節(jié) $bytesUploaded = $client->setFileName('chunk_c.ext')->seek(11000)->upload(); $chunkCkey = $client->getKey(); // 把分塊上傳的文件組合起來(lái) $client->setFileName('actual_file.ext')->concat($uploadKey, $chunkAkey, $chunkBkey, $chunkCkey);
分塊上傳的完整例子 在這里.
由于 tus-php 項(xiàng)目 本身還出于初級(jí)階段,后面可能還會(huì)有一些改動(dòng)。在 example 文件夾里,有三個(gè)不同的例子供你參考。如果任何問(wèn)題或者建議,歡迎留言交流。
Happy Coding!
相關(guān)學(xué)習(xí)推薦:php編程(視頻)
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com