今回はLaravel6を使って、投稿フォームにバリデーション(入力禁止文字)を設定するチュートリアルをやっていきます。
バリデーションというのは、サイト上のフォームに、ふさわしくない文字列を入力し送信した場合、「正しく入力してください」というエラー文を表示して、送信させないようにする事です。
一番分かりやすいのが、空欄のまま送信すると、「この項目は必須です」と出たり、
電話番号欄に文字を入力して送信すると、「数字のみ使えます」と出たりという奴がバリデーションです。
バリデーションは正しく入力してもらうという目的もありますが、ハッキング対策でもあります。
というのも、例えば、フォームにそのままJavascriptを書いて送信すると、それを表示するページを開いた時にJavascriptが実行されてしまうなんていう恐ろしい事も可能だからです。
というわけで、そういったハッカーからの攻撃を防ぐ意味も含めて、バリデーションのやり方を習得していきましょう。
Laravel6チュートリアル:バリデーション(入力禁止文字)でハッカー対策しよう!
このチュートリアルでは、すでにLaravelプロジェクト作成済み(Laravelサイトインストール済み)という前提で話を進めていきます。
もし、まだLaravelサイトを1つも作ってない場合は、この記事を見て、まずはインストールしてね↓
手順としては、
- ブレードで投稿フォームを作成
- コントローラーを作成
- ルートを作成
- バリデーションで禁止文字を作成
という手順でやっていきます。
ブレードで投稿フォームを作成
では、空のテキストエディタを開きます。
下のコードを丸ごとコピーします。
コピーしました
コピー
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>newsite</title>
<!-- Styles -->
<link rel="stylesheet" href="{{ asset('css/style.css') }}">
</head>
<body>
<div class="wrapper">
<div class="header"><h1>お問い合わせ</h1></div>
<div class="content_wrapper">
<div class="content2">
<form action="/enqsend" method="post">
@csrf
@if(count($errors) > 0)
<p><span style="color:red; font-weight:bold;">※エラー部分を修正してね!</span></p>
@endif
<p>タイトル</p>
<input type="text" name="title" class="formtitle" value="{{old('title')}}">
@error('title')
<p class="perror"><span style="color:red;">{{$message}}</span></p>
@enderror
<p> </p>
<p>本文</p>
<textarea name="main" cols="40" rows="10">{{old('main')}}</textarea>
@error('main')
<p class="perror"><span style="color:red;">{{$message}}</span></p>
@enderror
<p> </p>
<p>メールアドレス</p>
<input type="text" name="email" class="formtitle" value="{{old('email')}}">
@error('email')
<p class="perror"><span style="color:red;">{{$message}}</span></p>
@enderror
<p> </p>
<p>電話番号</p>
<input type="text" name="phone" class="formtitle" value="{{old('phone')}}">
@error('phone')
<p class="perror"><span style="color:red;">{{$message}}</span></p>
@enderror
<p> </p>
<input type="submit" class="submitbtn">
</form>
</div>
</div>
</div>
</body>
</html>
コピーしたら、resources\viewsフォルダにcontact.blade.phpという名前で保存してください。
コントローラーを作成
次にコマンドプロンプト(Shell/ターミナル)を開きます。
cd Laravelプロジェクトフォルダへのパス を入力、Enterします。
(例:cd D:\XAMPP\htdocs\newsite)
言ってる事がよく分からない場合は↓
次に
php artisan make:controller ContactController
と入力、Enterします。
app\Http\Controllersフォルダ内にContactController.phpができてるはずです。それを開きます。
そして黄枠部分を追記します。
コピーしました
コピー
public function contact(){
return view('contact');
}
public function enquiry(Request $request){
$data = "\n".$request->title."\n".$request->main."\n".$request->email."\n".$request->phone."\n";
\Storage::append('file.log', $data);
return redirect ('/contact');
}
そして上書き保存してください。
ルートを作成
routes\web.phpを開きます。
以下を追記してください。
コピーしました
コピー
// 問い合わせフォームページ
Route::get('/contact', 'ContactController@contact');
// 問い合わせフォームの送信
Route::post('/enqsend', 'ContactController@enquiry');
そして上書き保存します。
一度、フォームから普通に送信してみよう!
さて、ここまでできたら、一度フォームが正しく動くかブラウザから試してみましょう。
先程のコマンドプロンプトを開き、
php artisan serve と入力してください。
そして、ブラウザを開き、http://localhost:8000/contact にアクセスします。
上の画像のように、フォームができてるはずなので、試しに適当に入力して送信してみてください。
送信後、storage\appフォルダを開いてください。
file.logというのがあると思うので、開いてみてください。
こんな具合に今入力した内容が入ってるはずです。
さて、現時点では、バリデーションが何も設定されてないので、
全部空欄で送信しても、送信されますし、
電話番号の所に文字を入れてもそのまま送信されてしまいます。
では、そういった事を防ぐために、バリデーションを作って、エラーメッセージを返すようにしてみましょう。
バリデーションで禁止文字を作成
ここでコマンドプロンプトを使いますが、先程まで使ってたウィンドウは、php artisan serveしてるので、そのまま開いたまま放置し、新しいコマンドプロンプトウィンドウを開いてください。
cd Laravelプロジェクトフォルダへのパス を入力、Enterします。
(例:cd D:\XAMPP\htdocs\newsite)
次に
php artisan make:request ContactRequest
と入力、Enterします。
app\Http\Requestsフォルダ内にContactRequest.phpができてるはずなので、開いてください。
黄枠部分を上図のように書き換えます。(下のコードと丸っと入れ替えればOKです)
コピーしました
コピー
public function authorize()
{
return true;
}
public function rules()
{
return [
// 空欄OK、特殊記号禁止
'title' => 'nullable|regex:/^[^#<>^;_]*$/',
// 必須、特殊記号禁止
'main' => 'required|regex:/^[^#<>^;_]*$/',
// 必須、Email形式のみOK
'email' => 'required|email',
// 必須、数字と+と半角空欄のみOK
'phone' => 'required|regex:/^[0-9 +]*$/'
];
}
public function messages()
{
return[
'title.regex' => '使用禁止記号#<>^;_を消してください',
'main.required' =>'必須 (required)',
'email.required' =>'必須 (required)',
'phone.required' =>'必須 (required)',
'main.regex' => '使用禁止記号#<>^;_を消してください',
'email.email' =>'正しいEmail形式で入力ください',
'phone.regex' =>'使えるのは、数字と+のみです'
];
}
これで上書き保存してください。
バリデーションルールの書き方
このrequestファイルは、フォームの送信許可条件(バリデーションルール)を書くファイルです。
まず、一番上のfunction authorizeですが、
元々はreturn falseになってますが、falseだと全て受け付けないという意味なので、trueに変える事で、フォーム送信が可能になります。
ここに例えば「ログインユーザーはtrue、未ログインユーザーはfalse」のような条件をif文などを使って書く事もできます。
次の function rulesですが、
Laravelの「バリデーションルールタグ」と「正規表現(regex)」という2種類のタグを使って、フォームの空欄に入力された値に条件を付ける事ができます。
例えば、先程作ったブレードの、入力必須にしたい入力欄がname="phone"だとしたら、
'phone' => 'required' と書けば、入力必須になります。
emailの欄は、emailというルールを入れる事で、〇〇@〇〇の形しか受け付けなくしてます。
他にも、title欄の場合、nullable(空欄でもOK)という条件をまず書き、さらに条件をもう一つ加えたいので、|を入れ、regex(正規表現)として、#<>^;_のような特殊記号はこの空欄では使えないようにしてあります。
なぜ記号の一部を禁止するかというと、フォームを悪用したハッキングを防ぐためです。
例えば、仮にフォームに以下のように、javascriptのタグを入れて送信されたとします。
すると、この投稿が表示される記事ページを開いた時に、このJavascriptが実行され↓
こんなふうに勝手にポップアップ表示させる事ができてしまいます。
なので、最初からこういった攻撃スクリプトが送れないように、タグによく使われる記号をフォームでは使えないように禁止してしまうわけです。
もちろん、フォームでこれらの記号を禁止せず、使いたい欄もありますよね。そんな時は、バリデーションは使わず、エスケープというタグを文字化する処理を施す事でハッキング対策をする事も可能です。
正規表現の基礎的な書き方
regex: と書いた後からが正規表現になっていて、
/^[ ]*$/ で囲まれた部分の中の文字を許可してます。
なので、phoneの中には、その[ ]内の0-9の数字と空白と+のみが入力OKという事です。
逆に、先頭に^を付ける事で、禁止文字にする事もできるので、^#<>^;_とする事で、
#<>^;_は使用禁止になるわけです。
参考
このrequiredのようなバリデーションルールですが、Laravel公式ページの「使用可能なバリデーションルール」項目に一覧が書かれてます。
正規表現は「ひらがなのみ可」など超細かい設定ができる反面、複雑なので「正規表現 ひらがなのみ」のようにググって自分の作りたい条件の書き方を探すと良いです。
エラーメッセージを自分で作る
そして、messagesメソッド部分ですが、
これは、エラーメッセージを自分で作れます。
例えば、title欄で禁止文字が使われた場合は、title.regexとして、使いたい文言を書きます。
email欄にemail形式ではない文が入力されると、正しいEmail形式で入力くださいと表示されるようにしてるわけです。
これで、ファイルを上書き保存します。
コントローラーに条件をセットする
次に先程のContactController.phpを開きます。
赤線2箇所を追記(編集)します。
まず、
use App\Http\Requests\ContactRequest;
の一文を追記します。
そして、enquiryメソッドのRequestをContactRequestに書き換えます。
これで、コントローラーのenquiryメソッドの命令が発動する前に、先にContactRequestファイルの検閲が入り、検閲に引っかかった場合は、コントローラーに進まずに、そのままフォームに返されるようになりました。
では、実際にフォームを使って、バリデーションが効いてるか試してみましょう!
バリデーションをテストする
ブラウザから、http://localhost:8000/contact にアクセスしてください。
そして、バリデーションに引っかかるであろう文字を入力しましょう。
これで送信してみます。すると・・
このように、先程作ったエラー文が表示され、そのまま戻されるわけです。
→419 Page Expired とLaravelでフォーム送信時に出た時の対処法
ちなみに、これ、ちょっとした仕掛けをしないと、
バリデーションで画面を戻した時に、入力した値が全部消えてしまいます。
このように、inputなら、value={{old('name')}} 、textareaなら、タグの間に{{old('name')}} と入れないと、せっかくフォーム入力したデータが、エラーで戻った際に全部消えてしまいますので、気をつけてください。
また、@error('name')~{{$message}}~@enderror というのもありますよね。これがエラー文を表示してる部分です。エラー文を表示したい位置に@errorを入れるというわけです。