技術資料

Laravel 13でBladeの新規登録フォームを作成する:バリデーション・CSRF・入力値の再表示

作成日:2026.08.21

Laravel 13のBladeで、既存のmembersテーブルへnameとemailを登録する新規登録フォームを作成します。$request->validate()による入力値の検証、@csrfによるCSRF対策、@errorによるエラー表示、old()による入力値の再表示、登録後のリダイレクトメッセージまでを確認します。

前回は、Laravel 13でSQLiteを使い、membersテーブルとMember Modelを用意して、TinkerからCRUDを実行しました

今回はその続きとして、Bladeで新規登録フォームを作成します。フォームへ入力した名前とメールアドレスをバリデーションし、問題がなければmembersテーブルへ保存します。入力に誤りがある場合は、エラーメッセージを表示し、入力済みの値をフォームへ戻します。

今回はLaravelのフォーム処理に絞って確認します。

前提

今回の対象環境は以下の通りです。

  • OS: Windows 11
  • PHP: 8.3以上
  • Composer
  • Laravel Framework: 13.x
  • SQLite
  • ターミナル: PowerShell

Laravel 13のプロジェクトを作成し、SQLiteの設定とmembersテーブルのMigration、Member Modelを用意している状態から始めます。プロジェクトの作成方法や、テーブルの準備については、次の記事を参照してください。

前回作成したmembersテーブルには、今回使用するnameemailのカラムがあります。

members
├─ id
├─ name
├─ email
├─ created_at
└─ updated_at

このテーブルは説明用のものです。Laravelの認証用ユーザーを管理するテーブルではありません。

フォーム処理の流れ

今回は、フォームを表示する処理と、入力値を登録する処理を分けます。

GET /members/create
    ↓
MemberController@create
    ↓
resources/views/members/create.blade.php

POST /members
    ↓
MemberController@store
    ↓
バリデーション
    ↓
Member::create()
    ↓
登録完了メッセージを付けてフォームへリダイレクト

入力値に問題がなければ、検証済みの値だけをMember Modelへ渡します。バリデーションに失敗した場合は、Laravelが元のページへリダイレクトし、エラー情報と入力値を次のリクエストで利用できるようにします。

Member Modelの設定を確認する

今回は、Controllerから配列をMember::create()へ渡します。Modelに保存を許可する属性を指定しておく必要があるため、app/Models/Member.phpを確認します。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Model;

#[Fillable(['name', 'email'])]
class Member extends Model
{
    //
}

#[Fillable(['name', 'email'])]は、配列から保存できる属性をnameemailに限定する設定です。リクエストの入力値をそのままModelへ渡すのではなく、後ほどバリデーション済みの値だけを渡します。

この設定は、前回の記事でMember::create()を使う場合の例として紹介したものです。すでに同じ設定を追加している場合は、重複して記述する必要はありません。

ルートを追加する

まず、routes/web.phpへフォーム表示用と登録処理用のルートを追加します。

<?php

use App\Http\Controllers\MemberController;
use Illuminate\Support\Facades\Route;

Route::get('/members/create', [MemberController::class, 'create'])
    ->name('members.create');

Route::post('/members', [MemberController::class, 'store'])
    ->name('members.store');

GETの/members/createはフォームを表示します。フォームを送信したときは、POSTの/membersへリクエストを送ります。

POST処理に別のURLを使うこともできますが、今回はLaravel公式のバリデーション例に近い構成にしています。ルート名を付けておくと、Bladeのroute()でURLを生成できるため、URLを直接書く箇所を減らせます。

Controllerを作成する

Controllerがまだない場合は、プロジェクトのルートディレクトリで次のコマンドを実行します。

php artisan make:controller MemberController

app/Http/Controllers/MemberController.phpを、次の内容にします。

<?php

namespace App\Http\Controllers;

use App\Models\Member;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;

class MemberController extends Controller
{
    public function create(): View
    {
        return view('members.create');
    }

    public function store(Request $request): RedirectResponse
    {
        $validated = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'email', 'max:255'],
        ], [
            'name.required' => '名前を入力してください。',
            'name.string' => '名前は文字列で入力してください。',
            'name.max' => '名前は255文字以内で入力してください。',
            'email.required' => 'メールアドレスを入力してください。',
            'email.email' => 'メールアドレスの形式で入力してください。',
            'email.max' => 'メールアドレスは255文字以内で入力してください。',
        ]);

        Member::create($validated);

        return to_route('members.create')
            ->with('success', 'メンバーを登録しました。');
    }
}

createメソッドでは、フォーム用のBladeを返します。storeメソッドでは、最初に入力値を検証し、検証に成功した場合だけMember::create()を実行します。

$request->validate()は、バリデーションに成功すると検証済みの値を返します。失敗した場合は、その後のMember::create()まで処理が進みません。

バリデーションルール

今回指定したルールは、次の通りです。

  • required: 値の入力を必須にする
  • string: 文字列であることを確認する
  • email: メールアドレスの形式を確認する
  • max:255: 255文字以内であることを確認する

今回はmembers.emailに、同じメールアドレスの重複チェックは行っていません。実際の会員登録機能で重複を禁止する場合は、データベースとバリデーションルールを別途設計します。

Bladeで新規登録フォームを作成する

resources/views/members/create.blade.phpを作成します。

<!doctype html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>メンバー登録</title>
</head>
<body>
    <main>
        <h1>メンバー登録</h1>

        @if (session('success'))
            <p>{{ session('success') }}</p>
        @endif

        <form method="POST" action="{{ route('members.store') }}">
            @csrf

            <div>
                <label for="name">名前</label>
                <input
                    id="name"
                    type="text"
                    name="name"
                    value="{{ old('name') }}"
                >
                @error('name')
                    <p>{{ $message }}</p>
                @enderror
            </div>

            <div>
                <label for="email">メールアドレス</label>
                <input
                    id="email"
                    type="email"
                    name="email"
                    value="{{ old('email') }}"
                >
                @error('email')
                    <p>{{ $message }}</p>
                @enderror
            </div>

            <button type="submit">登録</button>
        </form>
    </main>
</body>
</html>

フォームのmethodはPOST、送信先は登録処理用のmembers.storeルートです。LaravelのBladeでは、route()の結果やセッションのメッセージを、通常のBlade記法でHTMLへ出力できます。

@csrfを追加する

@csrfは、フォームへCSRFトークンを埋め込むBladeディレクティブです。HTMLへ変換されると、hidden属性の入力項目として出力されます。

Laravel 13のリクエスト偽造対策では、ブラウザが送信するOrigin情報を確認する処理と、CSRFトークンを確認する処理が使われます。接続条件やブラウザによってOriginの確認が利用できない場合は、従来のトークン検証へ進みます。そのため、POST、PUT、PATCH、DELETEのHTMLフォームには、明示的に@csrfを含めておくのが基本です。

@csrfを省略した場合の結果は、Laravelの設定やリクエスト条件によって異なります。トークン検証が行われる条件では、CSRFトークンの不一致としてリクエストが拒否されることがあります。CSRF対策を無効にして送信を通すのではなく、フォームへ@csrfを追加するようにします。

old()で入力値を再表示する

バリデーションに失敗すると、Laravelは入力値を次のリクエストで利用できるようにします。Bladeではold('name')old('email')を使うと、直前に入力した値をvalue属性へ戻せます。

例えば、名前を入力した状態でメールアドレスの検証に失敗すると、フォームへ戻ったときに名前をもう一度入力する必要がありません。

@errorでエラーを表示する

@error('name')は、nameのバリデーションエラーが存在する場合に、ブロック内を表示します。エラーメッセージは、ブロック内で利用できる$messageに入っています。

今回はController側で日本語のメッセージを指定しているため、画面には「名前を入力してください。」や「メールアドレスの形式で入力してください。」などが表示されます。

フォームを表示する

Laravelの開発サーバーを起動します。

php artisan serve

ブラウザで次のURLを開きます。

http://127.0.0.1:8000/members/create

名前とメールアドレスの入力欄、「登録」ボタンが表示されれば、GETルート、Controller、Bladeの接続を確認できています。

バリデーションの動作を確認する

必須項目を空にして送信する

何も入力せずに「登録」をクリックします。

バリデーションに失敗すると、ControllerのMember::create()は実行されず、元のフォーム画面へ戻ります。画面には、次のエラーメッセージが表示されます。

  • 名前を入力してください。
  • メールアドレスを入力してください。
メールアドレスの形式を確認する

名前に「テストユーザー」、メールアドレスに「invalid」などを入力して送信します。

メールアドレスの形式が正しくないため、メールアドレス欄に「メールアドレスの形式で入力してください。」と表示されます。名前の入力値はold('name')によって再表示されます。

この時点では、バリデーションに失敗しているため、membersテーブルへレコードは追加されません。

正しい値を入力する

次のような値を入力します。

  • 名前: テストユーザー
  • メールアドレス: user@example.test

「登録」をクリックしてバリデーションに成功すると、Member::create($validated)が実行され、membersテーブルへレコードが追加されます。

登録後は、members.createへリダイレクトし、画面に「メンバーを登録しました。」と表示します。今回のフォームには一覧画面を用意していないため、登録結果は次のTinkerで確認します。

php artisan tinker
App\Models\Member::orderByDesc('id')
    ->first(['id', 'name', 'email']);

直前に登録したnameemailが表示されれば、フォームからデータベースまでの処理を確認できています。確認が終わったら、Tinkerでexitを入力します。

うまく動かない場合

419やCSRFに関するエラーになる

まず、Bladeのフォーム内に@csrfがあるか確認します。フォームのmethodがPOSTになっているか、送信先がmembers.storeルートになっているかも確認してください。

セッションを利用できない状態や、Cookieが無効になっている状態でも、CSRFトークンの検証に失敗することがあります。ブラウザのCookie設定、.envのセッション設定、Laravelのログも確認します。

MassAssignmentExceptionになる

Member::create($validated)でMass Assignmentに関する例外が発生する場合は、Member Modelに#[Fillable(['name', 'email'])]が設定されているか確認します。

また、$validatedに含まれるキーと、Fillableで許可したキーが一致しているかも確認します。今回のフォームでは、保存対象をnameemailに限定しています。

View [members.create] not foundになる

Controllerではview('members.create')を指定しているため、Bladeファイルは次の場所に必要です。

resources/views/members/create.blade.php

ディレクトリ名、ファイル名、.blade.phpの拡張子が一致しているか確認します。

could not find driverになる

SQLiteへ接続するときにcould not find driverと表示される場合は、PHPのSQLite用PDO拡張が有効になっていない可能性があります。

php --ini
php -m | Select-String -Pattern 'PDO|sqlite'

pdo_sqlitesqlite3が表示されるか確認します。PHPを複数インストールしている場合は、PowerShellで実行しているPHPと、Laravelが想定しているPHPが一致しているかも確認してください。

注意点

  • 今回のmembersテーブルは、フォーム処理を確認するための説明用テーブルであり、Laravelの認証用ユーザー管理ではない。
  • メールアドレスの形式を検証しても、実在性やメールの到達性まで確認できるわけではない。
  • フォームから受け取った値は、バリデーション済みの値だけをModelへ渡す。
  • Bladeで入力値やメッセージを出力するときは、基本的に{{ }}を使う。{!! !!}で未検証の値をHTMLとして出力しない。
  • CSRF対策を無効にしてフォーム送信を通すのではなく、対象フォームへ@csrfを追加する。
  • 実際の会員登録機能では、認証、認可、重複メールアドレス、個人情報保護、レート制限などを別途設計する。

まとめ

今回は、前回作成したmembersテーブルとMember Modelを使い、Bladeで新規登録フォームを作成しました。

フォームには@csrfを追加し、Controllerでは$request->validate()nameemailを検証しました。検証に成功した値だけをMember::create()へ渡すことで、フォームからSQLiteへデータを登録できます。

バリデーションに失敗したときは、@errorでエラーを表示し、old()で入力済みの値を再表示しました。Laravelのフォーム処理では、入力画面、Controllerの検証と保存、エラー時の戻し方を分けて考えると、処理の流れを整理しやすいかと思います。

詳しい仕様は、Laravel公式のValidationCSRF ProtectionEloquentも参照してください。

この記事を書いた人

※上が私です。

奈良市を拠点に、27年以上の経験を持つフリーランスWebエンジニア、阿部辰也です。

これまで、ECサイトのバックエンド開発や業務効率化システム、公共施設の予約システムなど、多彩なプロジェクトを手がけ、企業様や制作会社様のパートナーとして信頼を築いてまいりました。

【制作会社・企業様向けサポート】
  • 専任エンジニアのいない企業様に対するシステム面の不安を解消
  • 柔軟な契約形態や短納期での対応により、急なニーズにも迅速にサポート
  • システムの企画段階から運用まで、ワンストップでのサービスを提供

Webシステムの開発やサイト改善でお困りの際は、どうぞお気軽にご相談ください。小さな疑問から大規模プロジェクトまで、最適なご提案を心を込めてさせていただきます。

ぜひ、プロフィールWeb制作会社様向け業務案内一般企業様向け業務案内もご覧くださいね。

Laravel Pintの使い方:PHPコードの書式を整えてCIで検査する

2026.09.15

Laravel Pintを使ってPHPコードの書式を整える方法を紹介します。ローカルでの自動修正、CIで書式違反だけを検査する--test、対象範囲の指定、pint.jsonの設定、Bladeファイルを扱う際の注意点を整理し、Pintを導入する判断基準も説明します。

CI/CD Laravel PHP

GitHub ActionsでPHP・LaravelのCIを始める:テスト・Lint・ビルドを自動化するWorkflowの基本

2026.09.13

PHP・Laravelプロジェクトを対象に、GitHub ActionsのWorkflow、イベント、ジョブ、ステップの基本を説明します。Composerのテスト、npm ci、フロントエンドビルド、Laravel PintをCIへ組み込む方法に加え、featureブランチやPull Requestで実行される条件、失敗時のログ確認、Secrets・権限・Actionのバージョン管理についても整理します。

CI/CD GitHub Laravel PHP

Laravel 13でArtisanコマンドを作成する:引数・オプション・dry-runの基本

2026.09.10

Laravel 13でArtisanコマンドを作成する方法を、引数・オプション・コンソール出力・終了コードの基本から解説します。日時指定した記事を定期的に公開するDB更新処理を例に、--dry-runで対象を確認してから安全に実行する方法や、スケジューラー・cronでの定期実行についても紹介します。

Laravel PHP

LaravelのFeature Testで開発用DBを初期化してしまった:Codex運用で学ぶテストDBの多層防御

2026.09.07

CodexにLaravelのFeature Test実行を依頼した際、テスト用DBではなくローカルの開発用DBへ接続した状態でRefreshDatabaseが実行され、データが失われる事故が発生しました。この記事では、PHPUnitのforce="true"による環境変数固定、DB_URLの無効化、config:clearのComposer Script化、Laravel起動後のDB接続先ガード、通常テストとIntegration Testの分離など、テストDBの誤接続を防ぐ多層防御を紹介します。

Codex Laravel PHP

阿部辰也へのお仕事の依頼・お問い合わせ

軽いご相談もお気軽にどうぞ!

個人情報の取り扱いについて *必須 プライバシーポリシーをご確認いただき、同意いただける場合は「同意する」にチェックをしてください。

keyboard_double_arrow_up
TOP