速習Larave3(その3)、バリディーションとCSRF対策
タグ: Laravel3
今回は入力のバリデーションとCSRF対策を追加しましょう。
ソース:github
- 参照:フォームの作成
- 参照:パリディーション
- 参照:ルーティング:フィルター
まずは追加フォームをご覧ください。application/views/add.blade.php
でしたね。
@layout('template') @section('title') 記事追加 @endsection @section('content') {{ Form::open() }} <div> {{ Form::label('title', 'タイトル') }}<br> {{ Form::text('title', Input::old('title', '')) }} @if ($errors->has('title')) <p style="color: red;">{{ $errors->first('title') }}</p> @endif </div> <div> {{ Form::label('body', '本文') }}<br> {{ Form::textarea('body', Input::old('body', '')) }} @if ($errors->has('body')) <p style="color: red;">{{ $errors->first('body') }}</p> @endif </div> <div> {{ Form::submit('送信') }} </div> {{ Form::token() }} {{ Form::close() }} @endsection
バリデーションを行い、引っかかった場合のエラーメッセージを表示する処理が追加されています。$errorsはバリデーションを実行することで、Validatorクラスが生成するMessageクラスのインスタンスです。has()メソッドで存在をチェックし、first()メソッドで、最初の一つだけを取り出します。もし、行いたければforeachで回して、その項目に発生したバリデーションエラーを全部表示することも可能です。
Tips!! @ifを使用せずとも、Messageクラスのfirst()は実際のメッセージを持たない場合、何も表示しません。Messageクラスは各メッセージをHTML要素を付け加え出力することもできます。お好みでお好きな手法を取れます。今回はビューで何を行なっているのかが明確なため、@ifを使用する方法を採用しています。
なお、この$errors変数は特別で、Laravelにより自動的にセッションから'errors'というキーを持つ保存値がビューにセットされます。いちいち開発者が自分でビューに渡す必要はありません。
さらに、Formクラスのtoken()を追加しています。これはCSRF対策として隠しフィールドにランダムに生成されたトークンを埋め込んでくれるものです。トークンはセッションに自動保存されます。この2つを比較すれば、送信されたばかりのフレッシュなフォームから入力が返ってきたのか判断がつくわけです。
では、処理を確認するためにroutes.php
をご覧ください。前回から変更するのはpost/add
のPOSTメソッドに対するルートです。
// フォーム処理 Route::post('/post/add', array( 'as' => 'post-add', 'before' => 'csrf', function() { // バリディーションルール $rules = array( 'title' => 'required|max:50', 'body' => 'required|max:8000', ); $input = Input::only(array( 'title', 'body' )); $val = Validator::make($input, $rules); if ( $val->passes() ) { // バリデーション通過 // 新ポストの追加 $post = new Post($input); $post->save(); // 更に追加の可能性があるため、 // フォームは空のままリダイレクト return Redirect::to_route('post-add'); } else { // バリデーション失敗 // バリディーションで生成されたエラーと // フォームに入力された内容を // セッションのフラッシュデーターを通じ // フォームに送る return Redirect::to_route('post-add') ->with_errors($val->errors) ->with_input(); } } ));
CSRF対策に入れたコードは'before' => 'csrf',
の部分だけです。Laravelではルート実行の前後にフィルターを指定できます。ルート前にcsrf
フィルターをチェックするように指定しました。
このフィルターの実装もroutes.phpの中で定義されています。
Route::filter('csrf', function() { if ( Request::forged() ) return Response::error('500'); });
ビューの所で説明したCSRFトークンを比較しています。もし異なっていれば不正なフォームからの送信だと判断します。デフォルトでは500、つまり内部エラーとして表示されます。これもお好きなように変更できます。
さて、route.phpに戻りましょう。バリディーションのコードも確認してください。ルールを定義し、バリディーションのインスタンスを生成し、実行した結果で、処理を分けています。どのフレームワークでも同じような処理になりますね。Laravelの場合、エラーであることをチェックするfails()
だけでなく、逆のpasses()
が用意されています。(無駄?ええ、でも皆さん各自のコーディングの好みに合わせるためですよ。)
説明のため、コメントを入れてあり長いですが、コメントを外しても、そのまま読めます。それがLaravelの可読性の良さです。
さて、実行してみましょう。ちゃんとエラーになることを確認してください。
あれ、残念ながらメッセージが英語ですね。それは、Laravelの言語設定がデフォルトの英語のままだからです。application/config/application.php
を開き、language
をja
に変更してください。メッセージが日本語に変わります。複数形のlanguages
ではありませんよ。注意してください。
エラーメッセージ中に表示される項目名も日本語にしたい場合はapplication/language/ja/validation.php
のattributes
アイテムに指定します。
'attributes' => array( 'title' => 'タイトル', 'body' => '本文', ),
これで全部日本語で表示されます。