LaravelのミドルウェアはHttpのGETやPOSTなどのリクエストでアプリに入ってくるリクエストの中身をチェックしたり必要なら変えたりする重要なコードです。このミドルウェアの設定は、L11.x以前ではapp/Http/Kernel.phpというファイルの中身に含まれていてわかりやすかったのですが、L11.x以降はLaravelのライブラリの奥に入ってしまい日の目をみなくなってしまいました。これらを引っ張りだしてLaravelのミドルウェアがどのように使用されているか紹介します。

グローバルミドルウェア

リクエストをグローバルに処理するミドルウェアは、グローバルミドルウェアと呼ばれ、tinkerでの以下の実行でデフォルトの設定を見ることができます。

> use Illuminate\Foundation\Configuration\Middleware;

> (new Middleware)->getGlobalMiddleware();
= [
    "Illuminate\Foundation\Http\Middleware\InvokeDeferredCallbacks",
    "Illuminate\Http\Middleware\TrustProxies",
    "Illuminate\Http\Middleware\HandleCors",
    "Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance",
    "Illuminate\Http\Middleware\ValidatePostSize",
    "Illuminate\Foundation\Http\Middleware\TrimStrings",
    "Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull",
  ]

それぞれのミドルウェアのクラスは独立した役割がありますが、ここでの紹介は比較的理解しやすい最後の2つに絞ります。

TrimStrings

このミドルウェアはHttpのGETやPOSTなどのリクエストのデータに含まれる文字列の前後の空白文字を削除します。
ここでの空白文字はすべていわゆる半角文字の範囲で、

  • 空白
  • 改行(\n)
  • 復帰(\r)
  • タブ(\t)
  • 垂直タブ(\v)
  • ヌル文字(\0)

が含まれます。日本語の全角空白文字が含まれないことに注意を。
また、以下のユニコードも削除されます。

  • 表示不可能な文字(\x{FEFF})
  • ゼロ幅スペース(\x{200B})
  • 左から右へのマーク(\x{200E})

削除されるのは文字列中でなく前後であることに注意を。

早速、tinkerで実行してみましょう。

まずは、Requestのインスタンスを作成します。 app()を使うと簡単に作成できます。

> $request = app('request');
= Illuminate\Http\Request {#207
    +attributes: Symfony\Component\HttpFoundation\ParameterBag {#208},
    +request: Symfony\Component\HttpFoundation\InputBag {#197},
    +query: Symfony\Component\HttpFoundation\InputBag {#209},
    +server: Symfony\Component\HttpFoundation\ServerBag {#93},
    +files: Symfony\Component\HttpFoundation\FileBag {#196},
    +cookies: Symfony\Component\HttpFoundation\InputBag {#204},
    +headers: Symfony\Component\HttpFoundation\HeaderBag {#100},
  }

そして、そのリクエストにユーザーの入力をシミュレートした連想配列をマージします。
もちろん、nameの値の前後にしっかりと空白文字を入れてあります。

> $request->merge(['name' => '    山田太郎    '])->all();
= [
     "name" => "    山田太郎    ",
  ]

今度はこのリクエストにTrimStringsのミドルウェアを適用します。

> use Illuminate\Foundation\Http\Middleware\TrimStrings;

> (new TrimStrings)->handle($request, fn($request) => $request)->all();
= [
    "name" => "山田太郎",
  ]

前後の空白文字が削除されましたね。

handle()のパラメーターは2つ必要されます。最初はリクエストのインスタンス、次はクロージャとして次のミドルウェアを渡します。
それゆえに最初に掲載したグローバルミドルウェアが順々にリクエストに処理を加えていきます。
ここでは、単に、処理されたリクエストを返すクロージャを与えています。

ConverEmptyStringsToNull

ConvertEmptyStringsToNullは、先のTrimStringsの次に適用されるミドルウェアで、今度は空の文字列をnullに変換する処理を行います。

このミドルウェアをデモするために、今度は空の値のemailの連想配列をリクエストにマージします。

> $request->merge(['email' => ''])->all();

= [
    "name" => "山田太郎",
    "email" => "",
  ]

先ほどTrimpStringsのミドルウェアを適用された同じリクエストを使用しために、nameの値が残っていることに注意を。

このリクエストに対して、ConvertEmptyStringsToNullを適用します。

> use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;

> (new ConvertEmptyStringsToNull)->handle($request, fn($request) => $request)->all();
= [
    "name" => "山田太郎",
    "email" => null,
  ]

空の文字列がnullに変換されましたね。

グローバルミドルウェアをすべて適用

最後に、最初に掲載したグローバルミドルウェアをすべてリクエストに適用するコードを紹介します。

Laravelでは以下の関数で、Pipelineのクラスを使用してリクエストをそれぞれのミドルウェアを順に適用していき最後にルートとでマップしているコントローラなどへ渡してます。


    /**
     * Send the given request through the middleware / router.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    protected function sendRequestThroughRouter($request)
    {
        $this->app->instance('request', $request);

        Facade::clearResolvedInstance('request');

        $this->bootstrap();

        return (new Pipeline($this->app))
            ->send($request)
            ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
            ->then($this->dispatchToRouter());
    }

上のコードを元に、tinkerで実行できるようにしてみました。

> use Illuminate\Foundation\Configuration\Middleware;

> $middlewares = (new Middleware)->getGlobalMiddleware();

> $request = app('request')->merge(['name' => '   山田太郎   ', 'email' => '']);

> use Illuminate\Pipeline\Pipeline;

> app(Pipeline::class)->send($request)->through($middlewares)->thenReturn()->all();
= [
    "name" => "山田太郎",
    "email" => null,
  ]
メルマガ購読の申し込みはこちらから。

By khino