
本教程详细介绍了如何在 laravel 中验证上传文件数组的总大小。由于 laravel 内置验证器主要针对单个文件大小,对于整个文件数组的合计大小验证,需要通过创建自定义验证规则来实现。文章将指导您完成自定义规则的创建、逻辑实现,并将其集成到表单请求的验证规则中,确保所有上传文件的总大小符合预期限制。
在 Laravel 应用中处理文件上传时,我们经常需要对单个文件的大小、类型等进行验证。然而,当用户上传多个文件(作为文件数组)时,有时不仅需要限制每个文件的大小,还需要限制所有文件合计的总大小。Laravel 的内置验证规则,例如 max,通常只作用于单个文件,无法直接验证文件数组的聚合大小。本文将指导您如何通过创建自定义验证规则来解决这一问题。
1. 理解 Laravel 内置文件验证的局限性
考虑以下典型的 Laravel 验证规则,它限制了每个 images 数组中的图片文件类型和最大大小(1000 KB):
public function rules()
{
return [
// ... 其他验证规则
'images.*' => 'mimes:jpg,jpeg,png|max:1000' // 验证每个图片文件不超过 1000 KB
];
}这里的 images.* 规则确保了数组中的每个文件都符合要求。但如果用户上传了 10 张图片,每张 900 KB,那么总大小将达到 9000 KB (9 MB),这可能仍然超出了我们对整个上传批次的总大小限制。为了实现对总大小的验证,我们需要一个自定义的解决方案。
2. 创建自定义验证规则
Laravel 提供了强大的自定义验证规则机制,允许我们定义复杂的验证逻辑。我们将创建一个名为 ArraySize 的自定义规则来验证文件数组的总大小。
首先,使用 Artisan 命令生成一个新的验证规则:
php artisan make:rule ArraySize
这会在 app/Rules 目录下创建一个 ArraySize.php 文件。
3. 实现自定义规则逻辑
打开 app/Rules/ArraySize.php 文件,并根据以下示例代码修改其内容。这个规则的核心逻辑是遍历文件数组,累加每个文件的大小,然后将总大小与我们设定的最大值进行比较。
maxSize = $maxSize;
}
/**
* 判断验证规则是否通过。
*
* @param string $attribute 字段名称
* @param mixed $value 待验证的值 (文件数组)
* @return bool
*/
public function passes($attribute, $value): bool
{
$totalSize = 0;
// 确保 $value 是一个数组
if (!is_array($value)) {
return false;
}
foreach ($value as $file) {
// 确保数组中的每个元素都是 UploadedFile 实例
if (!$file instanceof UploadedFile) {
return false;
}
$totalSize += $file->getSize(); // getSize() 返回字节数
}
// 将总字节数转换为 KB,并判断是否小于允许的最大值
// 如果总大小小于最大允许值,则验证通过 (返回 true)
return ($totalSize / 1024) < $this->maxSize;
}
/**
* 获取验证失败时返回的错误消息。
*
* @return string
*/
public function message(): string
{
return sprintf('所有图片的总大小必须小于 %d KB。', $this->maxSize);
}
}代码解析:
- __construct(int $maxSize): 构造函数接收一个 $maxSize 参数,用于设定允许的最大总大小,单位为 KB。
-
passes($attribute, $value):
- 初始化 $totalSize 为 0,用于累加文件大小。
- 首先检查 $value 是否为数组,如果不是,则验证失败。
- 遍历 $value 数组,对每个元素:
- 检查它是否是 Illuminate\Http\UploadedFile 的实例。这确保我们处理的是实际上传的文件对象。
- 通过 $file->getSize() 获取当前文件的大小(单位为字节),并累加到 $totalSize。
- 最后,将 $totalSize(字节)转换为 KB ($totalSize / 1024),并与构造函数中传入的 $maxSize 进行比较。如果总大小小于 $maxSize,则 passes 方法返回 true(验证通过),否则返回 false(验证失败)。
- message(): 定义了当验证失败时返回的错误消息。使用 sprintf 可以动态地将 $maxSize 插入到消息中,提供更具体的信息。
4. 在验证中使用自定义规则
现在,您可以在您的表单请求(Form Request)或控制器中引入并使用这个自定义规则。
首先,在文件顶部引入 ArraySize 规则:
use App\Rules\ArraySize;
然后,在您的 rules() 方法中,将 ArraySize 规则应用于 images 字段。请注意,images 字段代表整个文件数组,而 images.* 字段则代表数组中的每个单独文件。
public function rules()
{
return [
'title' => 'required|max:125',
'quantity' => 'required|numeric|min:0',
'retail_price' => 'required|numeric|min:0',
'diamond_shape_id' => 'required',
'diamond_cut_id' => 'required',
'diamond_color_id' => 'required',
'diamond_clarity_id' => 'required',
'carat_weight' => 'required',
'diamond_polish_id' => 'required',
'diamond_symmetry_id' => 'required',
'video_url' => ['url', new EmbeddableUrl],
'images.*' => 'mimes:jpg,jpeg,png|max:1000', // 验证单个文件
'images' => ['required', new ArraySize(30000)], // 验证文件数组总大小,30000 KB = 30 MB
];
}在上述示例中,new ArraySize(30000) 表示我们希望所有上传图片的合计大小不得超过 30000 KB (即 30 MB)。同时,images.* 规则仍然会验证每个单独的文件不超过 1000 KB。
5. 注意事项与最佳实践
- 单位一致性:在 ArraySize 规则中,$maxSize 参数的单位是 KB。确保在实例化规则时传入的值是正确的 KB 单位。
- 错误消息本地化:如果您的应用支持多语言,您可以通过在 resources/lang/{locale}/validation.php 文件中添加自定义消息,或者在规则的 message() 方法中返回 __('validation.custom.images.array_size') 来实现错误消息的本地化。
- 与其他规则结合:将 images.* (针对单个文件) 和 images (针对文件数组) 的验证规则结合使用,可以提供更全面的验证。
- 性能考量:对于非常大的文件数组或文件,计算总大小可能会消耗一些时间。在极端情况下,可以考虑在文件上传前进行前端预校验,以减少不必要的服务器请求。
- 空数组处理:在上述 rules() 中,我们为 images 字段添加了 required 规则。这意味着如果 images 数组为空,它将首先被 required 规则捕获。如果您允许空数组,但仍然想验证非空数组的总大小,可以移除 required 规则。
总结
通过创建自定义验证规则,我们成功解决了 Laravel 中对上传文件数组总大小进行验证的需求。这种方法不仅功能强大,而且高度可定制,能够适应各种复杂的业务逻辑。掌握自定义验证规则的技巧,将大大提升您在 Laravel 中处理复杂数据验证的能力。










