【改訂版】CodeIgniter4のルーティング
この記事は CodeIgniter Advent Calendar 2022 - Qiita の5日目です。まだ、空きがありますので、興味のある方は気軽に参加してください。
CodeIgniter4のルーティングについて解説します。
手動ルーティング
CodeIgniter 4.2.0 から、セキュリティ上の理由で、すべてのルートを設定ファイルに定義する「手動ルーティング」がデフォルトになりました。 詳細は、「【改訂版】本当は危ないCodeIgniter4の自動ルーティング」を参照してください。
コントローラがあるだけではルーティングされないため、ルートを定義しない限りコントローラにアクセスできません。定義されていないURLにアクセスしても 404 ページが表示されます。
HTTPメソッドでのルーティング
ルートは、app/Config/Routes.php に設定します。
特定のHTTPメソッドを指定してルートを設定することができます。
GETメソッドの場合は、$routes->get() を使用します。
$routes->get('news', [\App\Controllers\News::class, 'index']);
上記は、http://example.com/news にアクセスすると、News コントローラの index() メソッドが呼び出されます。
POSTメソッドの場合は、$routes->post() を使用します。
$routes->post('news/create', [\App\Controllers\News::class, 'create']);
上記は、http://example.com/news/create にアクセスすると、News コントローラの create() メソッドが呼び出されます。
$routes->put()、$routes->delete() なども同様です。
URLの一部をキャプチャ
(:segment)、(:num)、(:any) などのプレースホルダーを使います。
(:segment) は1つのURIセグメント、(:num) は数字だけの1つのセグメント、(:any) は任意の文字列にマッチします。
$routes->get('news/(:segment)', [\App\Controllers\News::class, 'view']);
上記は、/news/foo にアクセスすると、News コントローラの view() メソッドの第1引数に foo を渡し、呼び出します。
ルートのグループ化
ルートをグループ化することもできます。
$routes->group('admin', function ($routes) {
$routes->get('users', [\App\Controllers\Admin\Users::class, 'index']);
$routes->get('blog', [\App\Controllers\Admin\Blog::class, 'index']);
});
上記は、admin/users と admin/blog のルートを設定しています。
コントローラフィルターの適用
ルートに対してコントローラフィルターを指定することもできます。
以下は、login というフィルターをルートに適用するサンプルです。
$routes->post('news/create', [\App\Controllers\News::class, 'create'], ['filter' => 'login']);
$routes->group('admin', ['filter' => 'login'], function ($routes) {
$routes->get('users', [\App\Controllers\Admin\Users::class, 'index']);
$routes->get('blog', [\App\Controllers\Admin\Blog::class, 'index']);
});
名前付きルート
オプションでルートに名前を付けることができます。
$routes->get(
'users/(:num)/gallery/(:num)',
[\App\Controllers\Galleries::class, 'showUserGallery'],
['as' => 'user-gallery']
);
ビューで以下のように使えます。
<a href="<?= url_to('user-gallery', 15, 12) ?>">ギャラリーを表示する</a>
<!-- 結果: 'http://example.com//users/15/gallery/12' -->
名前付きルートを使うと、ビューを変更せずに簡単にルートを変更することができます。
ルート設定の確認
spark routes コマンドで設定したルートを確認することができます。
$ php spark routes
CodeIgniter v4.2.10 Command Line Tool - Server Time: 2022-12-05 20:17:56 UTC-06:00
+--------+--------+------------------------------------------+----------------+---------------+
| Method | Route | Handler | Before Filters | After Filters |
+--------+--------+------------------------------------------+----------------+---------------+
| GET | / | \App\Controllers\Home::index | | toolbar |
| CLI | ci(.*) | \CodeIgniter\CLI\CommandRunner::index/$1 | | |
+--------+--------+------------------------------------------+----------------+---------------+
デフォルトでは上記のルートが設定されています。ルートは上から順に評価され、マッチすればそのメソッドが実行されます。
なお、CLI はコマンドライン用の特殊なルートです。
自動ルーティング(改善)
CodeIgniter 4.1.x までデフォルトだった自動ルーティングは、あまりにも簡単に脆弱性を作り込んでしまうため、 4.2.0 からより安全な「自動ルーティング(改善)」が追加されました。
自動ルーティング(改善)を有効にする
自動ルーティング(改善)を有効にするには、app/Config/Routes.php と app/Config/Feature.php の 2箇所で設定する必要があります。
app/Config/Routes.php
$routes->setAutoRoute(true);
app/Config/Feature.php
public bool $autoRoutesImproved = true;
$autoRoutesImproved が false だと、自動ルーティング(レガシー)になります。
自動ルーティング(改善)の基本
自動ルーティング(改善)は、基本的に以下の規約で自動的にルーティングします。
http://example.com/{コントローラ名}/{メソッド名(HTTP動詞を除く)}/{引数1}/{引数2}/...
以下の Newsコントローラを作成します。
<?php
namespace App\Controllers;
class News extends BaseController
{
public function getTest($p1 = 'x', $p2 = 'x')
{
return '$p1: ' . esc($p1) . ', $p2: ' . esc($p2);
}
}
すると、以下のルートが自動的に定義されます。
+-----------+---------------------+------------------------------------------+----------------+---------------+
| Method | Route | Handler | Before Filters | After Filters |
+-----------+---------------------+------------------------------------------+----------------+---------------+
| GET(auto) | news/test[/..][/..] | \App\Controllers\News::getTest | | toolbar |
+-----------+---------------------+------------------------------------------+----------------+---------------+
getTest()メソッドの最初の get はHTTPメソッド(HTTP動詞)です。この場合はGETメソッドでこのルートにアクセスできることになります。
例えば、POSTメソッドでアクセスさせたい場合は、postTest()メソッドを定義する必要があります。
php spark serve コマンドを実行し、
http://localhost:8080/news/test/a/b にブラウザからアクセスすると、以下が表示されます。
$p1: a, $p2: b
http://localhost:8080/news/test/a にアクセスすると、以下が表示されます。
$p1: a, $p2: x
http://localhost:8080/news/test にアクセスすると、以下が表示されます。
$p1: x, $p2: x
http://localhost:8080/news/test/a/b/c にアクセスすると、404 - File Not Found が表示されます。
引数の数が合わないからです。
デフォルトメソッド
http://localhost:8080/news でアクセス可能にするには、以下のように getIndex() メソッドを追加します。
<?php
namespace App\Controllers;
class News extends BaseController
{
// ...
public function getIndex()
{
return __METHOD__;
}
}
これで http://localhost:8080/news にアクセスすると、以下が表示されます。
App\Controllers\News::getIndex
このようにURLの {メソッド名(HTTP動詞を除く)} の部分を省略したときに実行されるメソッドを「デフォルトメソッド」と言います。
デフォルトでは index が設定されています。
デフォルトコントローラ
http://localhost:8080/ のように {コントローラ名} がないURLにアクセス可能にするには、以下のように Homeコントローラを作成します。
<?php
namespace App\Controllers;
class Home extends BaseController
{
public function getIndex()
{
return view('welcome_message');
}
}
しかし、デフォルトでは app/Config/Routes.php に / へのルート(以下)が定義されています。
$routes->get('/', 'Home::index');
定義済みのルートは自動ルーティングより優先されるので、Home::index()メソッドが存在しないため、404 - File Not Found になります。
そこで、上記のルートの定義をコメントアウトしてください。
//$routes->get('/', 'Home::index');
これで、http://localhost:8080/ に自動ルーティング(改善)によりアクセス可能になります。
自動ルーティング(改善)の規約
規約をまとめておきます。
- URLは基本的にはすべて小文字を想定
- URLでの
{コントローラ名}はすべて小文字、実際のクラス名は先頭のみ大文字- サブフォルダを使う場合は、サブフォルダ名も先頭のみ大文字
- メソッド名には
getIndex()、postCreate()のようにHTTP動詞のプリフィックスが必要http://example.com/news/createにGETメソッドでリクエストした場合、NewsコントローラのgetCreate()メソッドが実行される
- メソッド名が省略されたURLの場合、デフォルトメソッド(デフォルトでは
index)があれば実行されるhttp://example.com/newsにGETメソッドでリクエストした場合、NewsコントローラのgetIndex()メソッドが実行される
- トップページへのリクエストの場合、デフォルトコントローラ(デフォルトでは
Home)が実行されるhttp://example.com/にGETメソッドでリクエストした場合、HomeコントローラのgetIndex()メソッドが実行される
- デフォルトコントローラとデフォルトメソッドはURLの中で必ず省略する必要がある
http://example.com/にはアクセス可能だがhttp://example.com/homeには 404 が返るhttp://example.com/newsにはアクセス可能だがhttp://example.com/news/indexには 404 が返る
- メソッドのパラメータ数がチェックされる
- パラメータ数が一致しない場合は 404 が返る
- 手動ルーティングで定義されているコントローラには一切アクセスできない
- 手動ルーティングするコントローラと自動ルーティングするコントローラは厳密に区別される
News::index()へのルートが手動ルーティングで設定されている場合、News::getCreate()メソッドを追加してnews/createにアクセスしても 404 が返る
_remap()メソッドはサポートされない
自動ルーティング(レガシー)
CodeIgniter 4.1.x までは、デフォルトで以下の規約で自動的にルーティングされていました。 これは CodeIgniter3 の自動ルーティングと同じものです。
http://example.com/{コントローラ名}/{メソッド名}/{引数1}/{引数2}/...
この機能は現在では「自動ルーティング(レガシー)」と呼ばれています。
セキュリティ上の問題があるため、デフォルトでは無効になっています。
自動ルーティング(レガシー)を有効にする
自動ルーティング(レガシー)を有効にするには、
app/Config/Routes.php で以下を設定します。
app/Config/Routes.php
$routes->setAutoRoute(true);
セキュリティ上の理由から、自動ルーティング(レガシー)は推奨しません。できる限りオフに設定してください。
自動ルーティング(レガシー)を有効にすると、デフォルトでは以下のルートがあることがわかります。
+--------+------------------+------------------------------------------+----------------+---------------+
| Method | Route | Handler | Before Filters | After Filters |
+--------+------------------+------------------------------------------+----------------+---------------+
| GET | / | \App\Controllers\Home::index | | toolbar |
| CLI | ci(.*) | \CodeIgniter\CLI\CommandRunner::index/$1 | | |
| auto | / | \App\Controllers\Home::index | | toolbar |
| auto | home | \App\Controllers\Home::index | | toolbar |
| auto | home/index[/...] | \App\Controllers\Home::index | | toolbar |
+--------+------------------+------------------------------------------+----------------+---------------+
/ へのルートは Method が GET のルート(1行目)と auto のルート(3行目)の 2つあります。リクエストが GET / の場合、GET のルートが上にあるため、auto のルートは実際には使われません。しかし、リクエストが POST / の場合は auto のルートがマッチします。
Method が auto のルートは自動ルーティング(レガシー)であることを示し、 あらゆるHTTPメソッドでアクセス可能です。
この記事は CodeIgniter Advent Calendar 2022 - Qiita の5日目です。まだ、空きがありますので、興味のある方は気軽に参加してください。
関連
参考
Date: 2022/12/05



![徹底攻略PHP5技術者認定[上級]試験問題集 [PJ0-200]対応 徹底攻略PHP5技術者認定[上級]試験問題集 [PJ0-200]対応](http://tatsu-zine.com/images/books/164/cover_s.jpg)

