Top > Blog > Programming

CodeIgniterでカスタムの404エラーページを作成する

CodeIgniterではエラーページのテンプレートが application/errors/error_404.php (1.7.x系だと system/application/errors/error_404.php)にありますが、これをカスタマイズしただけだとセッションなどが使えません。コントローラーを用意して前処理を行なう事もできません。

CodeIgniter 1.7系の場合は、Custom 404 error pages with CodeIgniterに詳しい記述がありました。ここではこれをバージョン2.0.x系に適用する場合の方法をメモしておきます。CodeIgniter 2.0 では後述する404エラー用のルーティング設定があります。

コントローラーの作成

まずエラー画面を表示するコントローラーを作成します。

application/controllers/error.php

class Error extends CI_Controller {

    /**
     * コンストラクタ
     */
    function __construct(){
        parent::__construct();
    }

    /**
     * エラー画面の表示を行います。
     */
    function error_404() {
        // 404を返さないと検索エンジンに404画面が登録されてしまう。
        $this->output->set_status_header('404');
        
        // ここでViewの構築など、独自の処理
    }
}

ルーティング処理のオーバーライド

ネイティブライブラリでルーティング処理を行なっているRouter.phpを継承して、該当する部分をオーバーライドし、独自の処理を付け加えます。
ここは前述の参考ページと変わりはありませんが、CodeIgniterのバージョンが違えば、オーバーライドしている _validate_request() メソッドの中身が変わるので CodeIgniter 2.0.1, 2.0.2 に対応したMy_Router.phpファイルを置いておきます。このファイルは application/core/My_Router.php に配置します。

config/route.php に $route[‘404_override’] という箇所があるので、そこに

$route['404_override'] = 'error/error_404';

と記述します。(コメント欄でご指摘頂き、動作確認もしました。route.phpのソースコードコメントにも書いてあるので、こちらが正しいやり方ですね。 2011/05/09 追記)

以上で、前述のコントローラーに処理を書けば、任意の画面を作成できるようになります。

注意点

コントローラー内で 404 エラーを返すように設定しないと、エラー画面が検索エンジンにキャッシュされてしまいます。

また404エラーを表示するコントローラー名やメソッド名を変更する場合は、My_Router クラスのフィールド $error_controller, $error_method_404 をそれぞれ対応するものに書き換えてください。

CodeIgniterのバージョンが上がって CI_Routerクラスの中身が変わっている場合は、_validate_request()メソッドをMy_Routerクラスにコピーして最後の行を

return $this->error_404();

と書き換える必要があります。

全14コメント

  1. Kenji より:

    2.0 の場合は、config/route.php の

    $route[‘404_override’]

    を使った方がよいように思います。

    • 管理人 より:

      ご指摘ありがとうございました。
      記事を修正しました。

  2. shokun0803 より:

    はじめまして。
    上記方法でオリジナル404を表示することができました、ありがとうございます。

    ところで、上記記述でクラスを呼び出すことができないのですが、どのように処理されていますか?
    __construct()で$this->load->library(‘parser’);などとしても使えないのです。
    良い方法があったら教えてくださいm(__)m

    • 管理人 より:

      「クラスを呼び出す」の意味が把握できないのですが…、ユーザーライブラリの呼び出しならば、

      http://codeigniter.jp/user_guide_ja/general/creating_libraries.html

      で、それ以外だと…、
      たとえばCI_Controllerを継承したクラスが呼べないという意味でしたら、

      http://codeigniter.jp/user_guide_ja/general/core_classes.html

      ですね。1.7.x だとコントローラーの継承はユーザーライブラリと同じやり方でしたが、2.x だと application/core/ に置かないといけなくなっているようです。

    • shokun0803 より:

      ご返事ありがとうございます。
      単純にオリジナル404のviewでテンプレートパーサーを使おうと思ったらエラーになっちゃったっていう話なんですけど…(汗)

      viewは$this->load->viewにすればテンプレートパーサーを使わないのでなんとかなるとして、viewの中でユーザーエージェントを利用している部分があるのですが、$this->load->library(‘user_agent’);でユーザーエージェントクラスを呼び出しても、$this->browser = $this->agent->browser();でエラーになっちゃうので…

      ユーザーライブラリでなく既存のライブラリが利用できないのには何か理由があるのかな?ということで、現在調査中です。
      お手間おかけしてすみません。

    • 管理人 より:

      ひとまず私の環境で、

      ----------
      class Error extends CI_Controller {
      
          function __construct(){
              parent::__construct();
              $this->load->library('user_agent');
              $this->browser = $this->agent->browser();
          }
      
          function error_404() {
              $this->output->set_status_header('404');
              $data = array();
      
              $data[MAIN_CONTENTS] = $this->load->view('contents/error_404', $data, TRUE);
              $this->load->view('layout', $data);
          }
      }
      ----------
      

      というコントローラーを作成してみましたが、特にエラーは起きませんでした。ご参考になりますでしょうか…?

  3. shokun0803 より:

    mizoguchi さんありがとうございます。
    コメント欄をQAみたいにしてしまってすみません…

    function __construct()に関してはほぼ同じ書き方なので、当方の環境では6行目($this->agent->browser())でエラーになりますね、一応コピペで試させていただきました。
    route.phpの$route[‘404_override’]に何らかの問題があるんじゃないかと疑っていますが、当方とは違う環境で動いているということは他の原因なのかもしれません。

    同僚が英語のフォーラムで404_override関連の投稿を見つけたらしいのですが、午後にでも検証してもらおうと思っています。
    当方は午後よりCMSビズに行ってしまうので、検証の結果がわかったら明日にでもご報告をさせていただきます。

    管理人様本当にすみません…

    • 管理人 より:

      了解しました!うまく原因が分かると私もありがたいです。

      いま手元の環境を確認しましたが、私は CodeIgniter 2.0.2 を使っています。という事は 2.0.1 ではこれを試していないので…もしそれが原因でしたら、申し訳ありません。

      よろしくお願いいたします。

    • shokun0803 より:

      昨日からいろいろとすみません。

      判ったことがひとつあります。
      /example.com/404 でのアクセスは正常で、/example.cpm/form/404 など、他のコントローラーで作られたページがからむ404だとエラーになります。
      で、error.phpから$this->load->library(‘user_agent’);をコメントアウトしても変わりませんが、form.php側をコメントアウトすると正常に動作します。

      2.0.2ですが、日本語版がまだないのと、2.0.3を待ったほうが良いとのことのようで、まだ試せていません…すみません。

    • 管理人 より:

      あ、なるほど、何となく分かったような分からないような…
      _remap() メソッドあたりは使えないでしょうか?

    • shokun0803 より:

      現状、2.0.1で行うにはコア部分の修正か、それを上書くクラスを作るかしかないような気配です。2.0.2は本当に日本語版でないんですかねー

      他にもっと最適な方法があるのかは今のところ分かりません…

    • 管理人 より:

      分かりました。コントローラーがあって、そこに定義されていないメソッドが呼ばれた時に、カスタムの404ページが呼ばれないという事ですね。

      私は、CI_Controller を継承した基底コントローラーを application/core に定義し、各コントローラーではその基底コントローラーを継承するようにしています。
      各コントローラーで使う共通メソッドは、その基底コントローラーに定義しています。

      そうする事でエラー処理を共通化させたりしているのですが、前述の error_404() メソッドも実はErrorコントローラークラスではなく、その基底コントローラーに実装しています。
      Error コントローラークラスはそれを継承した空のクラスでして…

      で、「定義されていないメソッドが呼ばれた時に404エラーページを表示する」にはどうするかですが、

      http://codeigniter.jp/user_guide_ja/general/controllers.html#remapping

      にあるとおり、基底コントローラーで _remap() メソッドを定義しておけば、解決出来るのではないかと。
      上記のドキュメントでは call_user_func_array() 関数を呼んだ後で、メソッドが無ければ show_404() 関数を呼んでいますが、こちらの場合はそこを $this->error_404(); としました。

      問題が「定義されていないメソッドが呼ばれた時に404エラーページを表示する」という事であれば、これで解決出来ると思います。

    • shokun0803 より:

      管理人様。

      結論から言えば、無事に動作いたしました。バージョンアップは行っていません。
      様々なヒントなどありがとうございました。
      MY_Controller.phpを作成することで解決しましたが、他の共通メソッドなどが書けるので便利ですね!

      オリジナル404の作成がきっかけで違う勉強までさせていただきました。
      お手間を取らせてしまいまして申し訳ありませんでした、大変助かりました。ありがとうございますm(__)m

    • 管理人 より:

      良かったです!
      結構とんちんかんなお答えもしていましたので、申し訳ありませんでした。

      CodeIgniter はシンプルで自由度が高いフレームワークなので、私はとても気に入っています。
      あえて言うなら、SpringFrameworkやmybatisのようなPDFか1枚の HTML で上から順に読んでいけるようなドキュメントがあると精読出来て良いんだけどな~とは思いますが、それくらいしか不満がありません。
      足りない機能があれば作れば良いですし。。

      私の方からお世話になる事もあるかもしれません。その節はまたよろしくお願いいたします。

shokun0803 へのコメント