コントローラフィルタ

コントローラフィルタを使用すると、コントローラの実行前または実行後にアクションを実行できます。イベントとは異なり、フィルタが適用される特定の URI またはルートを選択できます。ビフォアフィルタは Request を変更できますが、アフターフィルタは Response に作用し、変更することもできるため、非常に柔軟で強力です。

フィルタで実行できるタスクの一般的な例を以下に示します。

  • 着信リクエストに対して CSRF 保護を実行する

  • サイトの領域をロールに基づいて制限する

  • 特定のエンドポイントでレート制限を実行する

  • 「メンテナンス中」ページを表示する

  • 自動コンテンツネゴシエーションを実行する

  • などなど…

フィルタの作成

フィルタは、CodeIgniter\Filters\FilterInterface を実装する単純なクラスです。これらには、それぞれコントローラの前後に実行されるコードを保持する 2 つのメソッド、before()after() が含まれています。クラスには両方のメソッドを含める必要がありますが、必要ない場合はメソッドを空のままにすることができます。スケルトンフィルタークラスは次のようになります。

<?php

namespace App\Filters;

use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;

class MyFilter implements FilterInterface
{
    public function before(RequestInterface $request, $arguments = null)
    {
        // Do something here
    }

    public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
    {
        // Do something here
    }
}

ビフォアフィルタ

Request の置き換え

任意のフィルタから、$request オブジェクトを返すと、現在の Request が置き換えられ、コントローラが実行されるときに存在し続ける変更を行うことができます。

後続のフィルタの停止

また、一連のフィルタがある場合、特定のフィルタの後に後続のフィルタの実行を停止することもできます。空でない結果を返すことで、これを簡単に行うことができます。ビフォアフィルタが空の結果を返した場合、コントローラのアクションまたは後続のフィルタは引き続き実行されます。

空でない結果ルールに対する例外は、Request インスタンスです。ビフォアフィルタでそれを返しても実行は停止しませんが、現在の $request オブジェクトのみが置き換えられます。

Response の返却

ビフォアフィルタはコントローラが実行される前に実行されるため、場合によってはコントローラでのアクションの実行を停止したい場合があります。

これは通常、次の例のようにリダイレクトを実行するために使用されます。

<?php

namespace App\Filters;

use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;

class MyFilter implements FilterInterface
{
    public function before(RequestInterface $request, $arguments = null)
    {
        $auth = service('auth');

        if (! $auth->isLoggedIn()) {
            return redirect()->to(site_url('login'));
        }
    }
}

Response インスタンスが返された場合、Response はクライアントに返送され、スクリプトの実行は停止します。これは、API のレート制限を実装するのに役立ちます。例については、Throttler を参照してください。

アフターフィルタ

アフターフィルタは、$response オブジェクトのみを返すことができること、およびスクリプトの実行を停止できないことを除いて、ビフォアフィルタとほぼ同じです。これにより、最終出力を変更したり、単に最終出力で何かを実行したりできます。これは、特定のセキュリティヘッダーが正しく設定されていることを確認したり、最終出力をキャッシュしたり、最終出力を悪口フィルタでフィルタリングしたりするために使用できます。

フィルタの設定

フィルタがいつ実行されるかを設定する方法は 2 つあります。1 つは app/Config/Filters.php で行い、もう 1 つは app/Config/Routes.php で行います。

特定のルートにフィルタを指定する場合は、 app/Config/Routes.php を使用し、URI ルーティングを参照してください。

ルート(app/Config/Routes.php 内)に指定されたフィルタは、app/Config/Filters.php に指定されたフィルタよりも前に実行されます。

注意

フィルタを適用する最も安全な方法は、自動ルーティングを無効にしルートにフィルタを設定することです。

app/Config/Filters.php ファイルには、フィルタの実行タイミングを正確に設定できる 4 つのプロパティが含まれています。

警告

フィルタ設定の URI の最後に常に * を追加することをお勧めします。コントローラメソッドは、考えられる URL とは異なる URL でアクセスできる場合があるためです。たとえば、自動ルーティング(レガシー)が有効になっている場合、Blog::index があると、blogblog/index、および blog/index/1 などでアクセスできます。

$aliases

$aliases 配列は、実行するフィルタである 1 つ以上の完全修飾クラス名と単純な名前を関連付けるために使用されます。

<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;

class Filters extends BaseConfig
{
    public array $aliases = [
        'csrf' => \CodeIgniter\Filters\CSRF::class,
    ];

    // ...
}

エイリアスは必須であり、後で完全なクラス名を使用しようとすると、システムはエラーをスローします。このように定義すると、使用するクラスを簡単に切り替えることができます。たとえば、別の認証システムに変更する必要があると判断した場合、フィルタのクラスを変更するだけで済むため、非常に便利です。

複数のフィルタを 1 つのエイリアスに結合して、複雑なフィルタセットを簡単に適用できます。

<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;

class Filters extends BaseConfig
{
    public array $aliases = [
        'api-prep' => [
            \App\Filters\Negotiate::class,
            \App\Filters\ApiAuth::class,
        ],
    ];

    // ...
}

必要なだけ多くのエイリアスを定義する必要があります。

$globals

2 番目のセクションでは、フレームワークによって行われたすべての有効なリクエストに適用されるフィルタを定義できます。

ここで使用するフィルタの数に注意する必要があります。リクエストごとに実行されるフィルタが多すぎると、パフォーマンスに影響を与える可能性があるためです。

フィルタは、エイリアスを before または after 配列に追加することで指定できます。

<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;

class Filters extends BaseConfig
{
    // ...

    public array $globals = [
        'before' => [
            'csrf',
        ],
        'after' => [],
    ];

    // ...
}

いくつかの URI を除く

ほとんどすべてのリクエストにフィルタを適用したいが、いくつかのリクエストはそのままにしておく必要がある場合があります。一般的な例の 1 つは、サードパーティ Web サイトからのリクエストが 1 つまたは 2 つの特定の URI にヒットできるように、CSRF 保護フィルタからいくつかの URI を除外し、残りを保護する必要がある場合です。

これを行うには、except キーと、エイリアスとともに値として一致させる URI パス(BaseURL を基準とする)を持つ配列を追加します。

<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;

class Filters extends BaseConfig
{
    // ...

    public array $globals = [
        'before' => [
            'csrf' => ['except' => 'api/*'],
        ],
        'after' => [],
    ];

    // ...
}

フィルタ設定で URI パス(BaseURL を基準とする)を使用できる場所では、正規表現を使用するか、この例のように、アスタリスク(*)をワイルドカードとして使用して、その後のすべての文字に一致させることができます。この例では、api/ で始まる URI パスは CSRF 保護から除外されますが、サイトのフォームはすべて保護されます。

複数の URI パスを指定する必要がある場合は、URI パスパターンの配列を使用できます。

<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;

class Filters extends BaseConfig
{
    // ...

    public array $globals = [
        'before' => [
            'csrf' => ['except' => ['foo/*', 'bar/*']],
        ],
        'after' => [],
    ];

    // ...
}

$methods

警告

$methods フィルターを使用する場合、自動ルーティング(レガシー)を無効にする必要があります。なぜなら、自動ルーティング(レガシー)では、任意のHTTPメソッドでコントローラにアクセスできてしまうからです。予期しないメソッドでコントローラにアクセスすると、フィルターをバイパスする可能性があります。

POST、GET、PUTなどの特定のHTTPメソッドのすべてのリクエストにフィルターを適用できます。この配列では、メソッド名を小文字で指定します。値は実行するフィルターの配列になります。

<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;

class Filters extends BaseConfig
{
    // ...

    public array $methods = [
        'post' => ['invalidchars', 'csrf'],
        'get'  => ['csrf'],
    ];

    // ...
}

注意

$globals$filters プロパティとは異なり、これらはbeforeフィルターとしてのみ実行されます。

標準のHTTPメソッドに加えて、cli という特別なケースもサポートしています。cli メソッドは、コマンドラインから実行されたすべてのリクエストに適用されます。

$filters

このプロパティは、フィルターエイリアスの配列です。各エイリアスに対して、フィルターを適用するURIパス(BaseURLに対する相対パス)パターンのリストを含む before および after 配列を指定できます。

<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;

class Filters extends BaseConfig
{
    // ...

    public array $filters = [
        'foo' => ['before' => ['admin/*'], 'after' => ['users/*']],
        'bar' => ['before' => ['api/*', 'admin/*']],
    ];

    // ...
}

フィルター引数

バージョン4.4.0で新しく追加されました。

$filters を設定する際、フィルターに追加の引数を渡すことができます。

<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;

class Filters extends BaseConfig
{
    // ...

    public $filters = [
        'group:admin,superadmin'  => ['before' => ['admin/*']],
        'permission:users.manage' => ['before' => ['admin/users/*']],
    ];

    // ...
}

この例では、URIが admin/*' に一致する場合、配列 ['admin', 'superadmin']$arguments に渡され、group フィルターの before() メソッドに渡されます。URIが admin/users/*' に一致する場合、配列 ['users.manage']$arguments に渡され、permission フィルターの before() メソッドに渡されます。

フィルターの確認

CodeIgniterには、ルートのフィルターを確認するための次のコマンドがあります。

filter:check

バージョン4.3.0で新しく追加されました。

例として、GETメソッドでルート / のフィルターを確認します。

php spark filter:check get /

出力は次のようになります。

+--------+-------+----------------+---------------+
| Method | Route | Before Filters | After Filters |
+--------+-------+----------------+---------------+
| GET    | /     |                | toolbar       |
+--------+-------+----------------+---------------+

spark routes コマンドでもルートとフィルターを確認できますが、ルートに正規表現を使用している場合は正確なフィルターが表示されない可能性があります。詳細については、URIルーティングを参照してください。

提供されているフィルター

CodeIgniter4にバンドルされているフィルターは、HoneypotCSRFInvalidCharsSecureHeaders、および DebugToolbar です。

注意

フィルターは、設定ファイルで定義された順序で実行されます。ただし、有効になっている場合、DebugToolbar は、他のフィルターで発生するすべてをキャプチャできるように、常に最後に実行されます。

InvalidChars

このフィルターは、ユーザー入力データ($_GET$_POST$_COOKIEphp://input)に次の文字が含まれることを禁止します。

  • 無効なUTF-8文字

  • 改行とタブコードを除く制御文字

SecureHeaders

このフィルターは、アプリケーションのセキュリティを向上させるために使用できるHTTPレスポンスヘッダーを追加します。

ヘッダーをカスタマイズする場合は、CodeIgniter\Filters\SecureHeaders を拡張し、$headers プロパティをオーバーライドします。そして、app/Config/Filters.php$aliases プロパティを変更します。

<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;

class Filters extends BaseConfig
{
    public array $aliases = [
        // ...
        'secureheaders' => \App\Filters\SecureHeaders::class,
    ];

    // ...
}

セキュリティヘッダーについて知りたい場合は、OWASP Secure Headers Project を参照してください。