[eluser]Pascal Kriete[/eluser]
New Version <a href="http://ellislab.com/forums/viewthread/76340/#381933">here</a>
I've been looking for a better way to route errors to my own error controller (while keeping the proper url). Up until now I've always included my error controller along with the request controller. Then I check if the requested controller has the function I want, and if it doesn't, I instantiate the error class and call the 404.
Needless to say that this is an awful solution.
So here's my attempt at something more flexible. It replaces the normal show_error function of the Exceptions class. If an error is encountered it opens a connection to the same server, but changes the url to call an error function. So you have can have your errors in a controller with full library access, etc.
Code:
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
* CI_Exceptions extension to route errors to controller
*
* @package CodeIgniter
* @subpackage Libraries
* @category Exceptions
* @author Pascal Kriete
*/
class MY_Exceptions extends CI_Exceptions {
var $CI;
/**
* Controller
*
* @access public
*/
function MY_Exceptions()
{
parent::CI_Exceptions();
}
// --------------------------------------------------------------------
/**
* General Error Page
*
* @access private
* @param string disabled - there to keep ci happy
* @param string ditto for this one
* @param string the error function name
* @return string
*/
function show_error($heading, $message, $template = 'error_general')
{
// Prevent infinite loops
if($_SERVER['HTTP_USER_AGENT'] === 'CI_Error')
die('Invalid error handler.');
// Figure out url to error function
$handler = 'error/' . $template;
$ci_conf =& load_class('Config');
$ci_uri = $ci_conf->site_url($handler);
//Drop http:// if it exists
$ci_uri = str_replace('http://', '', $ci_uri);
//Seperate host from path
$ci_uri = explode('/', $ci_uri, 2);
// Let the stream do it's magic
$error_output = $this->_stream_error($ci_uri[0], '/'.$ci_uri[1]);
return $error_output;
}
// --------------------------------------------------------------------
/**
* Sneaky backdoor stream
*
* @access private
* @param string host name (no http://)
* @param string path to request
* @return string
*/
function _stream_error($host, $path = '/')
{
// Open socket connection
$err = fsockopen($host, 80);
// Toss info to the other side
fputs($err, "GET $path HTTP/1.1\r\n");
fputs($err, "Host: $host\r\n");
fputs($err, "User-Agent: CI_Error\r\n");
fputs($err, "Connection: Close\r\n\r\n");
// Listen for response
$resp = '';
while (!feof($err))
$resp .= fgets($err, 128);
fclose($err);
// Remove http header
$resp = split("\r\n\r\n",$resp);
return $resp[1];
}
}
?>
The possible functions this calls are identical to the templates in the error folder. So a error controller could be:
Code:
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
class Error extends Controller {
/**
* Constructor
*
* @access public
*/
function Error()
{
parent::Controller();
}
// --------------------------------------------------------------------
/**
* Show 404 Error
*
* @access public
*/
function error_404()
{
header("HTTP/1.1 404 Not Found");
echo 'Ooops... the url you requested doesn\'t exist.<br/>';
}
/**
* Others that are defined by default
*
* function error_db() { }
* function error_general() { }
* function error_php() { }
*/
}
?>
I plan on using this for an open source project, so if anyone knows of any drawbacks to this please let me know.