フォームから入力されてくる文字でやっかいなのは、文字列の前後にユーザーのタイプミスで入れられる空白文字。英語では半角のスペース、日本語では全角のスペース。

これらの空白文字を削除してくれる関数はすでにPHPにはあります。

http://php.net/manual/ja/function.trim.php

さて、この関数をララベルのどこで使用するのが適切でしょうか?

まず考えるのは、コントローラ。バリデーションの前に、以下のようにループで空白文字を削除。

public function postSignup(Request $request)
{
    ...

    $trimmed = [];

    foreach($request->all as $key => $val)
    {
        $trimmed[$key] = trim($val);
    }

    $request->merge($trimmed);

    $this->validate($request, $rules, $messages);

    ...

しかし、どこのコントローラでもこれを行うのは面倒です。フォームリクエストという手もありますね。しかし、これもコントローラ1つに対してフォームリクエスト1つを作成すれば、同じ手間。もっとグローバルで対応する手はない?

そこで登場するのは、HTTPミドルウェアです。HTTPミドルウェアは、フォームなどから入力されてくる値をフィルターするためのプログラムです。

フィルターは、

app/Http/Middleware

のディレクトリに存在します。すでに以下のファイルが用意されていて、それぞれのフィルターのカスタマイズを行うことができます。

Authenticate.php ユーザーの認証のため
EncryptCookies.php クッキーの暗号化のため
RedirectIfAuthenticate.php すでに認証されているならリダイレクトするため
VerifyCsrfToken.php セッション乗っ取りを防ぐため

ここに新たなミドルウェアとして空白文字のトリムを入れましょう。


namespace App\Http\Middleware; 

use Closure; class TrimInput {
    /** 
     * Handle an incoming request. 
     * 
     * @param \Illuminate\Http\Request $request 
     * @param \Closure $next 
     * @return mixed 
     */ 
    public function handle($request, Closure $next) { 

        $input = $request->all();

        $trimmed = [];

        foreach($input as $key => $val)
        {
            $trimmed[$key] = trim($val);
        }

        $request->merge($trimmed);

        return $next($request);
    }
}

まず、簡単な対応として、入力されたそれぞれの値に対して半角の空白文字のトリムを実行します。クラス名はファイル名と同様にTrimInputと命名します。既存のクラスを継承する必要はなく、handle()の関数を定義するのみです。

入力の値は、$requestのパラメータからオブジェクトとして取得して、それをトリムした文字列で上書きします。そして、最後には次のフィルターの関数を上書きされたリクエストとともにコールします。

しかし、残念ながらこれだけでは実行されません。以下のファイルにおいて、登録する必要あります。


namespace App\Http; 

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{ 
/**
 * The application's global HTTP middleware stack.
 *
 * @var array
 */ 
    protected $middleware = [
        \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \App\Http\Middleware\TrimInput::class,
    ]; 

/**
 * The application's route middleware.
 *
 * @var array
 */
    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    ];
}

TrimInputは21行目に登録されています。先にリストした他のミドルウェアも入っていますね。

さて、これだけは十分ではありません。いくつか、対応すべき問題があります。

まず、フォームでは日本語の入力を期待するのに、全角スペースの対応ができていません。

また、フォームなどから入力される値は、たいていが文字列ですがPHPでは、配列の[]を使用することで以下のような同型の複数行フォームの入力も可能です。


<form>
...
<div>あなたの趣味を以下に記入してください:</div>
<ul>
  <li><input type="text" name="hobby[]" value=""></li>
  <li><input type="text" name="hobby[]" value=""></li>
...
</form>

この配列での入力値の対応も先のコードでは無理です。そして、動作確認はどうしましょう。空白文字ゆえに画面での確認は難しいです。フォームのユニットテストが必要ですね。これらを含めて次回に仕上げましょう。

By khino