Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
16591 anikendra 1
<?php
2
/**
3
 * Exception Renderer
4
 *
5
 * Provides Exception rendering features. Which allow exceptions to be rendered
6
 * as HTML pages.
7
 *
8
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
9
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
10
 *
11
 * Licensed under The MIT License
12
 * For full copyright and license information, please see the LICENSE.txt
13
 * Redistributions of files must retain the above copyright notice.
14
 *
15
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
16
 * @link          http://cakephp.org CakePHP(tm) Project
17
 * @package       Cake.Error
18
 * @since         CakePHP(tm) v 2.0
19
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
20
 */
21
 
22
App::uses('Sanitize', 'Utility');
23
App::uses('Router', 'Routing');
24
App::uses('CakeResponse', 'Network');
25
App::uses('Controller', 'Controller');
26
 
27
/**
28
 * Exception Renderer.
29
 *
30
 * Captures and handles all unhandled exceptions. Displays helpful framework errors when debug > 1.
31
 * When debug < 1 a CakeException will render 404 or 500 errors. If an uncaught exception is thrown
32
 * and it is a type that ExceptionHandler does not know about it will be treated as a 500 error.
33
 *
34
 * ### Implementing application specific exception rendering
35
 *
36
 * You can implement application specific exception handling in one of a few ways:
37
 *
38
 * - Create an AppController::appError();
39
 * - Create a subclass of ExceptionRenderer and configure it to be the `Exception.renderer`
40
 *
41
 * #### Using AppController::appError();
42
 *
43
 * This controller method is called instead of the default exception handling. It receives the
44
 * thrown exception as its only argument. You should implement your error handling in that method.
45
 *
46
 * #### Using a subclass of ExceptionRenderer
47
 *
48
 * Using a subclass of ExceptionRenderer gives you full control over how Exceptions are rendered, you
49
 * can configure your class in your core.php, with `Configure::write('Exception.renderer', 'MyClass');`
50
 * You should place any custom exception renderers in `app/Lib/Error`.
51
 *
52
 * @package       Cake.Error
53
 */
54
class ExceptionRenderer {
55
 
56
/**
57
 * Controller instance.
58
 *
59
 * @var Controller
60
 */
61
	public $controller = null;
62
 
63
/**
64
 * template to render for CakeException
65
 *
66
 * @var string
67
 */
68
	public $template = '';
69
 
70
/**
71
 * The method corresponding to the Exception this object is for.
72
 *
73
 * @var string
74
 */
75
	public $method = '';
76
 
77
/**
78
 * The exception being handled.
79
 *
80
 * @var Exception
81
 */
82
	public $error = null;
83
 
84
/**
85
 * Creates the controller to perform rendering on the error response.
86
 * If the error is a CakeException it will be converted to either a 400 or a 500
87
 * code error depending on the code used to construct the error.
88
 *
89
 * @param Exception $exception Exception
90
 */
91
	public function __construct(Exception $exception) {
92
		$this->controller = $this->_getController($exception);
93
 
94
		if (method_exists($this->controller, 'appError')) {
95
			$this->controller->appError($exception);
96
			return;
97
		}
98
		$method = $template = Inflector::variable(str_replace('Exception', '', get_class($exception)));
99
		$code = $exception->getCode();
100
 
101
		$methodExists = method_exists($this, $method);
102
 
103
		if ($exception instanceof CakeException && !$methodExists) {
104
			$method = '_cakeError';
105
			if (empty($template) || $template === 'internalError') {
106
				$template = 'error500';
107
			}
108
		} elseif ($exception instanceof PDOException) {
109
			$method = 'pdoError';
110
			$template = 'pdo_error';
111
			$code = 500;
112
		} elseif (!$methodExists) {
113
			$method = 'error500';
114
			if ($code >= 400 && $code < 500) {
115
				$method = 'error400';
116
			}
117
		}
118
 
119
		$isNotDebug = !Configure::read('debug');
120
		if ($isNotDebug && $method === '_cakeError') {
121
			$method = 'error400';
122
		}
123
		if ($isNotDebug && $code == 500) {
124
			$method = 'error500';
125
		}
126
		$this->template = $template;
127
		$this->method = $method;
128
		$this->error = $exception;
129
	}
130
 
131
/**
132
 * Get the controller instance to handle the exception.
133
 * Override this method in subclasses to customize the controller used.
134
 * This method returns the built in `CakeErrorController` normally, or if an error is repeated
135
 * a bare controller will be used.
136
 *
137
 * @param Exception $exception The exception to get a controller for.
138
 * @return Controller
139
 */
140
	protected function _getController($exception) {
141
		App::uses('AppController', 'Controller');
142
		App::uses('CakeErrorController', 'Controller');
143
		if (!$request = Router::getRequest(true)) {
144
			$request = new CakeRequest();
145
		}
146
		$response = new CakeResponse();
147
 
148
		if (method_exists($exception, 'responseHeader')) {
149
			$response->header($exception->responseHeader());
150
		}
151
 
152
		if (class_exists('AppController')) {
153
			try {
154
				$controller = new CakeErrorController($request, $response);
155
				$controller->startupProcess();
156
				$startup = true;
157
			} catch (Exception $e) {
158
				$startup = false;
159
			}
160
			// Retry RequestHandler, as another aspect of startupProcess()
161
			// could have failed. Ignore any exceptions out of startup, as
162
			// there could be userland input data parsers.
163
			if ($startup === false &&
164
				!empty($controller) &&
165
				$controller->Components->enabled('RequestHandler')
166
			) {
167
				try {
168
					$controller->RequestHandler->startup($controller);
169
				} catch (Exception $e) {
170
				}
171
			}
172
		}
173
		if (empty($controller)) {
174
			$controller = new Controller($request, $response);
175
			$controller->viewPath = 'Errors';
176
		}
177
		return $controller;
178
	}
179
 
180
/**
181
 * Renders the response for the exception.
182
 *
183
 * @return void
184
 */
185
	public function render() {
186
		if ($this->method) {
187
			call_user_func_array(array($this, $this->method), array($this->error));
188
		}
189
	}
190
 
191
/**
192
 * Generic handler for the internal framework errors CakePHP can generate.
193
 *
194
 * @param CakeException $error The exception to render.
195
 * @return void
196
 */
197
	protected function _cakeError(CakeException $error) {
198
		$url = $this->controller->request->here();
199
		$code = ($error->getCode() >= 400 && $error->getCode() < 506) ? $error->getCode() : 500;
200
		$this->controller->response->statusCode($code);
201
		$this->controller->set(array(
202
			'code' => $code,
203
			'name' => h($error->getMessage()),
204
			'message' => h($error->getMessage()),
205
			'url' => h($url),
206
			'error' => $error,
207
			'_serialize' => array('code', 'name', 'message', 'url')
208
		));
209
		$this->controller->set($error->getAttributes());
210
		$this->_outputMessage($this->template);
211
	}
212
 
213
/**
214
 * Convenience method to display a 400 series page.
215
 *
216
 * @param Exception $error The exception to render.
217
 * @return void
218
 */
219
	public function error400($error) {
220
		$message = $error->getMessage();
221
		if (!Configure::read('debug') && $error instanceof CakeException) {
222
			$message = __d('cake', 'Not Found');
223
		}
224
		$url = $this->controller->request->here();
225
		$this->controller->response->statusCode($error->getCode());
226
		$this->controller->set(array(
227
			'name' => h($message),
228
			'message' => h($message),
229
			'url' => h($url),
230
			'error' => $error,
231
			'_serialize' => array('name', 'message', 'url')
232
		));
233
		$this->_outputMessage('error400');
234
	}
235
 
236
/**
237
 * Convenience method to display a 500 page.
238
 *
239
 * @param Exception $error The exception to render.
240
 * @return void
241
 */
242
	public function error500($error) {
243
		$message = $error->getMessage();
244
		if (!Configure::read('debug')) {
245
			$message = __d('cake', 'An Internal Error Has Occurred.');
246
		}
247
		$url = $this->controller->request->here();
248
		$code = ($error->getCode() > 500 && $error->getCode() < 506) ? $error->getCode() : 500;
249
		$this->controller->response->statusCode($code);
250
		$this->controller->set(array(
251
			'name' => h($message),
252
			'message' => h($message),
253
			'url' => h($url),
254
			'error' => $error,
255
			'_serialize' => array('name', 'message', 'url')
256
		));
257
		$this->_outputMessage('error500');
258
	}
259
 
260
/**
261
 * Convenience method to display a PDOException.
262
 *
263
 * @param PDOException $error The exception to render.
264
 * @return void
265
 */
266
	public function pdoError(PDOException $error) {
267
		$url = $this->controller->request->here();
268
		$code = 500;
269
		$this->controller->response->statusCode($code);
270
		$this->controller->set(array(
271
			'code' => $code,
272
			'name' => h($error->getMessage()),
273
			'message' => h($error->getMessage()),
274
			'url' => h($url),
275
			'error' => $error,
276
			'_serialize' => array('code', 'name', 'message', 'url', 'error')
277
		));
278
		$this->_outputMessage($this->template);
279
	}
280
 
281
/**
282
 * Generate the response using the controller object.
283
 *
284
 * @param string $template The template to render.
285
 * @return void
286
 */
287
	protected function _outputMessage($template) {
288
		try {
289
			$this->controller->render($template);
290
			$this->controller->afterFilter();
291
			$this->controller->response->send();
292
		} catch (MissingViewException $e) {
293
			$attributes = $e->getAttributes();
294
			if (isset($attributes['file']) && strpos($attributes['file'], 'error500') !== false) {
295
				$this->_outputMessageSafe('error500');
296
			} else {
297
				$this->_outputMessage('error500');
298
			}
299
		} catch (MissingPluginException $e) {
300
			$attributes = $e->getAttributes();
301
			if (isset($attributes['plugin']) && $attributes['plugin'] === $this->controller->plugin) {
302
				$this->controller->plugin = null;
303
			}
304
			$this->_outputMessageSafe('error500');
305
		} catch (Exception $e) {
306
			$this->_outputMessageSafe('error500');
307
		}
308
	}
309
 
310
/**
311
 * A safer way to render error messages, replaces all helpers, with basics
312
 * and doesn't call component methods.
313
 *
314
 * @param string $template The template to render
315
 * @return void
316
 */
317
	protected function _outputMessageSafe($template) {
318
		$this->controller->layoutPath = null;
319
		$this->controller->subDir = null;
320
		$this->controller->viewPath = 'Errors';
321
		$this->controller->layout = 'error';
322
		$this->controller->helpers = array('Form', 'Html', 'Session');
323
 
324
		$view = new View($this->controller);
325
		$this->controller->response->body($view->render($template, 'error'));
326
		$this->controller->response->type('html');
327
		$this->controller->response->send();
328
	}
329
 
330
}