速習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' => '本文',
),
これで全部日本語で表示されます。