あっぽログ
← 記事一覧に戻る

CakePHPのミドルウェア入門:リクエスト処理のパイプラインを理解して使いこなす

CakePHPのミドルウェアとは

CakePHPのミドルウェアは、HTTPリクエストとレスポンスの処理を順番につないでいく仕組みです。PSR-15(HTTP Server Request Handlers)に準拠しており、リクエストが最終的なコントローラに到達するまでの間に、認証チェック・ロギング・レスポンス加工などを挿入できます。

この仕組みは「パイプライン」と呼ばれ、リクエストが複数のミドルウェアを順番に通過して処理されるイメージです。

Request → [MiddlewareA] → [MiddlewareB] → [MiddlewareC] → Controller
                                                               ↓
Response ← [MiddlewareA] ← [MiddlewareB] ← [MiddlewareC] ← Response

ミドルウェアはリクエストの「前処理」と「後処理」の両方を担えるのが特徴です。


標準ミドルウェアを確認する

CakePHPには最初からいくつかのミドルウェアが用意されています。設定ファイルは src/Application.phpmiddleware() メソッドです。

// src/Application.php
use Cake\Http\MiddlewareQueue;
use Cake\Http\Middleware\CsrfProtectionMiddleware;
use Cake\Http\Middleware\EncryptedCookieMiddleware;
use Cake\Http\Middleware\SecurityHeadersMiddleware;

public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
    $middlewareQueue
        // セキュリティヘッダーを自動付与
        ->add(new SecurityHeadersMiddleware())
        // CSRF対策
        ->add(new CsrfProtectionMiddleware([
            'httponly' => true,
        ]));

    return $middlewareQueue;
}

MiddlewareQueue にミドルウェアを add() で追加するだけで有効になります。順番が重要で、上から順にリクエストが処理されます。


カスタムミドルウェアを作成する

独自のミドルウェアを作成するには、PSR-15の MiddlewareInterface を実装します。CakePHPのコード生成コマンドを使うと簡単に雛形を作れます。

bin/cake bake middleware AccessLog

生成されたファイルを編集してみましょう。以下はリクエストのURLとレスポンスのステータスコードをログに記録するシンプルなミドルウェアです。

<?php
// src/Middleware/AccessLogMiddleware.php
declare(strict_types=1);

namespace App\Middleware;

use Cake\Log\Log;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class AccessLogMiddleware implements MiddlewareInterface
{
    public function process(
        ServerRequestInterface $request,
        RequestHandlerInterface $handler
    ): ResponseInterface {
        // --- リクエスト前処理 ---
        $startTime = microtime(true);
        $path = $request->getUri()->getPath();
        $method = $request->getMethod();

        // 次のミドルウェア(またはコントローラ)へ処理を渡す
        $response = $handler->handle($request);

        // --- レスポンス後処理 ---
        $elapsed = round((microtime(true) - $startTime) * 1000, 2);
        $status = $response->getStatusCode();

        Log::info("[AccessLog] {$method} {$path} → {$status} ({$elapsed}ms)");

        return $response;
    }
}

ポイント解説

  • process() メソッドの中で $handler->handle($request) を呼ぶことで次の処理へバトンを渡します
  • $handler->handle()に書いた処理がリクエスト前処理、に書いた処理がレスポンス後処理になります。
  • $handler->handle() を呼ばずに直接レスポンスを返すと、後続のミドルウェアやコントローラをスキップできます(認証失敗時のリダイレクトなどに活用)。

ミドルウェアを登録する

作成したミドルウェアを Application.php に追加します。

use App\Middleware\AccessLogMiddleware;

public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
    $middlewareQueue
        ->add(new SecurityHeadersMiddleware())
        ->add(new AccessLogMiddleware())   // 追加
        ->add(new CsrfProtectionMiddleware());

    return $middlewareQueue;
}

認証チェックミドルウェアの例

特定のパスへのアクセスを制限するミドルウェアの例も見てみましょう。

<?php
// src/Middleware/AuthCheckMiddleware.php
namespace App\Middleware;

use Cake\Http\Response;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class AuthCheckMiddleware implements MiddlewareInterface
{
    public function process(
        ServerRequestInterface $request,
        RequestHandlerInterface $handler
    ): ResponseInterface {
        $path = $request->getUri()->getPath();

        // /admin 以下は認証必須
        if (str_starts_with($path, '/admin')) {
            $session = $request->getAttribute('session');

            if (!$session?->read('Auth.User')) {
                // 未ログインならログインページへリダイレクト
                $response = new Response();
                return $response->withStatus(302)
                    ->withHeader('Location', '/users/login');
            }
        }

        // 認証済み or 対象外パスはそのまま通す
        return $handler->handle($request);
    }
}

$handler->handle() を呼ばずに 302 レスポンスを返すことで、コントローラへの処理を止めてリダイレクトしています。


ミドルウェアの順番に注意する

ミドルウェアの登録順はとても重要です。例えば、ロギングは最初に配置してすべてのリクエストを記録し、認証チェックはCSRFより前に配置するなど、用途に応じた順番を意識しましょう。

$middlewareQueue
    ->add(new AccessLogMiddleware())      // 1. まず全リクエストをログ
    ->add(new SecurityHeadersMiddleware())// 2. セキュリティヘッダー付与
    ->add(new AuthCheckMiddleware())      // 3. 認証チェック
    ->add(new CsrfProtectionMiddleware());// 4. CSRFチェック

まとめ

CakePHPのミドルウェアを活用すると、コントローラを汚さずに横断的な処理を整理できます。

用途ミドルウェアの活用例
認証・認可未ログイン時のリダイレクト
ロギングアクセスログ・処理時間の記録
セキュリティCSRF対策・ヘッダー付与
レスポンス加工圧縮・キャッシュヘッダーの付与

PSR-15に準拠しているため、他のPSRライブラリとの組み合わせも容易です。まずは小さなロギングミドルウェアから作り始めて、パイプラインの流れを体感してみてください。

← 記事一覧に戻る