修复 Laravel 表单数组验证递归限制
Fixing Laravel form array validation recursion limits
Laravel 表单验证很棒,除了在使用数组表示法时它不会过滤掉无关的键。
我在我的控制器中键入提示表单请求。
public function saveEdit(Post\EditRequest $request)
{
$valid = $request->validated();
}
如果我的表单有 address_1
和 address_2
,并且用户欺骗 address_3
,则欺骗值不会出现在 $valid
。
但是,如果我的表单使用数组表示法,例如venue[address_1]
和venue[address_2]
,那么用户可以欺骗venue[address_3]
,它会出现在$valid
].
还有其他人遇到过这个吗?你是怎么处理的?
表单请求class上的validated()
方法似乎需要递归操作。
你可以使用点符号
public function rules()
{
return [
'venue.address_1' => 'required',
'venue.address_2' => 'required',
'venue.address_3'=>'required',
];
}
如果您使用的是动态数组,您也可以通过
public function rules()
{
return [
'venue.address_.*' => 'required'
];
}
不幸的是,Laravel 不包括对验证数组 keys 的内置支持,只有数组 values。为此,我们需要添加 custom validation rules。
然而,使用 $fillable
模型属性和 array_only()
辅助函数等替代保护,创建这些规则对于非常不可能的边缘情况来说是很多额外的工作。我们为预期用户错误提供验证反馈,并清理以保护我们的数据免受意外 输入。
如果用户欺骗了一个密钥,只要我们不保存它,或者我们将其过滤掉,如果他们没有看到漂亮的验证消息,他们就不会太在意——它不会验证一开始就不应该存在的字段是有意义的。
为了说明清理的工作原理,这里有一个 Venue
模型声明了它的可填充属性:
class Venue extends Model
{
protected $fillable = [ 'address_1', 'address_2' ];
...
}
现在,如果恶意用户试图欺骗数组中的另一个属性:
<input name="venue[address_1]" value="...">
<input name="venue[address_2]" value="...">
<input name="venue[address_3]" value="spoof!">
...我们直接使用输入数组来更新模型:
public function update(Request $request, $venueId)
{
$venue = Venue::find($venueId);
$venue->update($request->venue);
...
}
...模型将从输入数组中删除额外的 address_3
元素,因为我们从未将其声明为可填写字段。换句话说,模型净化了输入。
在某些情况下,我们可能需要在不使用 Eloquent 模型的情况下简单地清理数组元素。我们可以使用 array_only()
函数(或 Arr:only()
)来执行此操作:
$venueAddress = array_only($request->venue, [ 'address_1', 'address_2' ]);
Laravel 表单验证很棒,除了在使用数组表示法时它不会过滤掉无关的键。
我在我的控制器中键入提示表单请求。
public function saveEdit(Post\EditRequest $request)
{
$valid = $request->validated();
}
如果我的表单有 address_1
和 address_2
,并且用户欺骗 address_3
,则欺骗值不会出现在 $valid
。
但是,如果我的表单使用数组表示法,例如venue[address_1]
和venue[address_2]
,那么用户可以欺骗venue[address_3]
,它会出现在$valid
].
还有其他人遇到过这个吗?你是怎么处理的?
表单请求class上的validated()
方法似乎需要递归操作。
你可以使用点符号
public function rules()
{
return [
'venue.address_1' => 'required',
'venue.address_2' => 'required',
'venue.address_3'=>'required',
];
}
如果您使用的是动态数组,您也可以通过
public function rules()
{
return [
'venue.address_.*' => 'required'
];
}
不幸的是,Laravel 不包括对验证数组 keys 的内置支持,只有数组 values。为此,我们需要添加 custom validation rules。
然而,使用 $fillable
模型属性和 array_only()
辅助函数等替代保护,创建这些规则对于非常不可能的边缘情况来说是很多额外的工作。我们为预期用户错误提供验证反馈,并清理以保护我们的数据免受意外 输入。
如果用户欺骗了一个密钥,只要我们不保存它,或者我们将其过滤掉,如果他们没有看到漂亮的验证消息,他们就不会太在意——它不会验证一开始就不应该存在的字段是有意义的。
为了说明清理的工作原理,这里有一个 Venue
模型声明了它的可填充属性:
class Venue extends Model
{
protected $fillable = [ 'address_1', 'address_2' ];
...
}
现在,如果恶意用户试图欺骗数组中的另一个属性:
<input name="venue[address_1]" value="...">
<input name="venue[address_2]" value="...">
<input name="venue[address_3]" value="spoof!">
...我们直接使用输入数组来更新模型:
public function update(Request $request, $venueId)
{
$venue = Venue::find($venueId);
$venue->update($request->venue);
...
}
...模型将从输入数组中删除额外的 address_3
元素,因为我们从未将其声明为可填写字段。换句话说,模型净化了输入。
在某些情况下,我们可能需要在不使用 Eloquent 模型的情况下简单地清理数组元素。我们可以使用 array_only()
函数(或 Arr:only()
)来执行此操作:
$venueAddress = array_only($request->venue, [ 'address_1', 'address_2' ]);