文件上传
文件上传
基本文件上传
注意: 使用此功能必须保证 Livewire 版本 >= 1.2.0 。
Livewire 使上传和存储文件变得非常容易。
首先,将 WithFileUploads
trait 添加到您的组件中。 现在您可以在文件输入上使用 wire:model
,就好像它们是任何其他输入类型一样,Livewire 将负责其余的工作。
这是处理上传照片的简单组件的示例:
UploadPhoto.php
use Livewire\Component;
use Livewire\WithFileUploads;
class UploadPhoto extends Component
{
use WithFileUploads;
public $photo;
public function save()
{
$this->validate([
'photo' => 'image|max:1024', // 1MB Max
]);
$this->photo->store('photos');
}
}
upload-photo.blade.php
<form wire:submit.prevent="save">
<input type="file" wire:model="photo">
@error('photo') <span class="error">{{ $message }}</span> @enderror
<button type="submit">Save Photo</button>
</form>
从开发人员的角度来看,处理文件输入与处理任何其他输入类型没有什么不同:将 wire:model
添加到 标签中,其他所有工作都将由您完成。
但是,要使文件上载在 Livewire 中起作用,还有很多事情要做。 这是用户选择要上传的文件时发生的情况的一览:
- 选择新文件后,Livewire 的 JavaScript 向服务器上的组件发出初始请求,以获取临时的 “签名” 上传URL。
- 接收到该URL后,JavaScript 然后对签名的 URL 进行实际的“上传”,将上载存储在 Livewire 指定的临时目录中,并返回新的临时文件的唯一哈希ID。
- 一旦文件上传并生成了唯一的哈希ID,Livewire 的 JavaScript 就会向服务器上的组件发出最终请求,告诉它将所需的公共属性设置为新的临时文件。
- 现在,公共资源(在这种情况下为 $photo)被设置为临时文件上传,并随时可以存储或验证。
保存上传文件
前面的示例演示了最基本的存储方案:将临时上传的文件移动到应用程序默认文件系统磁盘上的“photo”目录中。
但是,您可能想要自定义所存储文件的文件名,或者甚至指定一个特定的存储“磁盘”来存储该文件(例如,可能在S3存储桶中)。
Livewire与Laravel用于存储上传文件的API相同,因此请随意浏览Laravel的文档。 以下是一些适合您的常见存储方案:
// 将上载的文件存储在默认文件系统磁盘的“photos”目录中。
$this->photo->store('photos');
// 将其存储在已配置的“ s3”存储桶的“photos”目录中。
$this->photo->store('photos', 's3');
// 使用文件名“ avatar.png”存储在“photos”目录中。
$this->photo->storeAs('photos', 'avatar');
// 使用文件名“ avatar.png”存储在S3的“photos”目录中。
$this->photo->storeAs('photos', 'avatar', 'S3');
// 存储在“photos”目录中,并在配置的“ s3”存储桶中具有“公共”可见性。
$this->photo->storePublicly('photos', 's3');
// 将名称为“ avatar.png”的文件以“公共”可见性存储在已配置的“ s3”存储桶中的“photos”目录中。
$this->photo->storePubliclyAs('photos', 'avatar', 's3');
上面的方法应该可以提供足够的灵活性,以完全按照您想要的方式存储上传的文件。
处理多文件
Livewire 通过检测 标签上的 multi 属性来自动处理多个文件上传。
这是处理多个上传的文件上传的示例:
UploadPhotos.php
use Livewire\Component;
use Livewire\WithFileUploads;
class UploadPhotos extends Component
{
use WithFileUploads;
public $photos = [];
public function save()
{
$this->validate([
'photos.*' => 'image|max:1024', // 1MB Max
]);
foreach ($this->photos as $photo) {
$photo->store('photos');
}
}
}
upload-photos.blade.php
<form wire:submit.prevent="save">
<input type="file" wire:model="photos" multiple>
@error('photos.*') <span class="error">{{ $message }}</span> @enderror
<button type="submit">Save Photo</button>
</form>
文件验证
就像您在前面的示例中看到的那样,使用Livewire验证文件上传与处理从标准Laravel控制器上传的文件完全相同。
有关 Laravel 的文件验证的更多信息,请访问文档
实时验证
在用户按下“提交”按钮之前,可以实时验证用户的上传。
同样,您可以像在Livewire中的任何其他输入类型一样完成此操作:
UploadPhoto.php
use Livewire\Component;
use Livewire\WithFileUploads;
class UploadPhoto extends Component
{
use WithFileUploads;
public $photo;
public function updatedPhoto()
{
$this->validate([
'photo' => 'image|max:1024', // 1MB Max
]);
}
public function save()
{
// ...
}
}
upload-photo.blade.php
<form wire:submit.prevent="save">
<input type="file" wire:model="photo">
@error('photo') <span class="error">{{ $message }}</span> @enderror
<button type="submit">Save Photo</button>
</form>
现在,当用户选择文件时(Livewire将文件上传到临时目录之后),该文件将被验证,并且在提交表单之前,用户将收到错误消息。
临时预览URL
用户选择文件后,您可能希望在他们提交表单并实际存储文件之前向他们显示该文件的预览。
Livewire 通过对上传的文件使用 -> temporaryUrl()
方法。
注意: 出于安全原因,仅图片上传支持临时网址。
这是带有图片预览的文件上传示例:
UploadPhotoWithPreview.php
use Livewire\Component;
use Livewire\WithFileUploads;
class UploadPhotoWithPreview extends Component
{
use WithFileUploads;
public $photo;
public function updatedPhoto()
{
$this->validate([
'photo' => 'image|max:1024',
]);
}
public function save()
{
// ...
}
}
upload-photo-with-preview.blade.php
<form wire:submit.prevent="save">
@if ($photo)
Photo Preview:
<img src="{{ $photo->temporaryUrl() }}">
@endif
<input type="file" wire:model="photo">
@error('photo') <span class="error">{{ $message }}</span> @enderror
<button type="submit">Save Photo</button>
</form>
Livewire 如前所述将临时文件存储在非公共目录中,因此,没有简单的方法可以向用户公开临时的公共URL进行图像预览。
Livewire 通过提供一个临时的,经过签名的URL来伪装成已上传的图像,从而解决了这种复杂性,以便您的页面可以向用户显示某些内容。
该URL受到保护,不会在临时目录上方的目录中显示文件,并且由于它是临时签名的,因此用户不能滥用此URL来预览系统上的其他文件。
如果您已将Livewire配置为使用S3进行临时文件存储,则调用-> temporaryUrl()
将直接从S3生成一个临时的,已签名的url,这样您就完全不会在Laravel应用服务器上看到此预览了。
文件上传测试
使用Laravel的文件上传测试助手,可以轻松地在Livewire中测试文件上传。
这是使用Livewire测试“ UploadPhoto”组件的完整示例。
UploadPhotoTest.php
/** @test **/
function can_upload_photo() {
Storage::fake();
$file = UploadedFile::fake()->image('avatar.png');
Livewire::test(UploadPhoto::class)
->set('photo', $file)
->call('save');
Storage::assertExists('avatar.png');
}
有关测试文件上传的更多详细信息,请参考Laravel的文件上传测试文档.
直接上传到Amazon S3
如前所述,Livewire将所有上传的文件存储在一个临时目录中,直到开发人员选择永久存储文件为止。
默认情况下,Livewire 使用默认文件系统磁盘配置(通常是“本地”),并将文件存储在名为 livewire-tmp/
的文件夹下。
这意味着文件上传总是在您的服务器上。 即使您以后选择将它们存储在S3存储桶中。
如果您希望绕过此系统,而是将Livewire的临时上传存储在S3存储桶中,则可以轻松配置该行为:
在您的 config/livewire.php
文件中,将livewire.temporary_file_upload.disk
设置为 s3(或另一个使用s3驱动程序的自定义磁盘):
config/livewire.php
return [
...
'temporary_file_upload' => [
'disk' => 's3',
...
],
];
现在,当用户上传文件时,该文件将永远不会真正命中您的服务器。 它将直接上载到子目录 livewire-tmp/
下的S3存储桶中。
配置自动清除文件
此临时目录将快速填充文件,因此,将S3配置为清除24小时之前的文件很重要。
要配置此行为,只需在配置了S3存储桶的环境中运行以下artisan命令。
php artisan livewire:configure-s3-upload-cleanup
现在,任何早于24小时的临时文件都将由S3自动清除。
如果您不使用S3,Livewire将自动处理文件清除。 无需运行此命令。
加载进度
尽管用于文件上传的 wire:model
与其他 wire:model
输入类型的工作方式不同,但用于显示加载指示器的界面保持不变。
您可以显示一个加载进度,其范围仅限于文件上传,如下所示:
<input type="file" wire:model="photo">
<div wire:loading wire:target="photo">Uploading...</div>
现在,在文件上传过程中,将显示“正在上传…”消息,然后在上传完成后将其隐藏。
这适用于整个 Livewire Loading States API。
进度指示器(以及所有JavaScript事件)
Livewire中的每个文件上传都会在元素上调度JavaScript事件,以供自定义JavaScript侦听。
以下是已调度的事件:
事件 | 描述 |
---|---|
livewire-upload-start |
上传开始时触发 |
livewire-upload-finish |
文件上传成功触发 |
livewire-upload-error |
文件上传失败触发 |
livewire-upload-progress |
在上载进度时调度包含上载进度百分比的事件 |
这是将Livewire文件上传包装在AlpineJS组件中以显示进度条的示例:
<div
x-data="{ isUploading: false, progress: 0 }"
x-on:livewire-upload-start="isUploading = true"
x-on:livewire-upload-finish="isUploading = false"
x-on:livewire-upload-error="isUploading = false"
x-on:livewire-upload-progress="progress = $event.detail.progress"
>
<!-- File Input -->
<input type="file" wire:model="photo">
<!-- Progress Bar -->
<div x-show="isUploading">
<progress max="100" x-bind:value="progress"></progress>
</div>
</div>
JavaScript 上传 API
与第三方文件上传库集成时,通常需要比简单的 <input type =“ file”>
标签更好的控制。
对于这些情况,Livewire开放了专用的JavaScript函数。
这些功能存在于 JavaScript 组件对象上,可以使用便捷的 Blade 指令@this 进行访问。 如果您以前没有看过@this,可以在这里 阅读更多有关它的内容。
<script>
let file = document.querySelector('input[type="file"]').files[0]
// Upload a file:
@this.upload('photo', file, (uploadedFilename) => {
// Success callback.
}, () => {
// Error callback.
}, (event) => {
// Progress callback.
// event.detail.progress contains a number between 1 and 100 as the upload progresses.
})
// Upload multiple files:
@this.uploadMultiple('photos', [file], successCallback, errorCallback, progressCallback)
// Remove single file from multiple uploaded files
@this.removeUpload('photos', uploadedFilename, successCallback)
</script>
配置
因为Livewire在开发人员有机会验证或存储它们之前临时存储所有文件上传,所以Livewire假定对所有文件上传进行某种默认处理。
全局验证
默认情况下,Livewire 将使用以下规则验证所有临时文件的上传:file | max:12288
(必须是小于12MB的文件)。
如果您希望自定义此选项,则可以在 config / livewire.php
内部的所有临时文件上载确切配置哪些验证规则:
config/livewire.php
return [
...
'temporary_file_upload' => [
...
'rules' => 'file|mimes:png,jpg,pdf|max:102400', // (100MB max, and only pngs, jpegs, and pdfs.)
...
],
];
全局中间件
默认情况下,临时文件上传端点具有限制的中间件。 您可以使用以下配置变量来完全自定义此端点使用的中间件:
config/livewire.php
return [
...
'temporary_file_upload' => [
...
'middleware' => 'throttle:5,1', // Only allow 5 uploads per user per minute.
],
];
临时文件目录
临时文件将上传到指定磁盘上的livewire-tmp /目录中。 您可以使用以下配置项此进行自定义:
config/livewire.php
return [
...
'temporary_file_upload' => [
...
'directory' => 'tmp',
],
];