CakePHPのミドルウェアとは
CakePHPのミドルウェアは、HTTPリクエストとレスポンスの処理を順番につないでいく仕組みです。PSR-15(HTTP Server Request Handlers)に準拠しており、リクエストが最終的なコントローラに到達するまでの間に、認証チェック・ロギング・レスポンス加工などを挿入できます。
この仕組みは「パイプライン」と呼ばれ、リクエストが複数のミドルウェアを順番に通過して処理されるイメージです。
Request → [MiddlewareA] → [MiddlewareB] → [MiddlewareC] → Controller
↓
Response ← [MiddlewareA] ← [MiddlewareB] ← [MiddlewareC] ← Response
ミドルウェアはリクエストの「前処理」と「後処理」の両方を担えるのが特徴です。
標準ミドルウェアを確認する
CakePHPには最初からいくつかのミドルウェアが用意されています。設定ファイルは src/Application.php の middleware() メソッドです。
// 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ライブラリとの組み合わせも容易です。まずは小さなロギングミドルウェアから作り始めて、パイプラインの流れを体感してみてください。