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 }