[eluser]Aquillyne[/eluser]
Hi, I'm new to CI. I'm very impressed so far but have a question - could anyone help out?
I want error messages from my site to appear as messages in one of my normal views, rather than as hard-coded messages from the /errors folder. Is there a way to load a view within/instead of an error message?
Thanks.
[eluser]Clooner[/eluser]
You could do a redirect in the error pages to a special "error" controller!
[eluser]Aquillyne[/eluser]
[quote author="clooner" date="1212937664"]You could do a redirect in the error pages to a special "error" controller![/quote]
The problem with that would be that the final error page would not give a 404 error.
Furthermore it seems impossible to reference CI inside an error page. To redirect (and what's the point in doing in manually) I'd have to load the URL helper. But calling $this->load->helper("URL") doesn't work: load isn't a property of $this in the scope (not that I know what the scope is).
What I really want is to deliver a 404 error header with the error messages supplied by CodeIgniter to the /error pages, but to feed it into a view as usual with any other page.
Isn't there a way?
[eluser]Michael Wales[/eluser]
So, the only downfall of using an error controller is you want the 404 header?
Add this to the top of the views that error controller calls:
Code: <?php header("HTTP/1.1 404 Not Found"); ?>
To make CI work in an error page - and I don't recommend this because you are then placing Controller code within a View (yucky!) - add the following code to the top:
Code: $CI =& get_instance();
Then, anytime you would normally use $this-> just use $CI-> instead.
Code: $CI->load->helper('url');
[eluser]Aquillyne[/eluser]
Surely there must be a way to achieve the desired effect without simply redirecting from the error page to another one? Why must I pass through a redirect?
Also, referencing the CI instance doesn't seem to do anything for me. If I add that line, the error page ceases to work entirely - I get a contentless browser 404 instead.
[eluser]Pascal Kriete[/eluser]
The Router (which calls most 404s) is loaded before CI_Base is instantiated, so you cannot use get_instance in the error templates.
It can be done with some work. First we need to extend two CI classes:
MY_Router:
Code: class MY_Router extends CI_Router {
/* Constructor */
function MY_Router()
{
// Needed for error pages
session_start();
parent::CI_Router();
}
// --------------------------------------------------------------------
function _validate_request($segments)
{
// Check for error flag
if (isset ($_SESSION['error']) )
{
$segments = array('error', 'placebo');
return $segments;
}
parent::_validate_request($segments);
}
}
MY_Exceptions:
Code: class MY_Exceptions extends CI_Exceptions {
var $CI;
/**
* Controller
*
* @access public
*/
function MY_Exceptions()
{
parent::CI_Exceptions();
}
// --------------------------------------------------------------------
/**
* Redirects if the previous request wasn't an error request
*
* @access public
* @param mixed error information
*/
function _redirect($error)
{
$conf =& load_class('Config');
$uri =& load_class('URI');
// If there is an error in MY_Controller we'll get a loop - stop it
if (isset ($_SESSION['error']))
{
echo '<h2>Fatal Error</h2>';
echo $_SESSION['error']['message'];
unset($_SESSION['error']);
exit;
}
$_SESSION['error'] = $error;
$redirect = $conf->site_url( $uri->uri_string() );
header("Location: ".$redirect);
}
// --------------------------------------------------------------------
/**
* General Error Page
*
* @access private
* @param string the heading
* @param string the message
* @param string the error function name
* @return string
*/
function show_error($heading = 'Fatal Error', $message = 'Unknown Error', $template = 'error_general')
{
$error = array(
'heading' => $heading,
'message' => $message,
'template' => $template
);
$this->_redirect($error);
}
// --------------------------------------------------------------------
/**
* Native PHP error handler
*
* @access private
* @param string the error severity
* @param string the error string
* @param string the error filepath
* @param string the error line number
* @return string
*/
function show_php_error($severity, $message, $filepath, $line)
{
$severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity];
$filepath = str_replace("\\", "/", $filepath);
// For safety reasons we do not show the full file path
if (FALSE !== strpos($filepath, '/'))
{
$x = explode('/', $filepath);
$filepath = $x[count($x)-2].'/'.end($x);
}
$error = array(
'severity' => $severity,
'message' => $message,
'filepath' => $filepath,
'line' => $line,
'template' => 'error_php'
);
$this->_redirect($error);
}
}
To be continued....
[eluser]Pascal Kriete[/eluser]
And now we need an error controller and error views. I'll just do the controller.
Error Controller:
Code: class Error extends Controller {
/**
* Constructor
*
* @access public
*/
function Error()
{
parent::Controller();
}
// --------------------------------------------------------------------
/**
* Shows error pages depending on the type of error
*
* @access private
*/
function _remap()
{
$err = $_SESSION['error'];
unset($_SESSION['error']);
switch($err['template'])
{
case 'error_404':
$this->_error_404($err['heading'], $err['message']);
break;
case 'error_php':
$this->_error_php($err['severity'], $err['message'], $err['filepath'], $err['line']);
break;
case 'error_db':
$this->_error_db($err['heading'], $err['message']);
break;
case 'error_general':
default:
$this->_error_general($err['heading'], $err['message']);
}
}
// --------------------------------------------------------------------
/**
* Display General Errors
*
* @access private
* @param string heading
* @param string error message
* @return description
*/
function _error_general($heading, $message)
{
$data = array(
'heading' => $heading,
'message' => $message
);
$this->load->view('error/general', $data);
}
// --------------------------------------------------------------------
/**
* Display 404 Errors
*
* @access private
* @param string heading
* @param string error message
*/
function _error_404($heading, $message)
{
header("HTTP/1.1 404 Not Found");
$data = array(
'heading' => $heading,
'message' => $message
);
$this->load->view('error/404', $data);
}
// --------------------------------------------------------------------
/**
* Display PHP Errors
*
* @access private
* @param string severity
* @param string message
* @param string filepath
* @param integer line
*/
function _error_php($severity, $message, $filepath, $line)
{
$data = array(
'severity' => $severity,
'message' => $message,
'filepath' => $filepath,
'line' => $line,
'template' => 'error_php'
);
$this->load->view('error/php', $data);
}
// --------------------------------------------------------------------
/**
* Display Database Errors
*
* @access private
* @param string heading
* @param string error message
* @return description
*/
function _error_db($heading, $message)
{
$data = array(
'heading' => $heading,
'message' => $message
);
$this->load->view('error/db', $data);
}
}
I had to copy paste that together with a few changes, so hopefully it works. Be careful when using this with a MY_Controller class, it loops easily.
[eluser]Aquillyne[/eluser]
[quote author="inparo" date="1212967129"]
MY_Router:
Code: class MY_Router extends CI_Router {
/* Constructor */
function MY_Router()
{
// Needed for error pages
session_start();
parent::CI_Router();
}
// --------------------------------------------------------------------
function _validate_request($segments)
{
// Check for error flag
if (isset ($_SESSION['error']) )
{
$segments = array('error', 'placebo');
return $segments;
}
parent::_validate_request($segments);
}
}
MY_Exceptions:
Code: class MY_Exceptions extends CI_Exceptions {
var $CI;
/**
* Controller
*
* @access public
*/
function MY_Exceptions()
{
parent::CI_Exceptions();
}
// --------------------------------------------------------------------
/**
* Redirects if the previous request wasn't an error request
*
* @access public
* @param mixed error information
*/
function _redirect($error)
{
$conf =& load_class('Config');
$uri =& load_class('URI');
// If there is an error in MY_Controller we'll get a loop - stop it
if (isset ($_SESSION['error']))
{
echo '<h2>Fatal Error</h2>';
echo $_SESSION['error']['message'];
unset($_SESSION['error']);
exit;
}
$_SESSION['error'] = $error;
$redirect = $conf->site_url( $uri->uri_string() );
header("Location: ".$redirect);
}
// --------------------------------------------------------------------
/**
* General Error Page
*
* @access private
* @param string the heading
* @param string the message
* @param string the error function name
* @return string
*/
function show_error($heading = 'Fatal Error', $message = 'Unknown Error', $template = 'error_general')
{
$error = array(
'heading' => $heading,
'message' => $message,
'template' => $template
);
$this->_redirect($error);
}
// --------------------------------------------------------------------
/**
* Native PHP error handler
*
* @access private
* @param string the error severity
* @param string the error string
* @param string the error filepath
* @param string the error line number
* @return string
*/
function show_php_error($severity, $message, $filepath, $line)
{
$severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity];
$filepath = str_replace("\\", "/", $filepath);
// For safety reasons we do not show the full file path
if (FALSE !== strpos($filepath, '/'))
{
$x = explode('/', $filepath);
$filepath = $x[count($x)-2].'/'.end($x);
}
$error = array(
'severity' => $severity,
'message' => $message,
'filepath' => $filepath,
'line' => $line,
'template' => 'error_php'
);
$this->_redirect($error);
}
}
[/quote]
Could you explain to me what's actually happening here? I can't follow the logic of it. At what point have you changed it so that errors trigger the error controller?
[eluser]Pascal Kriete[/eluser]
Sure thing.
Whenever CI encounters an error it calls the proper function in the Exceptions class. I overrode those functions (db errors aren't in there, but could be) so that they now set a session variable and then redirect to the same page.
So basically we've set a session variable and refreshed (url stays the same).
The router extension checks for the session variable (hence the native sessions, CI sessions don't work that early on in the processing), and if the variable is set it loads the error controller, regardless of the url. If it isn't set, it just routes them normally.
Let me know if that clears things up.
[eluser]Aquillyne[/eluser]
[quote author="inparo" date="1216514906"]Sure thing.
Whenever CI encounters an error it calls the proper function in the Exceptions class. I overrode those functions (db errors aren't in there, but could be) so that they now set a session variable and then redirect to the same page.
So basically we've set a session variable and refreshed (url stays the same).
The router extension checks for the session variable (hence the native sessions, CI sessions don't work that early on in the processing), and if the variable is set it loads the error controller, regardless of the url. If it isn't set, it just routes them normally.
Let me know if that clears things up.[/quote]
Wouldn't it be easier to redirect to the error controller rather than refreshing the same page?
|