1 <?php rcs_id('$Id: ErrorManager.php,v 1.2 2001-11-06 17:13:22 dairiki Exp $');
4 define ('EM_FATAL_ERRORS',
5 E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR);
6 define ('EM_WARNING_ERRORS',
7 E_WARNING | E_CORE_WARNING | E_COMPILE_WARNING | E_USER_WARNING);
8 define ('EM_NOTICE_ERRORS', E_NOTICE | E_USER_NOTICE);
12 * A class which allows custom handling of PHP errors.
14 * This is a singleton class. There should only be one instance
15 * of it --- you can access the one instance via $GLOBALS['ErrorManager'].
24 * As this is a singleton class, you should never call this.
27 function ErrorManager() {
28 $this->_handlers = array();
29 $this->_fatal_handler = false;
30 $this->_postpone_mask = 0;
31 $this->_postponed_errors = array();
33 set_error_handler('ErrorManager_errorHandler');
37 * Get mask indicating which errors are currently being postponed.
39 * @return int The current postponed error mask.
41 function getPostponedErrorMask() {
42 return $this->_postpone_mask;
46 * Set mask indicating which errors to postpone.
48 * The default value of the postpone mask is zero (no errors postponed.)
50 * When you set this mask, any queue errors which do not match tne new
54 * @param $newmask int The new value for the mask.
56 function setPostponedErrorMask($newmask) {
57 $this->_postpone_mask = $newmask;
58 $this->_flush_errors($newmask);
62 * Report any queued error messages.
65 function flushPostponedErrors() {
66 $this->_flush_errors();
70 * Push a custom error handler on the handler stack.
72 * Sometimes one is performing an operation where one expects certain errors
73 * or warnings. In this case, one might not want these errors reported
74 * in the normal manner. Installing a custom error handler via this method
75 * allows one to intercept such errors.
77 * An error handler installed via this method should be either a
78 * function or an object method taking one argument: a PhpError object.
80 * The error handler should return either:
82 * <dt> False <dd> If it has not handled the error. In this case, error
83 * processing will proceed as if the handler had never been called:
84 * the error will be passed to the next handler in the stack,
85 * or the default handler, if there are no more handlers in the stack.
86 * <dt> True <dd> If the handler has handled the error. If the error was
87 * a non-fatal one, no further processing will be done.
88 * If it was a fatal error, the ErrorManager will still
89 * terminate the PHP process (see setFatalHandler.)
90 * <dt> A PhpError object
91 * <dd> The error is not considered
92 * handled, and will be passed on to the next handler(s) in the stack
93 * (or the default handler).
94 * The returned PhpError need not be the same as the one passed to the
95 * handler. This allows the handler to "adjust" the error message.
98 * @param $handler string or array
99 * To register a global function as a handler, just pass the functions name
100 * (as a string). To register an object method as a handler, pass a array:
101 * the first element is the object, the second is the name of the method.
103 function pushErrorHandler($handler) {
104 array_unshift($this->_handlers, $handler);
108 * Pop an error handler off the handler stack.
111 function popErrorHandler() {
112 return array_shift($this->_handlers);
116 * Set a termination handler.
118 * This handler will be called upon fatal errors. The handler gets passed
119 * one argument: a PhpError object describing the fatal error.
122 * @param $handler string or array
123 * To register a global function as a handler, just pass the functions name
124 * (as a string). To register an object method as a handler, pass a array:
125 * the first element is the object, the second is the name of the method.
127 function setFatalHandler($handler) {
128 $this->_fatal_handler = $handler;
131 function _callHandler($handler, $error) {
132 if (is_string($handler)) {
133 return call_user_func($handler, $error);
135 else if (is_array($handler)) {
136 list($object, $method) = $handler;
137 if (method_exists($object, $method))
138 return call_user_method($method, $object, $error);
140 echo "<div>ErrorManager::_callHandler: BAD HANDLER<br></div>\n";
147 * The error is passed through any registered error handlers,
148 * and then either reported or postponed.
151 * @param $error object A PhpError object.
153 function handleError($error) {
156 if (!empty($in_handler)) {
157 echo "<p>ErrorManager: error while handling error:</p>\n";
158 echo $error->printError();
163 foreach ($this->_handlers as $handler) {
164 $result = $this->_callHandler($handler, $error);
166 continue; // Handler did not handle error.
168 elseif (is_object($result)) {
169 // handler filtered the result. Still should pass to the
170 // rest of the chain.
171 if ($error->isFatal()) {
172 // Don't let handlers make fatal errors non-fatal.
173 $result->errno = $error->errno;
178 // Handler handled error.
179 if (!$error->isFatal()) {
187 // Error was either fatal, or was not handled by a handler.
188 // Handle it ourself.
189 if ($error->isFatal()) {
192 else if (($error->errno & error_reporting()) != 0) {
193 if (($error->errno & $this->_postpone_mask) != 0) {
194 $this->_postponed_errors[] = $error;
197 $error->printError();
206 function _die($error) {
207 $error->printError();
208 $this->_flush_errors();
209 if ($this->_fatal_handler)
210 $this->_callHandler($this->_fatal_handler, $error);
217 function _flush_errors($keep_mask = 0) {
218 $errors = &$this->_postponed_errors;
219 foreach ($errors as $key => $error) {
220 if (($error->errno & $keep_mask) != 0)
222 unset($errors[$key]);
223 $error->printError();
229 * Global error handler for class ErrorManager.
231 * This is necessary since PHP's set_error_handler() does not allow one to
232 * set an object method as a handler.
236 function ErrorManager_errorHandler($errno, $errstr, $errfile, $errline)
238 global $ErrorManager;
239 $error = new PhpError($errno, $errstr, $errfile, $errline);
240 $ErrorManager->handleError($error);
245 * A class representing a PHP error report.
247 * @see The PHP documentation for set_error_handler at
248 * http://php.net/manual/en/function.set-error-handler.php .
257 * The PHP error message.
262 * The source file where the error occurred.
267 * The line number (in $this->errfile) where the error occured.
272 * Construct a new PhpError.
274 * @param $errstr string
275 * @param $errfile string
276 * @param $errline int
278 function PhpError($errno, $errstr, $errfile, $errline) {
279 $this->errno = $errno;
280 $this->errstr = $errstr;
281 $this->errfile = $errfile;
282 $this->errline = $errline;
286 * Determine whether this is a fatal error.
287 * @return boolean True if this is a fatal error.
290 return ($this->errno & (EM_WARNING_ERRORS|EM_NOTICE_ERRORS)) == 0;
294 * Determine whether this is a warning level error.
297 function isWarning() {
298 return ($this->errno & EM_WARNING_ERRORS) != 0;
302 * Determine whether this is a notice level error.
305 function isNotice() {
306 return ($this->errno & EM_NOTICE_ERRORS) != 0;
310 * Get a printable, HTML, message detailing this error.
311 * @return string The detailed error message.
313 function getDetail() {
314 if ($this->isNotice())
316 else if ($this->isWarning())
321 $errfile = ereg_replace('^' . getcwd() . '/', '', $this->errfile);
323 $lines = explode("\n", $this->errstr);
324 $errstr = htmlspecialchars(array_shift($lines));
325 foreach ($lines as $key => $line)
326 $lines[$key] = "<li>" . htmlspecialchars($line) . "</li>";
328 $errstr .= "<ul>\n" . join("\n", $lines) . "\n</ul>";
330 return sprintf("<p class='error'>%s:%d: %s[%d]: %s</p>\n",
331 htmlspecialchars($errfile),
332 $this->errline, $what, $this->errno,
337 * Print an HTMLified version of this error.
340 function printError() {
341 echo $this->getDetail();
345 if (!isset($GLOBALS['ErrorManager'])) {
346 $GLOBALS['ErrorManager'] = new ErrorManager;
349 // (c-file-style: "gnu")
354 // c-hanging-comment-ender-p: nil
355 // indent-tabs-mode: nil