GETでフォームを開きPOSTで名前を送り、検証結果に応じて表示またはフォームへ戻る流れ

説明と確認結果は2026年10月時点のものです。

名前を入力し、「こんにちは、おじちくさん!」のように入力内容を含む結果を返す小さなフォームを作ります。
私がこのコードで確かめたかったのは、actionでコントローラーを指定しているのか、入力エラーをどこで確認して表示するのかという点です。
この記事では、送信先の決まり方と、ブラウザー・Laravelそれぞれの入力チェックを分けて見ていきます。

入力欄を作るだけでなく、送信先のルート、受け取るコントローラー、入力チェック、エラー時の表示まで順に作ります。
名前をDBへ保存する処理は設けません。
Laravel Framework 13.35.0、PHP 8.3.6で確認したサンプルです。

作る画面とファイル

http://127.0.0.1:8000/learning/greetingでフォームを開き、名前を入れて「挨拶を表示」を押すと、同じ画面に結果を表示します。

名前を送信して挨拶を表示した画面

使うファイルは次の3つです。
パスはLaravelプロジェクトのルートから見たものです。

ファイル 役割
routes/web.php GETとPOSTの送信先を登録
app/Http/Controllers/GreetingController.php 入力検証と画面へのデータ受け渡し
resources/views/learning/greeting.blade.php 入力欄・エラー・結果の表示

PHP・Composer・Laravelプロジェクトが用意されていることが前提です。
ファイルの場所はartisanがあるフォルダーを基準に読みます。
このリポジトリでは実装済みなので、試す場合は重複追加しないでください。
別のプロジェクトでは、artisanのあるフォルダーで以下の作業を行います。

GETとPOSTをコントローラーへつなぐ

まずコントローラーとビューのファイルを作成します。

php artisan make:controller GreetingController --no-interaction
php artisan make:view learning.greeting --no-interaction

routes/web.phpに次の定義を追加します。
useはファイル上部の他のuseと並べ、既存の同じ宣言は重複させません。

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

Route::get('/learning/greeting', [GreetingController::class, 'form'])
    ->name('learning.greeting');
Route::post('/learning/greeting', [GreetingController::class, 'submit'])
    ->name('learning.greeting.submit');

同じURLでも、GETならform()、POSTならsubmit()を呼びます。
GreetingController::classはクラス、配列の2番目はメソッドの名前です。
ブラウザーでURLを開く操作はGET、今回のフォームの送信はPOSTになります。

コントローラーで名前を確認して渡す

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

<?php

namespace App\Http\Controllers;

use Illuminate\Contracts\View\View;
use Illuminate\Http\Request;

class GreetingController extends Controller
{
    public function form(): View
    {
        return view('learning.greeting', ['name' => null]);
    }

    public function submit(Request $request): View
    {
        $validated = $request->validate([
            'name' => ['required', 'string', 'max:40'],
        ], [
            'name.required' => '名前を入力してください。',
            'name.string' => '名前は文字列で入力してください。',
            'name.max' => '名前は40文字以内で入力してください。',
        ]);

        return view('learning.greeting', ['name' => $validated['name']]);
    }
}

form()は初回表示です。
nameをnullにして、まだ挨拶を表示しないことをビューへ伝えます。
submit()のRequest $requestには送信内容などが入ります。
Laravelが要求に応じたRequestを渡すため、自分でnew Request()を作る必要はありません。

validate()では、名前を必須にするrequired、文字列を要求するstring、40文字以内にするmax:40を指定しました。
チェックを通った値だけが$validatedへ返り、ビューの$nameとして渡されます。
: Viewはメソッドがビューを返すという型宣言で、上部のuseでその型を読み込んでいます。

短い例なので検証をコントローラーに置きました。
パスワード生成のように条件が増える場合は、FormRequestへ分離する方法もあります。

Bladeにフォームと結果を書く

resources/views/learning/greeting.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>
    <h1>名前を入力して挨拶を表示</h1>
    <form method="POST" action="{{ route('learning.greeting.submit') }}">
        @csrf
        <label for="name">名前(40文字以内)</label>
        <input id="name" name="name" type="text" maxlength="40" required
            value="{{ old('name', $name) }}" aria-describedby="name-error">
        <p id="name-error" role="status">@error('name'){{ $message }}@enderror</p>
        <button type="submit">挨拶を表示</button>
    </form>

    @if ($name !== null)
        <p id="greeting-result">こんにちは、{{ $name }}さん!</p>
    @endif
</body>
</html>

フォームのmethod="POST"で送信方法を指定します。
actionに入るのは送信先のURLであり、コントローラー名を直接指定しているわけではありません。
route('learning.greeting.submit')は、その名前が付いたルートからURLを生成します。

指定 役割
name('learning.greeting.submit') POSTルートに名前を付ける
route('learning.greeting.submit') 名前から/learning/greetingのURLを作る
method="POST"とactionのURL ブラウザーがPOSTリクエストを送る
[GreetingController::class, 'submit'] ルーターが送信先URLとPOSTに対応するメソッドを選ぶ

同じURLでもGETではform()を呼ぶため、URLだけでなくHTTPメソッドも対応の一部です。
入力欄のname="name"が、コントローラーで検証するキーに対応します。
id="name"はラベルと入力欄の関連付けに使います。

@csrfは、LaravelのCSRF保護に必要なトークンを隠し入力として出力します。
CSRFは、別のサイトなどを経由して意図しない要求を送られる問題への対策です。
今回のWebフォームではこの指定を含めます。

@error('name')は名前のエラーがある場合にメッセージを表示します。
old('name', $name)は、入力エラーで戻った直後の入力値を優先し、それがなければビューに渡された名前を使います。
@ifの部分は$nameがnullでないときだけ挨拶を表示します。

{{ $name }}と{{ old(...) }}はHTML用にエスケープされます。
入力された文字列をHTMLとしてそのまま出力する{!! !!}へ変更しないでください。

入力エラーではフォームへ戻る

通常のブラウザーフォームで検証に失敗すると、validate()は後続処理を進めず、元のフォームへ戻すリダイレクト応答を返します。
エラーメッセージと入力値はセッションへ一時的に渡され、次のGETで表示できます。

DBに名前を保存するコードはありませんが、エラー時の再表示にはセッションを使います。
パスワードなどの秘密値を扱う例へ、そのまま転用することは想定していません。
今回はデザインを加えない最小のHTMLなので、Viteやnpmビルドも不要です。

入力チェックはブラウザーとLaravelで行う

ブラウザーのrequiredは未入力の送信を防ぎ、maxlength="40"は入力できる長さを制限します。
ただし、これらの制限は外せるため、Laravelでもvalidate()で送信内容を検証します。

ブラウザーのメッセージは送信前に表示されます。
Laravelの検証エラーはフォームへ戻った後、@error('name')で入力欄の下に表示されます。

maxlengthを一時解除して41文字を送信した後、サーバーのエラー文を段落に表示した375px幅の実画面

正常入力とエラーを試す

プロジェクトのターミナルでサーバーを起動し、http://127.0.0.1:8000/learning/greetingを開きます。
起動済みなら、そのサーバーを使います。

php artisan serve --host=127.0.0.1 --port=8000
  1. おじちくを送信し、「こんにちは、おじちくさん!」が表示されることを確認します。
  2. 空白だけを送信し、入力欄の下に「名前を入力してください。」が表示されることを確認します。
  3. 開発者ツールで入力欄のmaxlengthを一時的に外して41文字を送信し、「名前は40文字以内で入力してください。」が表示されることを確認します。

確認後はページを再読み込みして、入力欄の制限を元に戻します。

まとめ

今回は、フォームから送った名前をコントローラーで検証し、Bladeで挨拶として表示しました。
URLの登録、入力処理、表示の3か所を分けて読めます。
送信先はroute()が作るURLとHTTPメソッドで決まり、サーバーの検証エラーはBlade内へ表示されます。
ブラウザーの入力制限だけでは確認できない値もあるため、画面操作とHTTPテストを組み合わせて確かめられます。

参考: Laravel 13の入力検証、CSRF保護、Blade