In codeigniter, as you know, a page of the form: /class/function/ID
, where class is the controller name, function is the method within the controller, and ID is
I had the same problem with you and I found a complete solution for this in CodeIgniter 3. Here I would like to share step by step how to solve it. Of course, we need to support a custom 404 page to satisfy SEO requirement.
class ErrorController extends CI_Controller
{
public function __construct()
{
parent::__construct();
}
public function index()
{
$this->output->set_status_header('404');
return $this->load->view('errors/error_404');
}
}
<div>
<p>We are so sorry. The page you requested could not be found.</p>
</div>
$route['404_override'] = 'ErrorController';
$config['subclass_prefix'] = 'MY_';
class MY_Exceptions extends CI_Exceptions {
public function __construct() {
parent::__construct();
}
function show_404($page = '', $log_error = TRUE) {
$CI = &get_instance();
$CI->output->set_status_header('404');
$CI->load->view('errors/error_404');
echo $CI->output->get_output();
exit;
}
}
abstract class MY_Model extends CI_Model
{
protected $table = 'table_name';
public function __construct()
{
parent::__construct();
$this->load->database();
}
public function find($id)
{
$result = $this->db->get_where($this->table, ['id' => $id]);
$data = $result->row_object();
if (!$data) {
show_404();
}
return $data;
}
}
show_404()
actually sends the proper headers for a search engine to register it as a 404 page (it sends 404 status).
Use a Firefox addon to check the headers received when calling show_404()
. You will see it sends the proper HTTP Status Code.
Check the default application/errors/error_404.php
. The first line is:
<?php header("HTTP/1.1 404 Not Found"); ?>
That line sets the HTTP Status as 404. It's all you need for the search engine to read your page as a 404 page.
Only follows these steps:
Step 1 Update your application/config/routes.php file
$route['404_override'] = 'error/error_404';
Step 2 Create your own controller in controllers folder ex. error.php
<?php
class Error extends CI_Controller
{
function error_404()
{
$data["heading"] = "404 Page Not Found";
$data["message"] = "The page you requested was not found ";
$this->load->view('error',$data);
}
}
?>
Step 3 Create your view in views folder ex. error.php
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252" />
<title><?php echo $heading;?></title>
</head>
<body>
<?php echo $message;?>
</body>
</html>
Yes show_404() WILL send out a 404 but it looks like hell. There have been a few hacks suggested here, but why hack when you can use built in features?
Upgrade to CI 2.0 and you'll be able to use the amazing:
$route['404_override'] = 'errors/error_404';
Then you can have a general errors controller without having to worry about trying to load views, libraries and helpers WY too early in the CI instance to function properly.
$this->output->set_status_header('404');
to generate 404 headers.
Create controller in your application/controllers folder.
class Error extends Controller
{
function error_404()
{
$this->load->view('error');
}
}
Then in your application/library extend the Router class by creating application/libraries/MY_Router.php
class MY_Router extends CI_Router
{
private $error_controller = 'error';
private $error_method_404 = 'error_404';
function MY_Router()
{
parent::CI_Router();
}
// this is just the same method as in Router.php, with show_404() replaced by $this->error_404();
function _validate_request($segments)
{
// Does the requested controller exist in the root folder?
if(file_exists(APPPATH.'controllers/'.$segments[0].EXT))
{
return $segments;
}
// Is the controller in a sub-folder?
if(is_dir(APPPATH.'controllers/'.$segments[0]))
{
// Set the directory and remove it from the segment array
$this->set_directory($segments[0]);
$segments = array_slice($segments, 1);
if(count($segments) > 0)
{
// Does the requested controller exist in the sub-folder?
if(!file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].EXT))
{
return $this->error_404();
}
}
else
{
$this->set_class($this->default_controller);
$this->set_method('index');
// Does the default controller exist in the sub-folder?
if(!file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.EXT))
{
$this->directory = '';
return array();
}
}
return $segments;
}
// Can't find the requested controller...
return $this->error_404();
}
function error_404()
{
$segments = array();
$segments[] = $this->error_controller;
$segments[] = $this->error_method_404;
return $segments;
}
function fetch_class()
{
// if method doesn't exist in class, change
// class to error and method to error_404
$this->check_method();
return $this->class;
}
function check_method()
{
$class = $this->class;
if (class_exists($class))
{
if ($class == 'doc')
{
return;
}
if (! in_array('_remap', array_map('strtolower', get_class_methods($class)))
&& ! in_array(strtolower($this->method), array_map('strtolower', get_class_methods($class))))
{
$this->class = $this->error_controller;
$this->method = $this->error_method_404;
include(APPPATH.'controllers/'.$this->fetch_directory().$this->error_controller.EXT);
}
}
}
}
If the page does not exist, it will be routed to error controller