1 <?php rcs_id('$Id: ErrorManager.php,v 1.10 2002-01-20 03:45:47 carstenklapp 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 * Get postponed errors, formatted as HTML.
72 * This also flushes the postponed error queue.
74 * @return string HTML describing any queued errors.
76 function getPostponedErrorsAsHTML() {
78 $this->flushPostponedErrors();
79 $html = ob_get_contents();
85 return Element('div', array('class' => 'errors'),
86 QElement('h4', sprintf(_("PHP %s Warnings"),
92 * Push a custom error handler on the handler stack.
94 * Sometimes one is performing an operation where one expects
95 * certain errors or warnings. In this case, one might not want
96 * these errors reported in the normal manner. Installing a custom
97 * error handler via this method allows one to intercept such
100 * An error handler installed via this method should be either a
101 * function or an object method taking one argument: a PhpError
104 * The error handler should return either:
106 * <dt> False <dd> If it has not handled the error. In this case,
107 * error processing will proceed as if the handler
108 * had never been called: the error will be passed
109 * to the next handler in the stack, or the
110 * default handler, if there are no more handlers
113 * <dt> True <dd> If the handler has handled the error. If the
114 * error was a non-fatal one, no further processing
115 * will be done. If it was a fatal error, the
116 * ErrorManager will still terminate the PHP
117 * process (see setFatalHandler.)
119 * <dt> A PhpError object <dd> The error is not considered
120 * handled, and will be passed on to
121 * the next handler(s) in the stack
122 * (or the default handler). The
123 * returned PhpError need not be the
124 * same as the one passed to the
125 * handler. This allows the handler to
126 * "adjust" the error message.
129 * @param $handler WikiCallback Handler to call.
131 function pushErrorHandler($handler) {
132 array_unshift($this->_handlers, $handler);
136 * Pop an error handler off the handler stack.
139 function popErrorHandler() {
140 return array_shift($this->_handlers);
144 * Set a termination handler.
146 * This handler will be called upon fatal errors. The handler
147 * gets passed one argument: a PhpError object describing the
151 * @param $handler WikiCallback Callback to call on fatal errors.
153 function setFatalHandler($handler) {
154 $this->_fatal_handler = $handler;
160 * The error is passed through any registered error handlers, and
161 * then either reported or postponed.
164 * @param $error object A PhpError object.
166 function handleError($error) {
169 if (!empty($in_handler)) {
170 echo "<p>ErrorManager: "._("error while handling error:")."</p>\n";
171 echo $error->printError();
176 foreach ($this->_handlers as $handler) {
177 $result = $handler->call($error);
179 continue; // Handler did not handle error.
181 elseif (is_object($result)) {
182 // handler filtered the result. Still should pass to
183 // the rest of the chain.
184 if ($error->isFatal()) {
185 // Don't let handlers make fatal errors non-fatal.
186 $result->errno = $error->errno;
191 // Handler handled error.
192 if (!$error->isFatal()) {
200 // Error was either fatal, or was not handled by a handler.
201 // Handle it ourself.
202 if ($error->isFatal()) {
205 else if (($error->errno & error_reporting()) != 0) {
206 if (($error->errno & $this->_postpone_mask) != 0) {
207 $this->_postponed_errors[] = $error;
210 $error->printError();
219 function _die($error) {
220 $error->printError();
221 $this->_flush_errors();
222 if ($this->_fatal_handler)
223 $this->_fatal_handler->call($error);
230 function _flush_errors($keep_mask = 0) {
231 $errors = &$this->_postponed_errors;
232 foreach ($errors as $key => $error) {
233 if (($error->errno & $keep_mask) != 0)
235 unset($errors[$key]);
236 $error->printError();
242 * Global error handler for class ErrorManager.
244 * This is necessary since PHP's set_error_handler() does not allow
245 * one to set an object method as a handler.
249 function ErrorManager_errorHandler($errno, $errstr, $errfile, $errline)
251 global $ErrorManager;
252 $error = new PhpError($errno, $errstr, $errfile, $errline);
253 $ErrorManager->handleError($error);
258 * A class representing a PHP error report.
260 * @see The PHP documentation for set_error_handler at
261 * http://php.net/manual/en/function.set-error-handler.php .
270 * The PHP error message.
275 * The source file where the error occurred.
280 * The line number (in $this->errfile) where the error occured.
285 * Construct a new PhpError.
287 * @param $errstr string
288 * @param $errfile string
289 * @param $errline int
291 function PhpError($errno, $errstr, $errfile, $errline) {
292 $this->errno = $errno;
293 $this->errstr = $errstr;
294 $this->errfile = $errfile;
295 $this->errline = $errline;
299 * Determine whether this is a fatal error.
300 * @return boolean True if this is a fatal error.
303 return ($this->errno & (EM_WARNING_ERRORS|EM_NOTICE_ERRORS)) == 0;
307 * Determine whether this is a warning level error.
310 function isWarning() {
311 return ($this->errno & EM_WARNING_ERRORS) != 0;
315 * Determine whether this is a notice level error.
318 function isNotice() {
319 return ($this->errno & EM_NOTICE_ERRORS) != 0;
323 * Get a printable, HTML, message detailing this error.
324 * @return string The detailed error message.
326 function getDetail() {
327 if ($this->isNotice())
329 else if ($this->isWarning())
334 $errfile = ereg_replace('^' . getcwd() . '/', '', $this->errfile);
336 $lines = explode("\n", $this->errstr);
337 $errstr = htmlspecialchars(array_shift($lines));
338 foreach ($lines as $key => $line)
339 $lines[$key] = "<li>" . htmlspecialchars($line) . "</li>";
341 $errstr .= "<ul>\n" . join("\n", $lines) . "\n</ul>";
343 return sprintf("<p class='error'>%s:%d: %s[%d]: %s</p>\n",
344 htmlspecialchars($errfile),
345 $this->errline, $what, $this->errno,
350 * Print an HTMLified version of this error.
353 function printError() {
354 echo $this->getDetail();
358 if (!isset($GLOBALS['ErrorManager'])) {
359 $GLOBALS['ErrorManager'] = new ErrorManager;
362 // (c-file-style: "gnu")
367 // c-hanging-comment-ender-p: nil
368 // indent-tabs-mode: nil