我设置了一个基本表单,允许用户更改自己的电子邮件地址,在更改电子邮件之前,我正在对其进行以下验证:
// Set up the form validation
$validator = Validator::make(
Input::all(),
array(
'email' => 'email|unique:users',
'password' => 'required'
)
);
// If validation fails, redirect to the settings page and send the errors
if ($validator->fails())
{
return Redirect::route('settings')->withErrors($validator)->withInput();
}
这很好,但是在这个基本验证之后,我想检查用户是否提供了正确的密码。为此,我正在使用Laravel的基本身份验证库执行以下操作:
// Find the user and validate their password
$user = Auth::user();
if (!Auth::validate(array('username' => $user->username, 'password' => Input::get('password'))))
{
die("failed to authenticate");
}
而不是处理逻辑告诉用户他们的密码本身不正确,我宁愿只是在password
输入中添加一个表单错误,所以它就像常规表单验证一样显示。像这样:
if (!Auth::validate(array('username' => $user->username, 'password' => Input::get('password'))))
{
$validator->addError('password', 'That password is incorrect.');
return Redirect::route('settings')->withErrors($validator)->withInput();
}
这样,我的密码输入旁边会显示错误的密码错误,看起来像是正确的表单验证。
我该怎么做?
答案 0 :(得分:28)
见Darren Craig的回答。
实现它的一种方法。
// inside if(Auth::validate)
if(User::where('email', $email)->first())
{
$validator->getMessageBag()->add('password', 'Password wrong');
}
else
{
$validator->getMessageBag()->add('email', 'Email not found');
}
答案 1 :(得分:8)
接受的答案有一个问题(在我看来,一般是Laravel的验证器) - 验证过程本身和验证状态检测合并为一种方法。
如果您盲目地从包中提交所有验证消息,那没什么大不了的。但是,如果您有一些额外的逻辑来检测验证器是否失败并执行其他操作(例如为当前验证的表单字段提供国际文本消息),那么您就遇到了问题。
演示:
// let's create an empty validator, assuming that we have no any errors yet
$v = Validator::make([], []);
// add an error
$v->errors()->add('some_field', 'some_translated_error_key');
$fails = $v->fails(); // false!!! why???
$failedMessages = $v->failed(); // 0 failed messages!!! why???
另外,
$v->getMessageBag()->add('some_field', 'some_translated_error_key');
产生相同的结果。为什么?因为如果你查看Laravel的Validator代码,你会发现以下内容:
public function fails()
{
return ! $this->passes();
}
public function passes()
{
$this->messages = new MessageBag;
正如您所看到的,fails()
方法基本上清除了丢失所有附加消息的包,从而使验证器认为没有错误。
无法将错误附加到现有验证程序并使其失败。您只能使用以下自定义错误创建新的验证程序:
$v = Validator::make(['some_field' => null],
['some_field' => 'Required:some_translated_error_key']);
$fails = $v->fails(); // true
$failedMessages = $v->failed(); // has error for `required` rule
如果您不喜欢对自定义附加错误滥用required
验证规则的想法,您始终可以使用自定义规则扩展Laravel Validator。我添加了一个通用failkey
规则,并以此方式强制执行:
// in custom Validator constructor: our enforced failure validator
array_push($this->implicitRules, "Failkey");
...
/**
* Allows to fail every passed field with custom key left as a message
* which should later be picked up by controller
* and resolved with correct message namespaces in validate or failValidation methods
*
* @param $attribute
* @param $value
* @param $parameters
*
* @return bool
*/
public function validateFailkey($attribute, $value, $parameters)
{
return false; // always fails
}
protected function replaceFailkey($message, $attribute, $rule, $parameters)
{
$errMsgKey = $parameters[0];
// $parameters[0] is the message key of the failure
if(array_key_exists($errMsgKey, $this->customMessages)){
$msg = $this->customMessages[$parameters[0]];
}
// fallback to default, if exists
elseif(array_key_exists($errMsgKey, $this->fallbackMessages)){
return $this->fallbackMessages[$parameters[0]];
}
else {
$msg = $this->translator->trans("validation.{$errMsgKey}");
}
// do the replacement again, if possible
$msg = str_replace(':attribute', "`" . $this->getAttribute($attribute)
. "`", $msg);
return $msg;
}
我可以这样使用它:
$v = Validator::make(['some_field' => null],
['some_field' => 'failkey:some_translated_error_key']);
$fails = $v->fails(); // true
$failedMessages = $v->failed(); // has error for `Failkey` rule
当然,这仍然是解决问题的一种愚蠢方式。
理想情况下,我会重新设计Validator,以明确区分其验证阶段和状态检测(validate()
和passes()
或更好isValid()
的单独方法),并添加便捷方法以手动失败具体规则的特定字段。虽然这也可能被认为是hacky,但如果我们想要使用Laravel验证器不仅使用Laravel自己的验证规则,而且还使用我们的自定义业务逻辑规则,我们别无选择。
答案 2 :(得分:3)
替代语法:
$validator->errors()
->add('photos', 'At least one photo is required for a new listing.');
答案 3 :(得分:2)
此外,添加以下Redirect::back()
函数可能会有所帮助:
$validator->getMessageBag()->add('password', 'Password wrong');
return Redirect::back()->withErrors($validator)->withInput();
根据
阿尔法
(http://heera.it/laravel-manually-invalidate-validation#.VVt7Wfl_NBc)
答案 4 :(得分:0)
我理解你为什么要这样做,但从安全的角度来看,实际上不好的做法是返回一条消息,指出用户名和/或密码是否不正确。这将允许黑客了解他们是否获得了正确的用户名或密码。
最好返回“您的凭据不正确”这样的通用消息,无论如何您都不希望这些消息显示在您的字段旁边。
答案 5 :(得分:0)
我通过验证和自定义验证解决了类似的问题。在我的情况下,我需要验证带有表单的上传文件是否是有效图像以及发布数据,因此我需要对文件和发布数据的验证测试运行验证测试。当我试图返回我的自定义验证数据时,我遇到了问题,只有Laravel的验证错误存在。根据@JustAMartin的帖子,我已经编写了一个显示所有错误的解决方案。
//Creem una instància del validador. Açò ens permet manipular-lo
$validator = Validator::make($request->all(), [
'nomCompanyia' => 'required',
'urlCompanyia' => 'url'
]);
$imageError = false;
$imgOriginal = null;
$imgMitjana = null;
$imgXicoteta = null;
$fallaValidacio = !$validator->passes(); //-> Retorna true si cap error, false en cas contrari.
if($request->hasFile('logoCompanyia') && !$fallaValidacio)
{
$imatge = $request->file('logoCompanyia');
if($imatge->isValid() && $this->verificaExtensionsImatges($imatge->getClientOriginalExtension(), $imatge->guessExtension()))
{
$sPath = $imatge->store('images/companyies/', 'public');
$fullPathOriginal = public_path() . "/storage/" . $sPath;
$fpInfo = pathinfo($fullPathOriginal);
$imgOriginal = sprintf("%s.%s", $fpInfo['filename'], $fpInfo['extension']);
//Crear les miniatures
$mitjana = Image::make($fullPathOriginal)->widen(300, function ($constraint) {
$constraint->upsize();
});
$imgMitjana = sprintf("%s_300.%s", $fpInfo['filename'], $fpInfo['extension']);
$mitjana->save($fpInfo['dirname'] . '/' . $imgMitjana);
$xicoteta = Image::make($fullPathOriginal)->widen(100, function ($constraint) {
$constraint->upsize();
});
$imgXicoteta = sprintf("%s_100.%s", $fpInfo['filename'], $fpInfo['extension']);
$xicoteta->save($fpInfo['dirname'] . '/' . $imgXicoteta);
}
else
{
$imageError = true;
$validator->getMessageBag()->add('logoCompanyia', "Sembla que el fitxer d'imatge no és vàlid o està corrupte. Només s'accepten els formats: .jpg, .jpeg, .png, .gif");
}
}
else
{
$imageError = true;
$validator->getMessageBag()->add('logoCompanyia', "Sembla que el fitxer d'imatge no és vàlid o ha sigut rebutjat per el servidor si és massa gran.");
}
if($fallaValidacio || $imageError)
{
$data['mode'] = "nou";
$data['urlFormulari'] = "administracio/companyies/afegir";
$data['nomCompanyia'] = $request->nomCompanyia;
$data['idCompanyia'] = 0;
$data['urlCompanyia'] = $request->urlCompanyia;
$data['logoCompanyia'] = $request->logoCompanyia;
$data['errors'] = (object) $validator->errors();
return view($this->formulariTemplate, $data);
}
$companyia = new Companyies();
$companyia->nom = $request->nomCompanyia;
$companyia->url = $request->urlCompanyia;
$companyia->logo_original = $imgOriginal;
$companyia->logo_300 = $imgMitjana;
$companyia->logo_100 = $imgXicoteta;
$companyia->save();
如您所见,我只调用$ validator-> pass()并将结果存储在变量中。当我调用这种方法时,所有的Laravel测试都会产生。如果它们被传递或者没有结果存储在变量中,那么您可以稍后测试您的变量。这允许对文件进行测试以最终确定所有数据是否正常。
如果有错误,我会使用view()帮助器重定向,添加所有数据:输入和错误。如果没有错误,则继续该方法的正常行为。
答案 6 :(得分:0)
如果您使用的是ajax调用,请不要忘记抛出ValidationException
。
if ($subscribed) {
$validator->errors()->add('email', __('Your email is already subscribed.'));
throw new ValidationException($validator);
}
答案 7 :(得分:0)
$validator -> errors() -> add('attribute', 'value');
return redirect($request -> url())
-> withErrors($validator)
-> withInput();
在“值”中,您可以传递任何内容。
答案 8 :(得分:0)
用户Matt K在评论中说laravel has since implemented validation hooks正是我们想要的:
$validator = Validator::make(...);
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->add('field', 'Something is wrong with this field!');
}
});
if ($validator->fails()) {
// this actually runs! even if the original validator succeeded!
}