Making a custom fully working 404 page with codeigniter

CodeIgniter has a really annoying bug with its 404_override setting which makes it pretty much useless as a complete solution. The bug is that it won’t load the correct libraries and helpers of your 404 controller if the controller which threw the 404 also loaded those modules for itself. Fear not, a workaround is at hand. The advantage of properly handling a 404 in the context of your CodeIgniter application is that you get access to your standard stuff like your site layout (views) so you can load all your menus and stuff and load the error message where the content would normally go – this way the visitor feels like they’re on the site and they can get onto a working page easily, if they so desire. You can also hook into your database and perhaps do some logging.

Firstly, if you’re not using MY_Controller then, err, well you really should be. It makes life so much easier. MY_Controller is an easy to define superclass for all of your controllers. Implementing it lets you centralise all your site-wide constants and routines, and it’s very useful here.

Define it in application/core/MY_Controller.php and make all your ‘real’ controllers extend it. Also define individual exception classes that you want to handle. The _remap method wraps the controller’s method invocation, so we override that and use it to catch exceptions. This means that at any point in your controllers, you can just throw an Exception404 and you don’t have to worry about anything else; the exception bubbles up to _remap which unloads any existing output and then loads the 404 view(s).

You could extend this to also define 403 exceptions, and any other error codes your application may deal with, and you could use the exception message (i.e. throw new Exception404(‘some message’);) to set some descriptive text for your 404 view. [update: actually I tried this and it’s a bit cumbersome, you’re probably best off having just a HTTPException class and set the status code as a constructor argument)]

This is sort of how mine looks:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// defined for neater syntax only
class Exception404 extends Exception {
}
public class MY_Controller extends CI_Controller {
  public function _remap($method, $params = array()) {
    try {
      if (!method_exists($this, $method))
        throw new Exception404();
      return call_user_func_array(array($this, $method), $params);
    } catch(Exception404 $e) {
      $this->show_404();
    }
  }
  protected function _load_header($data=array()) {
    $this->load->view('headerview.php', $data);
  }
  protected function _load_footer() {
    $this->load->view('footerview.php');
  }
  protected function show_404() {
    // clear any views that have already been loaded
    $this->output->set_output('');
    $this->output->set_status_header('404');
    $this->_load_header();
    $this->load->view('404.php');
    $this->_load_footer();
  }
}

CodeIgniter URLs work like this:

index.php/CONTROLLER/METHOD/ARG1/ARG2/ARG3/…/ARGN

So we can see here that when we request a method of a controller, the remap function catches it. If the URL is okay and the method exists, it is executed. If it doesn’t, the 404 is executed.

To make it so it also catches non-existent controllers, change application/config/routes.php:

1
$route['404_override'] = 'CONTROLLER/show_404';

CONTROLLER can be any controller which inherits MY_Controller. I use my default, you can use whatever most appeals or, if you want, define a new controller.

You may (probably) have your application and server set up so it’s possible to request URLs which aren’t handled by CodeIgniter’s index.php. In this case, you probably also want to redirect when Apache catches a 404 to your new custom 404. Put this in your htaccess:

1
ErrorDocument 404 /index.php/CONTROLLER/show_404

Where again, CONTROLLER is some controller that implements show404.

you should now have site-wide redirection of file-not-found URLs to your exciting and sexy new 404 page. I thoroughly recommend using the opportunity to display to your baffled visitor a picture of a lolcat. I recommend this one:

(Visited 13 times, 1 visits today)

Comments

comments

Leave a Reply