Zend Exception instead of 404 - php

My ZF app is throwing an exception instead of returning a 404 for urls which are really 404s. E.g. testlotto.ie/rrr should be a 404, yet I get the following:
Fatal error: Uncaught exception 'Zend_Controller_Dispatcher_Exception' with message 'Invalid controller specified (rrr)' in /mnt/pc/sites/git-lotto/lotto/irish-lotto/library/Zend/Controller/Dispatcher/Standard.php:
I have tried the suggestions on Fatal error: Uncaught exception 'Zend_Controller_Dispatcher_Exception' while creating object of model class and Uncaught exception 'Zend_Controller_Dispatcher_Exception' (as well as many others), and nothing is working.
I do have my ErrorController controller in the ../application/controllers dir, which is what is returned when I die() out getControllerDirectory() from Controller/Dispatcher/Standard.php - so no problem of controller not being found.
My ErrorController is as follows (not that it matters as it is not getting called):
<?php
class ErrorController extends Zend_Controller_Action
{
public function errorAction()
{
$errors = $this->_getParam('error_handler');
switch ($errors->type) {
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
// 404 error -- controller or action not found
$this->getResponse()->setHttpResponseCode(404);
$this->getResponse()->setRawHeader('HTTP/1.1 404 Not Found');
$content =<<<EOH
<h1>Unlucky!</h1>
<p>The url you entered is not a valid one - please check what you typed, the mistake is most likely there.</p>
EOH;
break;
default:
// application error
$content =<<<EOH
<h1>Error!</h1>
<p>An unexpected error occurred. Please try again later.</p>
EOH;
break;
}
// Clear previous content
$this->getResponse()->clearBody();
$this->view->content = $content;
}
}
The start of the despatch method is:
public function dispatch(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response)
{
$this->setResponse($response);
/**
* Get controller class
*/
if (!$this->isDispatchable($request)) {
$controller = $request->getControllerName();
//die($controller);
//$this->setParam('useDefaultControllerAlways',true);
//ErrorController::errorAction();
if (!$this->getParam('useDefaultControllerAlways') && !empty($controller)) {
require_once 'Zend/Controller/Dispatcher/Exception.php';
throw new Zend_Controller_Dispatcher_Exception('Invalid controller specified (' . $request->getControllerName() . ')');
}
$className = $this->getDefaultControllerClass($request);
As you can see, I tried as suggested setting setParam('useDefaultControllerAlways',true);, but all this achieves is the homepage of the website is rendered (default controller of course) with a 200 response code - I need a 404.
Also, $controller dies out as the "rrr" in this example.
My question is what do I need to do to get 404's returned? This used to work on my site - I just swapped servers and now it is not working.

The only solution I could find to this which worked (i.e. the site now correctly returns a 404 for urls which do not exist), was taken from http://www.christopherhogan.com/2012/06/13/zend-framework-404-page/
Specifically, adding the below to my bootstrap file does the trick:
try {
$frontController->dispatch(); //instead of just $frontController->dispatch();
} catch (Zend_Exception $e) {
// this is where the 404 goes
header( 'HTTP/1.0 404 Not Found' );
echo "<div style='float:center; width:1000px; margin:0 auto;'><img src='http://www.foundco.com/images/404.jpg' alt='Everything is gonna be fine, please do not panic!' /></div>";
}
However, it's not perfect, as my ErrorController does not get called into action. If anyone could suggest how to trigger my ErrorController from the bootstrap file, would be much appreciated.

Related

TinyMVC PDO layer raising error on database query

When I use the built in PDO layer in TinyMVC to request records from a table, it returns the following error:
Array
Error: 0
Message: Unknown file 'register_view.php'
File:{redacted}tinymvc\sysfiles\plugins\tinymvc_view.php
Line: 125
When I however try just returning the same variable without a connection it displays it fine. The error it is raising is in the view layer because it cannot get the parameter passed to it. However I see no reason why it is doing that considering the query is running ok.
Here is the code from the view method:
<body>
<h1>Hello <?=$fname?></h1>
<p>Hello World</p>
And the code from the controller:
function index(){
$this->load->model('User_Model','user');
$this->view->assign('title','Manage your Peacock account');
$this->view->assign('fname', $this->user->fname());
$this->view->display('user_view');
}
Finally the code from the model:
public function __get($property) {
if (property_exists($this, $property)) {
/**
* Retrieve the data from the database
*/
$this->$property = $this->db->query_one('select '.$this->getTable($property).' from users where id=?',array('1'));
return $this->$property;
}
}
Any help will be appreciated
TinyMVC has the unfortunate trait of declaring an "Unknown file" error whenever a view with a fatal error is "display"ed. The reason is simple: the include code for the view is in /tinymvc/sysfiles/plugins/tinymvc_view.php in the last function - "_view()" in a "try-catch" block:
try {
include($_tmvc_filepath);
} catch (Exception $e) {
throw new Exception("Unknown file '$_tmvc_filepath'");
}
so ANY fatal error raised by the view automatically throws the "Unknown file" error.
If you want to see the real error, comment all the above lines and add the line:
require($_tmvc_filepath);
instead. This will anyways raise a fatal error if the file really isn't found, and will show you the real error that is in the view.

I'm trying to handle an Exception in PHP but stack error is still showing rather than being handled by catch

I'm calling a method that I know could cause an error and I'm trying to handle the error by wrapping the code in a try/catch statement...
class TestController extends Zend_Controller_Action
{
public function init()
{
// Anything here happens BEFORE the View has rendered
}
public function indexAction()
{
// Anything `echo`ed here is added to the end of the View
$model = new Application_Model_Testing('Mark', 31);
$this->view->sentence = $model->test();
$this->loadDataWhichCouldCauseError();
$this->loadView($model); // this method 'forwards' the Action onto another Controller
}
private function loadDataWhichCouldCauseError()
{
try {
$test = new Application_Model_NonExistent();
} catch (Exception $e) {
echo 'Handle the error';
}
}
private function loadView($model)
{
// Let's pretend we have loads of Models that require different Views
switch (get_class($model)) {
case 'Application_Model_Testing':
// Controller's have a `_forward` method to pass the Action onto another Controller
// The following line forwards to an `indexAction` within the `BlahController`
// It also passes some data onto the `BlahController`
$this->_forward('index', 'blah', null, array('data' => 'some data'));
break;
}
}
}
...but the problem I have is that the error isn't being handled. When viewing the application I get the following error...
( ! ) Fatal error: Class 'Application_Model_NonExistent' not found in /Library/WebServer/Documents/ZendTest/application/controllers/TestController.php on line 23
Can any one explain why this is happening and how I can get it to work?
Thanks
use
if (class_exists('Application_Model_NonExistent')) {
$test = new Application_Model_NonExistent;
} else {
echo 'class not found.';
}
like #prodigitalson said you can't catch that fatal error.
An error and an exception are not the same thing. Exceptions are thrown and meant to be caught, where errors are generally unrecoverable and triggered with http://www.php.net/manual/en/function.trigger-error.php
PHP: exceptions vs errors?
Can I try/catch a warning?
If you need to do some cleanup because of an error, you can use http://www.php.net/manual/en/function.set-error-handler.php
Thats not an exception, thats a FATAL error meaning you cant catch it like that. By definition a FATAL should not be recoverable.
Exception and Error are different things. There is an Exception class, which you are using and that $e is it's object.
You want to handle errors, check error handling in php-zend framework. But here, this is a Fatal error, you must rectify it, can not be handled.

register_shutdown_function in Zend Framework

I'm trying to catch fatal errors occuring in my Zend Framework application. I tried to call register_shutdown_function from the bootstrap:
protected function _initErrorHandler()
{
register_shutdown_function(array("My_ErrorHandler", 'shutdownHandler'));
}
Then, in My_ErrorHandler, I wrote a function :
<?php
class My_ErrorHandler
{
static function shutdownHandler()
{
die('here');
}
}
This doesn't work. I tried the same with set_error_handler, and it works. However, this last function can't catch fatal errors.
Do you what I am missing?
Thanks
I managed to make it work.
In fact, it was working, but that was not very "friendly". The die('here') was hit, but after the fatal error was displayed in the browser.
So I catched the fatal error, and then redirected to the standard Zend Framework error controller, this is the result :
<?php
class My_ErrorHandler
{
/**
* Catch all errors within the Applications
* #see Bootstrap
*/
static function shutdownHandler()
{
$e = error_get_last();
if (!is_null($e) && $e['type'] == E_ERROR) { //fatal error
//log
Zend_Registry::get('log')->err($e['message']);
//Redirect to error page
$redirector = new Zend_Controller_Action_Helper_Redirector();
$redirector->gotoSimple('error', 'error', null, array('error_handler' => 'fatal'));
}
}
}
Hope it will help others ;)
Thanks to #Jon, #Richard Parnaby-King and #ficuscr for their help.
NB: try to keep shutdownHandler() as light as possible: it is called each page is displayed.

Catch and log fatal errors, warnings, notices in Zend Framework

Currently I am using a basic error controller which looks like this:
class ErrorController extends My_MyController
{
public function errorAction()
{
$errors = $this->_getParam('error_handler');
switch ($errors->type) {
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
// 404 error -- controller or action not found
$this->getResponse()
->setRawHeader('HTTP/1.1 404 Not Found');
$this->view->headTitle('HTTP/1.1 404 Not Found');
$this->view->message = 'HTTP/1.1 404 Not Found';
break;
default:
// application error; display error page, but don't change
// status code
// Log the exception:
$exception = $errors->exception;
$log = new Zend_Log(
new Zend_Log_Writer_Stream(
BASE_PATH . '/logs/applicationException.log'
)
);
$log->debug($exception->getMessage() . "\n" .
$exception->getTraceAsString());
$this->view->headTitle('HTTP/1.1 404 Not Found');
$this->view->message = 'Application error';
break;
}
$this->view->exception = $errors->exception;
}
}
This, however, only catches and logs application exceptions. It won't log any warnings, notices and fatal errors.
I would like to log those as well. Is there a recommended way to do it in ErrorController? Or should it be done outside of the ErrorController in index.php (since Zend Framework ErrorHandler will only handle no route, missing application/action exceptions and exceptions in action controllers)?
Notices and warnings aren't (or shouldn't) be application fatal. Fatal errors do what they say on the tin and sometimes can't be caught. But, if you really need to, perhaps look into:
http://php.net/manual/en/function.set-error-handler.php

php: autoload exception handling

I'm extending my previous question (Handling exceptions within exception handle) to address my bad coding practice.
I'm trying to delegate autoload errors to a exception handler.
<?php
function __autoload($class_name) {
$file = $class_name.'.php';
try {
if (file_exists($file)) {
include $file;
}else{
throw new loadException("File $file is missing");
}
if(!class_exists($class_name,false)){
throw new loadException("Class $class_name missing in $file");
}
}catch(loadException $e){
header("HTTP/1.0 500 Internal Server Error");
$e->loadErrorPage('500');
exit;
}
return true;
}
class loadException extends Exception {
public function __toString()
{
return get_class($this) . " in {$this->file}({$this->line})".PHP_EOL
."'{$this->message}'".PHP_EOL
. "{$this->getTraceAsString()}";
}
public function loadErrorPage($code){
try {
$page = new pageClass();
echo $page->showPage($code);
}catch(Exception $e){
echo 'fatal error: ', $code;
}
}
}
$test = new testClass();
?>
the above script is supposed to load a 404 page if the testClass.php file is missing, and it works fine, UNLESS the pageClass.php file is missing as well, in which case I see a
"Fatal error: Class 'pageClass' not found in D:\xampp\htdocs\Test\PHP\errorhandle\index.php on line 29" instead of the "fatal error: 500" message
I do not want to add a try/catch block to each and every class autoload (object creation), so i tried this.
What is the proper way of handling this?
Have you tried checking for pageClass early on in the process, since it seems to be necessary even to get the error page out? If it doesn't exist, and if you don't want to write the 404 page w/o any objects (e.g. just HTML), bombing out of execution where that class doesn't exist would seem to be a good path.
Hope that helps.
Thanks,
Joe

Categories