獲取上傳的文件
可使用 Illuminate\Http\Request
實例提供的 file
方法或者動態屬性來訪問上傳文件, file
方法返回 Illuminate\Http\UploadedFile
類的一個實例,該類繼承自 PHP
標準庫中提供與文件交互方法的 SplFileInfo
類:php
$file = $request->file('photo'); $file = $request->photo;
你可使用 hasFile
方法判斷文件在請求中是否存在:css
if (\$request->hasFile('photo')) { //文件存在... }
SplFileInfo
類:node
<?php $file = new SplFileInfo('test.jpg'); print_r(array( 'getATime' => $file->getATime(), //最後訪問時間 'getBasename' => $file->getBasename(), //獲取無路徑的basename 'getCTime' => $file->getCTime(), //獲取inode修改時間 'getExtension' => $file->getExtension(), //文件擴展名 'getFilename' => $file->getFilename(), //獲取文件名 'getGroup' => $file->getGroup(), //獲取文件組 'getInode' => $file->getInode(), //獲取文件inode 'getLinkTarget' => $file->getLinkTarget(), //獲取文件連接目標文件 'getMTime' => $file->getMTime(), //獲取最後修改時間 'getOwner' => $file->getOwner(), //文件擁有者 'getPath' => $file->getPath(), //不帶文件名的文件路徑 'getPathInfo' => $file->getPathInfo(), //上級路徑的SplFileInfo對象 'getPathname' => $file->getPathname(), //全路徑 'getPerms' => $file->getPerms(), //文件權限 'getRealPath' => $file->getRealPath(), //文件絕對路徑 'getSize' => $file->getSize(),//文件大小,單位字節 'getType' => $file->getType(),//文件類型 file dir link 'isDir' => $file->isDir(), //是不是目錄 'isFile' => $file->isFile(), //是不是文件 'isLink' => $file->isLink(), //是不是快捷連接 'isExecutable' => $file->isExecutable(), //是否可執行 'isReadable' => $file->isReadable(), //是否可讀 'isWritable' => $file->isWritable(), //是否可寫 ));
驗證文件是否上傳成功
使用 isValid
方法判斷文件在上傳過程當中是否出錯:json
if (\$request->file('photo')->isValid()){ //上傳成功... }
獲取文件的路徑 & 擴展名 & 其餘UploadedFile
類還提供了訪問上傳文件絕對路徑和擴展名的方法。 extension
方法能夠基於文件內容判斷文件擴展名,該擴展名可能會和客戶端提供的擴展名不一致:bootstrap
$path = $request->photo->path(); $extension = $request->photo->extension();
其餘文件方法bash
$file->guessExtension() //根據mime類型返回擴展名。return string | null $file->getMimeType() //返回文件的 mime 類型。return string | null $file->move(string $directory, string $name = null) //將文件移動到一個新的位置。return File $file->getClientOriginalName() //返回原始的文件名。return string | null $file->getClientOriginalExtension() //返回原始文件擴展名。 return string $file->getClientMimeType() //返回文件 mime 類型。return string | null $file->guessClientExtension() //根據客戶端mime類型返回擴展。return string | null $file->getClientSize() //返回文件的大小字節。return int | null $file->getError() //返回上傳文件的錯誤。return int $file->isValid() //返回文件是否成功上傳。return bool $file->getMaxFilesize() //返回在php.ini中配置的上傳文件的最大大小。return static int $file->getErrorMessage() //返回一個包含信息的上傳錯誤信息。return string
UploadedFile
實例上還有不少其餘可用方法,查看該類的 API 文檔瞭解更多信息。服務器
保存上傳的文件
要保存上傳的文件,須要使用你所配置的某個文件系統,對應配置位於 config/filesystems.php
:app
'disks' => [ 'local' => [ 'driver' => 'local', 'root' => storage_path('app'), ], 'public' => [ 'driver' => 'local', 'root' => storage_path('app/public'), 'url' => env('APP_URL').'/storage', 'visibility' => 'public', ], 's3' => [ 'driver' => 's3', 'key' => env('AWS_KEY'), 'secret' => env('AWS_SECRET'), 'region' => env('AWS_REGION'), 'bucket' => env('AWS_BUCKET'), ], ],
Laravel
默認使用 local
配置存放上傳文件,即本地文件系統,默認根目錄是 storage/app
,public
也是本地文件系統,只不過存放在這裏的文件能夠被公開訪問,其對應的根目錄是 storage/app/public
,要讓 Web
用戶訪問到該目錄下存放文件的前提是在應用入口 public
目錄下建一個軟鏈 storage
連接到 storage/app/public
。post
創建軟鏈接命令:單元測試
php artisan storage:link
在你的 public
目錄下就會有一個 link
軟鏈接指向了 storage/app/public
目錄:
public/storage(軟鏈接) → storage/app/public
目錄樹結構是這樣的:
public/ ├── storage(軟鏈接,指向目錄 `storage/app/public`) ├── css/ │ └── bootstrap.css └── js/ └── bootstrap.js storage/ └── app/ └── public/ └── user-avatar.png
那麼爲什麼要建立軟鏈接呢?
項目根目錄下的 public
是一個特殊的目錄——存放可公共訪問的資源。就像你看到的,除了 storage
這個軟連接,還有 CSS
和 JS
文件都放在這裏。若是你的域名是 my.app
,那麼訪問這些資源的 URL
以下:
http://my.app/storage/user-avatar.png
http://my.app/css/bootstrap.css
http://my.app/js/bootstrap.js
提示:你會發現,http://my.app/storage/user-avatar.png
實際訪問的文件資源的服務器地址是 storage/app/public/user-avatar.png
。
若是上傳的資源文件是存儲在本地的,Laravel
默認會放在 storage/app
裏面,這個目錄是不可見的,若是想要能公共訪問就必須暴露在項目根目錄下的 public 中,這就是建立軟連接的緣由 。
UploadedFile
類有一個 store
方法,該方法會將上傳文件移動到相應的磁盤路徑上,該路徑能夠是本地文件系統的某個位置,也能夠是雲存儲(如 Amazon S3
)上的路徑。
store
方法接收一個文件保存的相對路徑(相對於文件系統配置的根目錄 ),該路徑不須要包含文件名,由於系統會自動生成一個惟一 ID 做爲文件名。store
方法還接收一個可選的參數 —— 用於存儲文件的磁盤名稱做爲第二個參數(對應文件系統配置 disks
的鍵名,默認值是 local
),該方法會返回相對於根目錄的文件路徑:
$path = $request->photo->store('images'); $path = $request->photo->store('images', 'public');
若是你不想自動生成文件名,可使用 storeAs
方法,該方法接收保存路徑、文件名和磁盤名做爲參數:
$path = $request->photo->storeAs('images', 'filename.jpg'); $path = $request->photo->storeAs('images', 'filename.jpg', 'public');
那麼目錄結構是這樣的:
storage/ └── app/ └── public/ └── images/ └── filename.jpg
下面給出一個參考的實例:
route:
Route::post('fileupload', 'UploadController@fileUpload');
UploadController.php:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use Illuminate\Http\UploadedFile; class UploadController extends Controller { /** * 接受一個上傳的圖片 * * @param file photo * @return \Illuminate\Http\Response */ public function fileUpload(Request $request) { if($request->hasFile('photo') && $request->file('photo')->isValid()){ //獲取上傳的文件 $file = $request->file('photo'); $name = $file->getClientOriginalName(); if($store_result = $file->storeAs('images', $name, 'public')){ return response()->json(['success' => 'true'], 200); } } }
再寫一個單元測試實例:
生成一個測試文件
php artisan make:test UploadTest
修改測試文件 tests/Feature/UploadTest.php
內容:
<?php namespace Tests\Feature; use Tests\TestCase; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Storage; class UploadTest extends TestCase { /** @test */ public function it_can_upload_a_image() { $fake_image = UploadedFile::fake()->image('temp_test.jpg'); $response = $this->json('POST', "/fileupload", ['photo' => $fake_image]); // 斷言該文件被存儲 Storage::disk('public')->assertExists('images/test.jpg'); } }
運行測試:
phpunit --filter UploadTest