2014-03-03 46 views
9

我有一個基本的形式設置爲允許用戶更改他們的電子郵件地址,我做它下面的驗證之前,我改變了電子郵件:添加自定義驗證錯誤Laravel形式

// 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(); 
} 

這樣一來,密碼不正確的錯誤會顯示我旁邊的密碼輸入,看起來像適當的形式驗證。

我該怎麼做?

回答

18

查看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'); 
} 
+0

不知道爲什麼我需要檢查電子郵件,但郵件包的東西工作,謝謝。 :) –

+0

這很酷。我仍然不會傾向於混合我的驗證錯誤和應用程序消息。 –

+0

這太棒了。 – enchance

0

我明白你爲什麼要這樣做,但從安全的角度來看,它實際上是一種錯誤的做法,要返回一條指示用戶名和/或密碼是否不正確的消息。這將允許黑客瞭解他們是否獲得了正確的用戶名或密碼。

最好是返回一個類似'您的憑據不正確'的通用郵件,您不希望在字段旁邊顯示該郵件。

+1

雖然這是在他們的帳戶設置更改電子郵件頁面。如果他們到了這一點,他們已經擁有了用戶的憑據。 –

2

替代語法:

$validator->errors() 
      ->add('photos', 'At least one photo is required for a new listing.'); 
4

有一個問題與接受的答案(和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的驗證碼,你會發現以下內容:

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驗證。我添加了一個通用的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 

當然,這仍然是解決這一問題的哈克的方式。

理想情況下,我會重新設計驗證(對於validate()passes()或更好isValid()單獨的方法),以明確地分開狀態檢測其驗證階段,並且還添加方便的方法來手動故障與特定的規則的特定字段。雖然這也可能會被認爲是hacky,但是如果我們想要使用Laravel驗證器不僅僅是Laravel自己的驗證規則,還有我們的自定義業務邏輯規則,我們也別無選擇。

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-> passes()進行一次調用,並將結果存儲在一個變量中。當我打電話給這個方法時,所有的Laravel測試都已經完成。如果它們被傳遞或者結果不存儲在變量中,那麼您可以稍後測試您的變量。這允許對文件進行測試以最終確定所有數據是否正確。

如果出現錯誤,我使用view()助手重新導向,添加所有數據:輸入和錯誤。如果沒有錯誤,則該方法的正常行爲繼續。

相關問題