File indexing completed on 2024-12-22 05:36:33
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Controller 0017 * @subpackage Plugins 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 */ 0021 0022 /** Zend_Controller_Plugin_Abstract */ 0023 // require_once 'Zend/Controller/Plugin/Abstract.php'; 0024 0025 /** 0026 * Handle exceptions that bubble up based on missing controllers, actions, or 0027 * application errors, and forward to an error handler. 0028 * 0029 * @uses Zend_Controller_Plugin_Abstract 0030 * @category Zend 0031 * @package Zend_Controller 0032 * @subpackage Plugins 0033 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0034 * @license http://framework.zend.com/license/new-bsd New BSD License 0035 * @version $Id$ 0036 */ 0037 class Zend_Controller_Plugin_ErrorHandler extends Zend_Controller_Plugin_Abstract 0038 { 0039 /** 0040 * Const - No controller exception; controller does not exist 0041 */ 0042 const EXCEPTION_NO_CONTROLLER = 'EXCEPTION_NO_CONTROLLER'; 0043 0044 /** 0045 * Const - No action exception; controller exists, but action does not 0046 */ 0047 const EXCEPTION_NO_ACTION = 'EXCEPTION_NO_ACTION'; 0048 0049 /** 0050 * Const - No route exception; no routing was possible 0051 */ 0052 const EXCEPTION_NO_ROUTE = 'EXCEPTION_NO_ROUTE'; 0053 0054 /** 0055 * Const - Other Exception; exceptions thrown by application controllers 0056 */ 0057 const EXCEPTION_OTHER = 'EXCEPTION_OTHER'; 0058 0059 /** 0060 * Module to use for errors; defaults to default module in dispatcher 0061 * @var string 0062 */ 0063 protected $_errorModule; 0064 0065 /** 0066 * Controller to use for errors; defaults to 'error' 0067 * @var string 0068 */ 0069 protected $_errorController = 'error'; 0070 0071 /** 0072 * Action to use for errors; defaults to 'error' 0073 * @var string 0074 */ 0075 protected $_errorAction = 'error'; 0076 0077 /** 0078 * Flag; are we already inside the error handler loop? 0079 * @var bool 0080 */ 0081 protected $_isInsideErrorHandlerLoop = false; 0082 0083 /** 0084 * Exception count logged at first invocation of plugin 0085 * @var int 0086 */ 0087 protected $_exceptionCountAtFirstEncounter = 0; 0088 0089 /** 0090 * Constructor 0091 * 0092 * Options may include: 0093 * - module 0094 * - controller 0095 * - action 0096 * 0097 * @param Array $options 0098 * @return void 0099 */ 0100 public function __construct(Array $options = array()) 0101 { 0102 $this->setErrorHandler($options); 0103 } 0104 0105 /** 0106 * setErrorHandler() - setup the error handling options 0107 * 0108 * @param array $options 0109 * @return Zend_Controller_Plugin_ErrorHandler 0110 */ 0111 public function setErrorHandler(Array $options = array()) 0112 { 0113 if (isset($options['module'])) { 0114 $this->setErrorHandlerModule($options['module']); 0115 } 0116 if (isset($options['controller'])) { 0117 $this->setErrorHandlerController($options['controller']); 0118 } 0119 if (isset($options['action'])) { 0120 $this->setErrorHandlerAction($options['action']); 0121 } 0122 return $this; 0123 } 0124 0125 /** 0126 * Set the module name for the error handler 0127 * 0128 * @param string $module 0129 * @return Zend_Controller_Plugin_ErrorHandler 0130 */ 0131 public function setErrorHandlerModule($module) 0132 { 0133 $this->_errorModule = (string) $module; 0134 return $this; 0135 } 0136 0137 /** 0138 * Retrieve the current error handler module 0139 * 0140 * @return string 0141 */ 0142 public function getErrorHandlerModule() 0143 { 0144 if (null === $this->_errorModule) { 0145 $this->_errorModule = Zend_Controller_Front::getInstance()->getDispatcher()->getDefaultModule(); 0146 } 0147 return $this->_errorModule; 0148 } 0149 0150 /** 0151 * Set the controller name for the error handler 0152 * 0153 * @param string $controller 0154 * @return Zend_Controller_Plugin_ErrorHandler 0155 */ 0156 public function setErrorHandlerController($controller) 0157 { 0158 $this->_errorController = (string) $controller; 0159 return $this; 0160 } 0161 0162 /** 0163 * Retrieve the current error handler controller 0164 * 0165 * @return string 0166 */ 0167 public function getErrorHandlerController() 0168 { 0169 return $this->_errorController; 0170 } 0171 0172 /** 0173 * Set the action name for the error handler 0174 * 0175 * @param string $action 0176 * @return Zend_Controller_Plugin_ErrorHandler 0177 */ 0178 public function setErrorHandlerAction($action) 0179 { 0180 $this->_errorAction = (string) $action; 0181 return $this; 0182 } 0183 0184 /** 0185 * Retrieve the current error handler action 0186 * 0187 * @return string 0188 */ 0189 public function getErrorHandlerAction() 0190 { 0191 return $this->_errorAction; 0192 } 0193 0194 /** 0195 * Route shutdown hook -- Ccheck for router exceptions 0196 * 0197 * @param Zend_Controller_Request_Abstract $request 0198 */ 0199 public function routeShutdown(Zend_Controller_Request_Abstract $request) 0200 { 0201 $this->_handleError($request); 0202 } 0203 0204 /** 0205 * Pre dispatch hook -- check for exceptions and dispatch error handler if 0206 * necessary 0207 * 0208 * @param Zend_Controller_Request_Abstract $request 0209 */ 0210 public function preDispatch(Zend_Controller_Request_Abstract $request) 0211 { 0212 $this->_handleError($request); 0213 } 0214 0215 /** 0216 * Post dispatch hook -- check for exceptions and dispatch error handler if 0217 * necessary 0218 * 0219 * @param Zend_Controller_Request_Abstract $request 0220 */ 0221 public function postDispatch(Zend_Controller_Request_Abstract $request) 0222 { 0223 $this->_handleError($request); 0224 } 0225 0226 /** 0227 * Handle errors and exceptions 0228 * 0229 * If the 'noErrorHandler' front controller flag has been set, 0230 * returns early. 0231 * 0232 * @param Zend_Controller_Request_Abstract $request 0233 * @return void 0234 */ 0235 protected function _handleError(Zend_Controller_Request_Abstract $request) 0236 { 0237 $frontController = Zend_Controller_Front::getInstance(); 0238 if ($frontController->getParam('noErrorHandler')) { 0239 return; 0240 } 0241 0242 $response = $this->getResponse(); 0243 0244 if ($this->_isInsideErrorHandlerLoop) { 0245 $exceptions = $response->getException(); 0246 if (count($exceptions) > $this->_exceptionCountAtFirstEncounter) { 0247 // Exception thrown by error handler; tell the front controller to throw it 0248 $frontController->throwExceptions(true); 0249 throw array_pop($exceptions); 0250 } 0251 } 0252 0253 // check for an exception AND allow the error handler controller the option to forward 0254 if (($response->isException()) && (!$this->_isInsideErrorHandlerLoop)) { 0255 $this->_isInsideErrorHandlerLoop = true; 0256 0257 // Get exception information 0258 $error = new ArrayObject(array(), ArrayObject::ARRAY_AS_PROPS); 0259 $exceptions = $response->getException(); 0260 $exception = $exceptions[0]; 0261 $exceptionType = get_class($exception); 0262 $error->exception = $exception; 0263 switch ($exceptionType) { 0264 case 'Zend_Controller_Router_Exception': 0265 if (404 == $exception->getCode()) { 0266 $error->type = self::EXCEPTION_NO_ROUTE; 0267 } else { 0268 $error->type = self::EXCEPTION_OTHER; 0269 } 0270 break; 0271 case 'Zend_Controller_Dispatcher_Exception': 0272 $error->type = self::EXCEPTION_NO_CONTROLLER; 0273 break; 0274 case 'Zend_Controller_Action_Exception': 0275 if (404 == $exception->getCode()) { 0276 $error->type = self::EXCEPTION_NO_ACTION; 0277 } else { 0278 $error->type = self::EXCEPTION_OTHER; 0279 } 0280 break; 0281 default: 0282 $error->type = self::EXCEPTION_OTHER; 0283 break; 0284 } 0285 0286 // Keep a copy of the original request 0287 $error->request = clone $request; 0288 0289 // get a count of the number of exceptions encountered 0290 $this->_exceptionCountAtFirstEncounter = count($exceptions); 0291 0292 // Forward to the error handler 0293 $request->setParam('error_handler', $error) 0294 ->setModuleName($this->getErrorHandlerModule()) 0295 ->setControllerName($this->getErrorHandlerController()) 0296 ->setActionName($this->getErrorHandlerAction()) 0297 ->setDispatched(false); 0298 } 0299 } 0300 }