1: <?php
  2:   3:   4:   5:   6:   7:   8:   9:  10:  11:  12:  13:  14:  15:  16:  17:  18:  19:  20: 
 21: 
 22: App::uses('Sanitize', 'Utility');
 23: App::uses('Dispatcher', 'Routing');
 24: App::uses('Router', 'Routing');
 25: App::uses('Controller', 'Controller');
 26: App::uses('CakeRequest', 'Network');
 27: App::uses('CakeResponse', 'Network');
 28: App::uses('CakeEvent', 'Event');
 29: 
 30:  31:  32:  33:  34:  35:  36:  37:  38:  39:  40:  41:  42:  43:  44:  45:  46:  47:  48:  49:  50:  51:  52:  53:  54:  55:  56: 
 57: class ExceptionRenderer {
 58: 
 59:  60:  61:  62:  63: 
 64:     public $controller = null;
 65: 
 66:  67:  68:  69:  70: 
 71:     public $template = '';
 72: 
 73:  74:  75:  76:  77: 
 78:     public $method = '';
 79: 
 80:  81:  82:  83:  84: 
 85:     public $error = null;
 86: 
 87:  88:  89:  90:  91:  92:  93: 
 94:     public function __construct($exception) {
 95:         $this->controller = $this->_getController($exception);
 96: 
 97:         if (method_exists($this->controller, 'appError')) {
 98:             $this->controller->appError($exception);
 99:             return;
100:         }
101:         $method = $template = Inflector::variable(str_replace('Exception', '', get_class($exception)));
102:         $code = $exception->getCode();
103: 
104:         $methodExists = method_exists($this, $method);
105: 
106:         if ($exception instanceof CakeException && !$methodExists) {
107:             $method = '_cakeError';
108:             if (empty($template) || $template === 'internalError') {
109:                 $template = 'error500';
110:             }
111:         } elseif ($exception instanceof PDOException) {
112:             $method = 'pdoError';
113:             $template = 'pdo_error';
114:             $code = 500;
115:         } elseif (!$methodExists) {
116:             $method = 'error500';
117:             if ($code >= 400 && $code < 500) {
118:                 $method = 'error400';
119:             }
120:         }
121: 
122:         $isNotDebug = !Configure::read('debug');
123:         if ($isNotDebug && $method === '_cakeError') {
124:             $method = 'error400';
125:         }
126:         if ($isNotDebug && $code == 500) {
127:             $method = 'error500';
128:         }
129:         $this->template = $template;
130:         $this->method = $method;
131:         $this->error = $exception;
132:     }
133: 
134: 135: 136: 137: 138: 139: 140: 141: 142: 
143:     protected function _getController($exception) {
144:         App::uses('AppController', 'Controller');
145:         App::uses('CakeErrorController', 'Controller');
146:         if (!$request = Router::getRequest(true)) {
147:             $request = new CakeRequest();
148:         }
149:         $response = new CakeResponse();
150: 
151:         if (method_exists($exception, 'responseHeader')) {
152:             $response->header($exception->responseHeader());
153:         }
154: 
155:         if (class_exists('AppController')) {
156:             try {
157:                 $controller = new CakeErrorController($request, $response);
158:                 $controller->startupProcess();
159:                 $startup = true;
160:             } catch (Exception $e) {
161:                 $startup = false;
162:             }
163:             
164:             
165:             
166:             if ($startup === false &&
167:                 !empty($controller) &&
168:                 $controller->Components->enabled('RequestHandler')
169:             ) {
170:                 try {
171:                     $controller->RequestHandler->startup($controller);
172:                 } catch (Exception $e) {
173:                 }
174:             }
175:         }
176:         if (empty($controller)) {
177:             $controller = new Controller($request, $response);
178:             $controller->viewPath = 'Errors';
179:         }
180:         return $controller;
181:     }
182: 
183: 184: 185: 186: 187: 
188:     public function render() {
189:         if ($this->method) {
190:             call_user_func_array(array($this, $this->method), array($this->error));
191:         }
192:     }
193: 
194: 195: 196: 197: 198: 199: 
200:     protected function _cakeError(CakeException $error) {
201:         $url = $this->controller->request->here();
202:         $code = ($error->getCode() >= 400 && $error->getCode() < 506) ? $error->getCode() : 500;
203:         $this->controller->response->statusCode($code);
204:         $this->controller->set(array(
205:             'code' => $code,
206:             'name' => h($error->getMessage()),
207:             'message' => h($error->getMessage()),
208:             'url' => h($url),
209:             'error' => $error,
210:             '_serialize' => array('code', 'name', 'message', 'url')
211:         ));
212:         $this->controller->set($error->getAttributes());
213:         $this->_outputMessage($this->template);
214:     }
215: 
216: 217: 218: 219: 220: 221: 
222:     public function error400($error) {
223:         $message = $error->getMessage();
224:         if (!Configure::read('debug') && $error instanceof CakeException) {
225:             $message = __d('cake', 'Not Found');
226:         }
227:         $url = $this->controller->request->here();
228:         $this->controller->response->statusCode($error->getCode());
229:         $this->controller->set(array(
230:             'name' => h($message),
231:             'message' => h($message),
232:             'url' => h($url),
233:             'error' => $error,
234:             '_serialize' => array('name', 'message', 'url')
235:         ));
236:         $this->_outputMessage('error400');
237:     }
238: 
239: 240: 241: 242: 243: 244: 
245:     public function error500($error) {
246:         $message = $error->getMessage();
247:         if (!Configure::read('debug')) {
248:             $message = __d('cake', 'An Internal Error Has Occurred.');
249:         }
250:         $url = $this->controller->request->here();
251:         $code = ($error->getCode() > 500 && $error->getCode() < 506) ? $error->getCode() : 500;
252:         $this->controller->response->statusCode($code);
253:         $this->controller->set(array(
254:             'name' => h($message),
255:             'message' => h($message),
256:             'url' => h($url),
257:             'error' => $error,
258:             '_serialize' => array('name', 'message', 'url')
259:         ));
260:         $this->_outputMessage('error500');
261:     }
262: 
263: 264: 265: 266: 267: 268: 
269:     public function pdoError(PDOException $error) {
270:         $url = $this->controller->request->here();
271:         $code = 500;
272:         $this->controller->response->statusCode($code);
273:         $this->controller->set(array(
274:             'code' => $code,
275:             'name' => h($error->getMessage()),
276:             'message' => h($error->getMessage()),
277:             'url' => h($url),
278:             'error' => $error,
279:             '_serialize' => array('code', 'name', 'message', 'url', 'error')
280:         ));
281:         $this->_outputMessage($this->template);
282:     }
283: 
284: 285: 286: 287: 288: 289: 
290:     protected function _outputMessage($template) {
291:         try {
292:             $this->controller->render($template);
293:             $this->_shutdown();
294:             $this->controller->response->send();
295:         } catch (MissingViewException $e) {
296:             $attributes = $e->getAttributes();
297:             if (isset($attributes['file']) && strpos($attributes['file'], 'error500') !== false) {
298:                 $this->_outputMessageSafe('error500');
299:             } else {
300:                 $this->_outputMessage('error500');
301:             }
302:         } catch (MissingPluginException $e) {
303:             $attributes = $e->getAttributes();
304:             if (isset($attributes['plugin']) && $attributes['plugin'] === $this->controller->plugin) {
305:                 $this->controller->plugin = null;
306:             }
307:             $this->_outputMessageSafe('error500');
308:         } catch (Exception $e) {
309:             $this->_outputMessageSafe('error500');
310:         }
311:     }
312: 
313: 314: 315: 316: 317: 318: 319: 
320:     protected function _outputMessageSafe($template) {
321:         $this->controller->layoutPath = null;
322:         $this->controller->subDir = null;
323:         $this->controller->viewPath = 'Errors';
324:         $this->controller->layout = 'error';
325:         $this->controller->helpers = array('Form', 'Html', 'Session');
326: 
327:         $view = new View($this->controller);
328:         $this->controller->response->body($view->render($template, 'error'));
329:         $this->controller->response->type('html');
330:         $this->controller->response->send();
331:     }
332: 
333: 334: 335: 336: 337: 338: 339: 
340:     protected function _shutdown() {
341:         $afterFilterEvent = new CakeEvent('Controller.shutdown', $this->controller);
342:         $this->controller->getEventManager()->dispatch($afterFilterEvent);
343: 
344:         $Dispatcher = new Dispatcher();
345:         $afterDispatchEvent = new CakeEvent('Dispatcher.afterDispatch', $Dispatcher, array(
346:             'request' => $this->controller->request,
347:             'response' => $this->controller->response
348:         ));
349:         $Dispatcher->getEventManager()->dispatch($afterDispatchEvent);
350:     }
351: 
352: }
353: