Редакция 69 | Содержимое файла | Сравнить с предыдущей | Последнее изменение | Открыть журнал | RSS
Редакция | Автор | № строки | Строка |
---|---|---|---|
69 | alex-w | 1 | <?php |
2 | /** |
||
3 | * Error Stack Implementation |
||
4 | * |
||
5 | * This is an incredibly simple implementation of a very complex error handling |
||
6 | * facility. It contains the ability |
||
7 | * to track multiple errors from multiple packages simultaneously. In addition, |
||
8 | * it can track errors of many levels, save data along with the error, context |
||
9 | * information such as the exact file, line number, class and function that |
||
10 | * generated the error, and if necessary, it can raise a traditional PEAR_Error. |
||
11 | * It has built-in support for PEAR::Log, to log errors as they occur |
||
12 | * |
||
13 | * Since version 0.2alpha, it is also possible to selectively ignore errors, |
||
14 | * through the use of an error callback, see {@link pushCallback()} |
||
15 | * |
||
16 | * Since version 0.3alpha, it is possible to specify the exception class |
||
17 | * returned from {@link push()} |
||
18 | * |
||
19 | * Since version PEAR1.3.2, ErrorStack no longer instantiates an exception class. This can |
||
20 | * still be done quite handily in an error callback or by manipulating the returned array |
||
21 | * @category Debugging |
||
22 | * @package PEAR_ErrorStack |
||
23 | * @author Greg Beaver <cellog@php.net> |
||
24 | * @copyright 2004-2008 Greg Beaver |
||
25 | * @license http://www.php.net/license/3_0.txt PHP License 3.0 |
||
26 | * @version CVS: $Id: ErrorStack.php,v 1.28 2008/01/03 20:26:35 cellog Exp $ |
||
27 | * @link http://pear.php.net/package/PEAR_ErrorStack |
||
28 | */ |
||
29 | |||
30 | /** |
||
31 | * Singleton storage |
||
32 | * |
||
33 | * Format: |
||
34 | * <pre> |
||
35 | * array( |
||
36 | * 'package1' => PEAR_ErrorStack object, |
||
37 | * 'package2' => PEAR_ErrorStack object, |
||
38 | * ... |
||
39 | * ) |
||
40 | * </pre> |
||
41 | * @access private |
||
42 | * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] |
||
43 | */ |
||
44 | $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array(); |
||
45 | |||
46 | /** |
||
47 | * Global error callback (default) |
||
48 | * |
||
49 | * This is only used if set to non-false. * is the default callback for |
||
50 | * all packages, whereas specific packages may set a default callback |
||
51 | * for all instances, regardless of whether they are a singleton or not. |
||
52 | * |
||
53 | * To exclude non-singletons, only set the local callback for the singleton |
||
54 | * @see PEAR_ErrorStack::setDefaultCallback() |
||
55 | * @access private |
||
56 | * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] |
||
57 | */ |
||
58 | $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array( |
||
59 | '*' => false, |
||
60 | ); |
||
61 | |||
62 | /** |
||
63 | * Global Log object (default) |
||
64 | * |
||
65 | * This is only used if set to non-false. Use to set a default log object for |
||
66 | * all stacks, regardless of instantiation order or location |
||
67 | * @see PEAR_ErrorStack::setDefaultLogger() |
||
68 | * @access private |
||
69 | * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] |
||
70 | */ |
||
71 | $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false; |
||
72 | |||
73 | /** |
||
74 | * Global Overriding Callback |
||
75 | * |
||
76 | * This callback will override any error callbacks that specific loggers have set. |
||
77 | * Use with EXTREME caution |
||
78 | * @see PEAR_ErrorStack::staticPushCallback() |
||
79 | * @access private |
||
80 | * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] |
||
81 | */ |
||
82 | $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); |
||
83 | |||
84 | /**#@+ |
||
85 | * One of four possible return values from the error Callback |
||
86 | * @see PEAR_ErrorStack::_errorCallback() |
||
87 | */ |
||
88 | /** |
||
89 | * If this is returned, then the error will be both pushed onto the stack |
||
90 | * and logged. |
||
91 | */ |
||
92 | define('PEAR_ERRORSTACK_PUSHANDLOG', 1); |
||
93 | /** |
||
94 | * If this is returned, then the error will only be pushed onto the stack, |
||
95 | * and not logged. |
||
96 | */ |
||
97 | define('PEAR_ERRORSTACK_PUSH', 2); |
||
98 | /** |
||
99 | * If this is returned, then the error will only be logged, but not pushed |
||
100 | * onto the error stack. |
||
101 | */ |
||
102 | define('PEAR_ERRORSTACK_LOG', 3); |
||
103 | /** |
||
104 | * If this is returned, then the error is completely ignored. |
||
105 | */ |
||
106 | define('PEAR_ERRORSTACK_IGNORE', 4); |
||
107 | /** |
||
108 | * If this is returned, then the error is logged and die() is called. |
||
109 | */ |
||
110 | define('PEAR_ERRORSTACK_DIE', 5); |
||
111 | /**#@-*/ |
||
112 | |||
113 | /** |
||
114 | * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in |
||
115 | * the singleton method. |
||
116 | */ |
||
117 | define('PEAR_ERRORSTACK_ERR_NONCLASS', 1); |
||
118 | |||
119 | /** |
||
120 | * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()} |
||
121 | * that has no __toString() method |
||
122 | */ |
||
123 | define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2); |
||
124 | /** |
||
125 | * Error Stack Implementation |
||
126 | * |
||
127 | * Usage: |
||
128 | * <code> |
||
129 | * // global error stack |
||
130 | * $global_stack = &PEAR_ErrorStack::singleton('MyPackage'); |
||
131 | * // local error stack |
||
132 | * $local_stack = new PEAR_ErrorStack('MyPackage'); |
||
133 | * </code> |
||
134 | * @author Greg Beaver <cellog@php.net> |
||
135 | * @version 1.7.2 |
||
136 | * @package PEAR_ErrorStack |
||
137 | * @category Debugging |
||
138 | * @copyright 2004-2008 Greg Beaver |
||
139 | * @license http://www.php.net/license/3_0.txt PHP License 3.0 |
||
140 | * @version CVS: $Id: ErrorStack.php,v 1.28 2008/01/03 20:26:35 cellog Exp $ |
||
141 | * @link http://pear.php.net/package/PEAR_ErrorStack |
||
142 | */ |
||
143 | class PEAR_ErrorStack { |
||
144 | /** |
||
145 | * Errors are stored in the order that they are pushed on the stack. |
||
146 | * @since 0.4alpha Errors are no longer organized by error level. |
||
147 | * This renders pop() nearly unusable, and levels could be more easily |
||
148 | * handled in a callback anyway |
||
149 | * @var array |
||
150 | * @access private |
||
151 | */ |
||
152 | var $_errors = array(); |
||
153 | |||
154 | /** |
||
155 | * Storage of errors by level. |
||
156 | * |
||
157 | * Allows easy retrieval and deletion of only errors from a particular level |
||
158 | * @since PEAR 1.4.0dev |
||
159 | * @var array |
||
160 | * @access private |
||
161 | */ |
||
162 | var $_errorsByLevel = array(); |
||
163 | |||
164 | /** |
||
165 | * Package name this error stack represents |
||
166 | * @var string |
||
167 | * @access protected |
||
168 | */ |
||
169 | var $_package; |
||
170 | |||
171 | /** |
||
172 | * Determines whether a PEAR_Error is thrown upon every error addition |
||
173 | * @var boolean |
||
174 | * @access private |
||
175 | */ |
||
176 | var $_compat = false; |
||
177 | |||
178 | /** |
||
179 | * If set to a valid callback, this will be used to generate the error |
||
180 | * message from the error code, otherwise the message passed in will be |
||
181 | * used |
||
182 | * @var false|string|array |
||
183 | * @access private |
||
184 | */ |
||
185 | var $_msgCallback = false; |
||
186 | |||
187 | /** |
||
188 | * If set to a valid callback, this will be used to generate the error |
||
189 | * context for an error. For PHP-related errors, this will be a file |
||
190 | * and line number as retrieved from debug_backtrace(), but can be |
||
191 | * customized for other purposes. The error might actually be in a separate |
||
192 | * configuration file, or in a database query. |
||
193 | * @var false|string|array |
||
194 | * @access protected |
||
195 | */ |
||
196 | var $_contextCallback = false; |
||
197 | |||
198 | /** |
||
199 | * If set to a valid callback, this will be called every time an error |
||
200 | * is pushed onto the stack. The return value will be used to determine |
||
201 | * whether to allow an error to be pushed or logged. |
||
202 | * |
||
203 | * The return value must be one an PEAR_ERRORSTACK_* constant |
||
204 | * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG |
||
205 | * @var false|string|array |
||
206 | * @access protected |
||
207 | */ |
||
208 | var $_errorCallback = array(); |
||
209 | |||
210 | /** |
||
211 | * PEAR::Log object for logging errors |
||
212 | * @var false|Log |
||
213 | * @access protected |
||
214 | */ |
||
215 | var $_logger = false; |
||
216 | |||
217 | /** |
||
218 | * Error messages - designed to be overridden |
||
219 | * @var array |
||
220 | * @abstract |
||
221 | */ |
||
222 | var $_errorMsgs = array(); |
||
223 | |||
224 | /** |
||
225 | * Set up a new error stack |
||
226 | * |
||
227 | * @param string $package name of the package this error stack represents |
||
228 | * @param callback $msgCallback callback used for error message generation |
||
229 | * @param callback $contextCallback callback used for context generation, |
||
230 | * defaults to {@link getFileLine()} |
||
231 | * @param boolean $throwPEAR_Error |
||
232 | */ |
||
233 | function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false, |
||
234 | $throwPEAR_Error = false) |
||
235 | { |
||
236 | $this->_package = $package; |
||
237 | $this->setMessageCallback($msgCallback); |
||
238 | $this->setContextCallback($contextCallback); |
||
239 | $this->_compat = $throwPEAR_Error; |
||
240 | } |
||
241 | |||
242 | /** |
||
243 | * Return a single error stack for this package. |
||
244 | * |
||
245 | * Note that all parameters are ignored if the stack for package $package |
||
246 | * has already been instantiated |
||
247 | * @param string $package name of the package this error stack represents |
||
248 | * @param callback $msgCallback callback used for error message generation |
||
249 | * @param callback $contextCallback callback used for context generation, |
||
250 | * defaults to {@link getFileLine()} |
||
251 | * @param boolean $throwPEAR_Error |
||
252 | * @param string $stackClass class to instantiate |
||
253 | * @static |
||
254 | * @return PEAR_ErrorStack |
||
255 | */ |
||
256 | function &singleton($package, $msgCallback = false, $contextCallback = false, |
||
257 | $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack') |
||
258 | { |
||
259 | if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { |
||
260 | return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; |
||
261 | } |
||
262 | if (!class_exists($stackClass)) { |
||
263 | if (function_exists('debug_backtrace')) { |
||
264 | $trace = debug_backtrace(); |
||
265 | } |
||
266 | PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS, |
||
267 | 'exception', array('stackclass' => $stackClass), |
||
268 | 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)', |
||
269 | false, $trace); |
||
270 | } |
||
271 | $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] = |
||
272 | new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error); |
||
273 | |||
274 | return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; |
||
275 | } |
||
276 | |||
277 | /** |
||
278 | * Internal error handler for PEAR_ErrorStack class |
||
279 | * |
||
280 | * Dies if the error is an exception (and would have died anyway) |
||
281 | * @access private |
||
282 | */ |
||
283 | function _handleError($err) |
||
284 | { |
||
285 | if ($err['level'] == 'exception') { |
||
286 | $message = $err['message']; |
||
287 | if (isset($_SERVER['REQUEST_URI'])) { |
||
288 | echo '<br />'; |
||
289 | } else { |
||
290 | echo "\n"; |
||
291 | } |
||
292 | var_dump($err['context']); |
||
293 | die($message); |
||
294 | } |
||
295 | } |
||
296 | |||
297 | /** |
||
298 | * Set up a PEAR::Log object for all error stacks that don't have one |
||
299 | * @param Log $log |
||
300 | * @static |
||
301 | */ |
||
302 | function setDefaultLogger(&$log) |
||
303 | { |
||
304 | if (is_object($log) && method_exists($log, 'log') ) { |
||
305 | $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; |
||
306 | } elseif (is_callable($log)) { |
||
307 | $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; |
||
308 | } |
||
309 | } |
||
310 | |||
311 | /** |
||
312 | * Set up a PEAR::Log object for this error stack |
||
313 | * @param Log $log |
||
314 | */ |
||
315 | function setLogger(&$log) |
||
316 | { |
||
317 | if (is_object($log) && method_exists($log, 'log') ) { |
||
318 | $this->_logger = &$log; |
||
319 | } elseif (is_callable($log)) { |
||
320 | $this->_logger = &$log; |
||
321 | } |
||
322 | } |
||
323 | |||
324 | /** |
||
325 | * Set an error code => error message mapping callback |
||
326 | * |
||
327 | * This method sets the callback that can be used to generate error |
||
328 | * messages for any instance |
||
329 | * @param array|string Callback function/method |
||
330 | */ |
||
331 | function setMessageCallback($msgCallback) |
||
332 | { |
||
333 | if (!$msgCallback) { |
||
334 | $this->_msgCallback = array(&$this, 'getErrorMessage'); |
||
335 | } else { |
||
336 | if (is_callable($msgCallback)) { |
||
337 | $this->_msgCallback = $msgCallback; |
||
338 | } |
||
339 | } |
||
340 | } |
||
341 | |||
342 | /** |
||
343 | * Get an error code => error message mapping callback |
||
344 | * |
||
345 | * This method returns the current callback that can be used to generate error |
||
346 | * messages |
||
347 | * @return array|string|false Callback function/method or false if none |
||
348 | */ |
||
349 | function getMessageCallback() |
||
350 | { |
||
351 | return $this->_msgCallback; |
||
352 | } |
||
353 | |||
354 | /** |
||
355 | * Sets a default callback to be used by all error stacks |
||
356 | * |
||
357 | * This method sets the callback that can be used to generate error |
||
358 | * messages for a singleton |
||
359 | * @param array|string Callback function/method |
||
360 | * @param string Package name, or false for all packages |
||
361 | * @static |
||
362 | */ |
||
363 | function setDefaultCallback($callback = false, $package = false) |
||
364 | { |
||
365 | if (!is_callable($callback)) { |
||
366 | $callback = false; |
||
367 | } |
||
368 | $package = $package ? $package : '*'; |
||
369 | $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback; |
||
370 | } |
||
371 | |||
372 | /** |
||
373 | * Set a callback that generates context information (location of error) for an error stack |
||
374 | * |
||
375 | * This method sets the callback that can be used to generate context |
||
376 | * information for an error. Passing in NULL will disable context generation |
||
377 | * and remove the expensive call to debug_backtrace() |
||
378 | * @param array|string|null Callback function/method |
||
379 | */ |
||
380 | function setContextCallback($contextCallback) |
||
381 | { |
||
382 | if ($contextCallback === null) { |
||
383 | return $this->_contextCallback = false; |
||
384 | } |
||
385 | if (!$contextCallback) { |
||
386 | $this->_contextCallback = array(&$this, 'getFileLine'); |
||
387 | } else { |
||
388 | if (is_callable($contextCallback)) { |
||
389 | $this->_contextCallback = $contextCallback; |
||
390 | } |
||
391 | } |
||
392 | } |
||
393 | |||
394 | /** |
||
395 | * Set an error Callback |
||
396 | * If set to a valid callback, this will be called every time an error |
||
397 | * is pushed onto the stack. The return value will be used to determine |
||
398 | * whether to allow an error to be pushed or logged. |
||
399 | * |
||
400 | * The return value must be one of the ERRORSTACK_* constants. |
||
401 | * |
||
402 | * This functionality can be used to emulate PEAR's pushErrorHandling, and |
||
403 | * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of |
||
404 | * the error stack or logging |
||
405 | * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG |
||
406 | * @see popCallback() |
||
407 | * @param string|array $cb |
||
408 | */ |
||
409 | function pushCallback($cb) |
||
410 | { |
||
411 | array_push($this->_errorCallback, $cb); |
||
412 | } |
||
413 | |||
414 | /** |
||
415 | * Remove a callback from the error callback stack |
||
416 | * @see pushCallback() |
||
417 | * @return array|string|false |
||
418 | */ |
||
419 | function popCallback() |
||
420 | { |
||
421 | if (!count($this->_errorCallback)) { |
||
422 | return false; |
||
423 | } |
||
424 | return array_pop($this->_errorCallback); |
||
425 | } |
||
426 | |||
427 | /** |
||
428 | * Set a temporary overriding error callback for every package error stack |
||
429 | * |
||
430 | * Use this to temporarily disable all existing callbacks (can be used |
||
431 | * to emulate the @ operator, for instance) |
||
432 | * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG |
||
433 | * @see staticPopCallback(), pushCallback() |
||
434 | * @param string|array $cb |
||
435 | * @static |
||
436 | */ |
||
437 | function staticPushCallback($cb) |
||
438 | { |
||
439 | array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb); |
||
440 | } |
||
441 | |||
442 | /** |
||
443 | * Remove a temporary overriding error callback |
||
444 | * @see staticPushCallback() |
||
445 | * @return array|string|false |
||
446 | * @static |
||
447 | */ |
||
448 | function staticPopCallback() |
||
449 | { |
||
450 | $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']); |
||
451 | if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) { |
||
452 | $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); |
||
453 | } |
||
454 | return $ret; |
||
455 | } |
||
456 | |||
457 | /** |
||
458 | * Add an error to the stack |
||
459 | * |
||
460 | * If the message generator exists, it is called with 2 parameters. |
||
461 | * - the current Error Stack object |
||
462 | * - an array that is in the same format as an error. Available indices |
||
463 | * are 'code', 'package', 'time', 'params', 'level', and 'context' |
||
464 | * |
||
465 | * Next, if the error should contain context information, this is |
||
466 | * handled by the context grabbing method. |
||
467 | * Finally, the error is pushed onto the proper error stack |
||
468 | * @param int $code Package-specific error code |
||
469 | * @param string $level Error level. This is NOT spell-checked |
||
470 | * @param array $params associative array of error parameters |
||
471 | * @param string $msg Error message, or a portion of it if the message |
||
472 | * is to be generated |
||
473 | * @param array $repackage If this error re-packages an error pushed by |
||
474 | * another package, place the array returned from |
||
475 | * {@link pop()} in this parameter |
||
476 | * @param array $backtrace Protected parameter: use this to pass in the |
||
477 | * {@link debug_backtrace()} that should be used |
||
478 | * to find error context |
||
479 | * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also |
||
480 | * thrown. If a PEAR_Error is returned, the userinfo |
||
481 | * property is set to the following array: |
||
482 | * |
||
483 | * <code> |
||
484 | * array( |
||
485 | * 'code' => $code, |
||
486 | * 'params' => $params, |
||
487 | * 'package' => $this->_package, |
||
488 | * 'level' => $level, |
||
489 | * 'time' => time(), |
||
490 | * 'context' => $context, |
||
491 | * 'message' => $msg, |
||
492 | * //['repackage' => $err] repackaged error array/Exception class |
||
493 | * ); |
||
494 | * </code> |
||
495 | * |
||
496 | * Normally, the previous array is returned. |
||
497 | */ |
||
498 | function push($code, $level = 'error', $params = array(), $msg = false, |
||
499 | $repackage = false, $backtrace = false) |
||
500 | { |
||
501 | $context = false; |
||
502 | // grab error context |
||
503 | if ($this->_contextCallback) { |
||
504 | if (!$backtrace) { |
||
505 | $backtrace = debug_backtrace(); |
||
506 | } |
||
507 | $context = call_user_func($this->_contextCallback, $code, $params, $backtrace); |
||
508 | } |
||
509 | |||
510 | // save error |
||
511 | $time = explode(' ', microtime()); |
||
512 | $time = $time[1] + $time[0]; |
||
513 | $err = array( |
||
514 | 'code' => $code, |
||
515 | 'params' => $params, |
||
516 | 'package' => $this->_package, |
||
517 | 'level' => $level, |
||
518 | 'time' => $time, |
||
519 | 'context' => $context, |
||
520 | 'message' => $msg, |
||
521 | ); |
||
522 | |||
523 | if ($repackage) { |
||
524 | $err['repackage'] = $repackage; |
||
525 | } |
||
526 | |||
527 | // set up the error message, if necessary |
||
528 | if ($this->_msgCallback) { |
||
529 | $msg = call_user_func_array($this->_msgCallback, |
||
530 | array(&$this, $err)); |
||
531 | $err['message'] = $msg; |
||
532 | } |
||
533 | $push = $log = true; |
||
534 | $die = false; |
||
535 | // try the overriding callback first |
||
536 | $callback = $this->staticPopCallback(); |
||
537 | if ($callback) { |
||
538 | $this->staticPushCallback($callback); |
||
539 | } |
||
540 | if (!is_callable($callback)) { |
||
541 | // try the local callback next |
||
542 | $callback = $this->popCallback(); |
||
543 | if (is_callable($callback)) { |
||
544 | $this->pushCallback($callback); |
||
545 | } else { |
||
546 | // try the default callback |
||
547 | $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ? |
||
548 | $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] : |
||
549 | $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*']; |
||
550 | } |
||
551 | } |
||
552 | if (is_callable($callback)) { |
||
553 | switch(call_user_func($callback, $err)){ |
||
554 | case PEAR_ERRORSTACK_IGNORE: |
||
555 | return $err; |
||
556 | break; |
||
557 | case PEAR_ERRORSTACK_PUSH: |
||
558 | $log = false; |
||
559 | break; |
||
560 | case PEAR_ERRORSTACK_LOG: |
||
561 | $push = false; |
||
562 | break; |
||
563 | case PEAR_ERRORSTACK_DIE: |
||
564 | $die = true; |
||
565 | break; |
||
566 | // anything else returned has the same effect as pushandlog |
||
567 | } |
||
568 | } |
||
569 | if ($push) { |
||
570 | array_unshift($this->_errors, $err); |
||
571 | if (!isset($this->_errorsByLevel[$err['level']])) { |
||
572 | $this->_errorsByLevel[$err['level']] = array(); |
||
573 | } |
||
574 | $this->_errorsByLevel[$err['level']][] = &$this->_errors[0]; |
||
575 | } |
||
576 | if ($log) { |
||
577 | if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) { |
||
578 | $this->_log($err); |
||
579 | } |
||
580 | } |
||
581 | if ($die) { |
||
582 | die(); |
||
583 | } |
||
584 | if ($this->_compat && $push) { |
||
585 | return $this->raiseError($msg, $code, null, null, $err); |
||
586 | } |
||
587 | return $err; |
||
588 | } |
||
589 | |||
590 | /** |
||
591 | * Static version of {@link push()} |
||
592 | * |
||
593 | * @param string $package Package name this error belongs to |
||
594 | * @param int $code Package-specific error code |
||
595 | * @param string $level Error level. This is NOT spell-checked |
||
596 | * @param array $params associative array of error parameters |
||
597 | * @param string $msg Error message, or a portion of it if the message |
||
598 | * is to be generated |
||
599 | * @param array $repackage If this error re-packages an error pushed by |
||
600 | * another package, place the array returned from |
||
601 | * {@link pop()} in this parameter |
||
602 | * @param array $backtrace Protected parameter: use this to pass in the |
||
603 | * {@link debug_backtrace()} that should be used |
||
604 | * to find error context |
||
605 | * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also |
||
606 | * thrown. see docs for {@link push()} |
||
607 | * @static |
||
608 | */ |
||
609 | function staticPush($package, $code, $level = 'error', $params = array(), |
||
610 | $msg = false, $repackage = false, $backtrace = false) |
||
611 | { |
||
612 | $s = &PEAR_ErrorStack::singleton($package); |
||
613 | if ($s->_contextCallback) { |
||
614 | if (!$backtrace) { |
||
615 | if (function_exists('debug_backtrace')) { |
||
616 | $backtrace = debug_backtrace(); |
||
617 | } |
||
618 | } |
||
619 | } |
||
620 | return $s->push($code, $level, $params, $msg, $repackage, $backtrace); |
||
621 | } |
||
622 | |||
623 | /** |
||
624 | * Log an error using PEAR::Log |
||
625 | * @param array $err Error array |
||
626 | * @param array $levels Error level => Log constant map |
||
627 | * @access protected |
||
628 | */ |
||
629 | function _log($err) |
||
630 | { |
||
631 | if ($this->_logger) { |
||
632 | $logger = &$this->_logger; |
||
633 | } else { |
||
634 | $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']; |
||
635 | } |
||
636 | if (is_a($logger, 'Log')) { |
||
637 | $levels = array( |
||
638 | 'exception' => PEAR_LOG_CRIT, |
||
639 | 'alert' => PEAR_LOG_ALERT, |
||
640 | 'critical' => PEAR_LOG_CRIT, |
||
641 | 'error' => PEAR_LOG_ERR, |
||
642 | 'warning' => PEAR_LOG_WARNING, |
||
643 | 'notice' => PEAR_LOG_NOTICE, |
||
644 | 'info' => PEAR_LOG_INFO, |
||
645 | 'debug' => PEAR_LOG_DEBUG); |
||
646 | if (isset($levels[$err['level']])) { |
||
647 | $level = $levels[$err['level']]; |
||
648 | } else { |
||
649 | $level = PEAR_LOG_INFO; |
||
650 | } |
||
651 | $logger->log($err['message'], $level, $err); |
||
652 | } else { // support non-standard logs |
||
653 | call_user_func($logger, $err); |
||
654 | } |
||
655 | } |
||
656 | |||
657 | |||
658 | /** |
||
659 | * Pop an error off of the error stack |
||
660 | * |
||
661 | * @return false|array |
||
662 | * @since 0.4alpha it is no longer possible to specify a specific error |
||
663 | * level to return - the last error pushed will be returned, instead |
||
664 | */ |
||
665 | function pop() |
||
666 | { |
||
667 | $err = @array_shift($this->_errors); |
||
668 | if (!is_null($err)) { |
||
669 | @array_pop($this->_errorsByLevel[$err['level']]); |
||
670 | if (!count($this->_errorsByLevel[$err['level']])) { |
||
671 | unset($this->_errorsByLevel[$err['level']]); |
||
672 | } |
||
673 | } |
||
674 | return $err; |
||
675 | } |
||
676 | |||
677 | /** |
||
678 | * Pop an error off of the error stack, static method |
||
679 | * |
||
680 | * @param string package name |
||
681 | * @return boolean |
||
682 | * @since PEAR1.5.0a1 |
||
683 | */ |
||
684 | function staticPop($package) |
||
685 | { |
||
686 | if ($package) { |
||
687 | if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { |
||
688 | return false; |
||
689 | } |
||
690 | return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop(); |
||
691 | } |
||
692 | } |
||
693 | |||
694 | /** |
||
695 | * Determine whether there are any errors on the stack |
||
696 | * @param string|array Level name. Use to determine if any errors |
||
697 | * of level (string), or levels (array) have been pushed |
||
698 | * @return boolean |
||
699 | */ |
||
700 | function hasErrors($level = false) |
||
701 | { |
||
702 | if ($level) { |
||
703 | return isset($this->_errorsByLevel[$level]); |
||
704 | } |
||
705 | return count($this->_errors); |
||
706 | } |
||
707 | |||
708 | /** |
||
709 | * Retrieve all errors since last purge |
||
710 | * |
||
711 | * @param boolean set in order to empty the error stack |
||
712 | * @param string level name, to return only errors of a particular severity |
||
713 | * @return array |
||
714 | */ |
||
715 | function getErrors($purge = false, $level = false) |
||
716 | { |
||
717 | if (!$purge) { |
||
718 | if ($level) { |
||
719 | if (!isset($this->_errorsByLevel[$level])) { |
||
720 | return array(); |
||
721 | } else { |
||
722 | return $this->_errorsByLevel[$level]; |
||
723 | } |
||
724 | } else { |
||
725 | return $this->_errors; |
||
726 | } |
||
727 | } |
||
728 | if ($level) { |
||
729 | $ret = $this->_errorsByLevel[$level]; |
||
730 | foreach ($this->_errorsByLevel[$level] as $i => $unused) { |
||
731 | // entries are references to the $_errors array |
||
732 | $this->_errorsByLevel[$level][$i] = false; |
||
733 | } |
||
734 | // array_filter removes all entries === false |
||
735 | $this->_errors = array_filter($this->_errors); |
||
736 | unset($this->_errorsByLevel[$level]); |
||
737 | return $ret; |
||
738 | } |
||
739 | $ret = $this->_errors; |
||
740 | $this->_errors = array(); |
||
741 | $this->_errorsByLevel = array(); |
||
742 | return $ret; |
||
743 | } |
||
744 | |||
745 | /** |
||
746 | * Determine whether there are any errors on a single error stack, or on any error stack |
||
747 | * |
||
748 | * The optional parameter can be used to test the existence of any errors without the need of |
||
749 | * singleton instantiation |
||
750 | * @param string|false Package name to check for errors |
||
751 | * @param string Level name to check for a particular severity |
||
752 | * @return boolean |
||
753 | * @static |
||
754 | */ |
||
755 | function staticHasErrors($package = false, $level = false) |
||
756 | { |
||
757 | if ($package) { |
||
758 | if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { |
||
759 | return false; |
||
760 | } |
||
761 | return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level); |
||
762 | } |
||
763 | foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { |
||
764 | if ($obj->hasErrors($level)) { |
||
765 | return true; |
||
766 | } |
||
767 | } |
||
768 | return false; |
||
769 | } |
||
770 | |||
771 | /** |
||
772 | * Get a list of all errors since last purge, organized by package |
||
773 | * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be |
||
774 | * @param boolean $purge Set to purge the error stack of existing errors |
||
775 | * @param string $level Set to a level name in order to retrieve only errors of a particular level |
||
776 | * @param boolean $merge Set to return a flat array, not organized by package |
||
777 | * @param array $sortfunc Function used to sort a merged array - default |
||
778 | * sorts by time, and should be good for most cases |
||
779 | * @static |
||
780 | * @return array |
||
781 | */ |
||
782 | function staticGetErrors($purge = false, $level = false, $merge = false, |
||
783 | $sortfunc = array('PEAR_ErrorStack', '_sortErrors')) |
||
784 | { |
||
785 | $ret = array(); |
||
786 | if (!is_callable($sortfunc)) { |
||
787 | $sortfunc = array('PEAR_ErrorStack', '_sortErrors'); |
||
788 | } |
||
789 | foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { |
||
790 | $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level); |
||
791 | if ($test) { |
||
792 | if ($merge) { |
||
793 | $ret = array_merge($ret, $test); |
||
794 | } else { |
||
795 | $ret[$package] = $test; |
||
796 | } |
||
797 | } |
||
798 | } |
||
799 | if ($merge) { |
||
800 | usort($ret, $sortfunc); |
||
801 | } |
||
802 | return $ret; |
||
803 | } |
||
804 | |||
805 | /** |
||
806 | * Error sorting function, sorts by time |
||
807 | * @access private |
||
808 | */ |
||
809 | function _sortErrors($a, $b) |
||
810 | { |
||
811 | if ($a['time'] == $b['time']) { |
||
812 | return 0; |
||
813 | } |
||
814 | if ($a['time'] < $b['time']) { |
||
815 | return 1; |
||
816 | } |
||
817 | return -1; |
||
818 | } |
||
819 | |||
820 | /** |
||
821 | * Standard file/line number/function/class context callback |
||
822 | * |
||
823 | * This function uses a backtrace generated from {@link debug_backtrace()} |
||
824 | * and so will not work at all in PHP < 4.3.0. The frame should |
||
825 | * reference the frame that contains the source of the error. |
||
826 | * @return array|false either array('file' => file, 'line' => line, |
||
827 | * 'function' => function name, 'class' => class name) or |
||
828 | * if this doesn't work, then false |
||
829 | * @param unused |
||
830 | * @param integer backtrace frame. |
||
831 | * @param array Results of debug_backtrace() |
||
832 | * @static |
||
833 | */ |
||
834 | function getFileLine($code, $params, $backtrace = null) |
||
835 | { |
||
836 | if ($backtrace === null) { |
||
837 | return false; |
||
838 | } |
||
839 | $frame = 0; |
||
840 | $functionframe = 1; |
||
841 | if (!isset($backtrace[1])) { |
||
842 | $functionframe = 0; |
||
843 | } else { |
||
844 | while (isset($backtrace[$functionframe]['function']) && |
||
845 | $backtrace[$functionframe]['function'] == 'eval' && |
||
846 | isset($backtrace[$functionframe + 1])) { |
||
847 | $functionframe++; |
||
848 | } |
||
849 | } |
||
850 | if (isset($backtrace[$frame])) { |
||
851 | if (!isset($backtrace[$frame]['file'])) { |
||
852 | $frame++; |
||
853 | } |
||
854 | $funcbacktrace = $backtrace[$functionframe]; |
||
855 | $filebacktrace = $backtrace[$frame]; |
||
856 | $ret = array('file' => $filebacktrace['file'], |
||
857 | 'line' => $filebacktrace['line']); |
||
858 | // rearrange for eval'd code or create function errors |
||
859 | if (strpos($filebacktrace['file'], '(') && |
||
860 | preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'], |
||
861 | $matches)) { |
||
862 | $ret['file'] = $matches[1]; |
||
863 | $ret['line'] = $matches[2] + 0; |
||
864 | } |
||
865 | if (isset($funcbacktrace['function']) && isset($backtrace[1])) { |
||
866 | if ($funcbacktrace['function'] != 'eval') { |
||
867 | if ($funcbacktrace['function'] == '__lambda_func') { |
||
868 | $ret['function'] = 'create_function() code'; |
||
869 | } else { |
||
870 | $ret['function'] = $funcbacktrace['function']; |
||
871 | } |
||
872 | } |
||
873 | } |
||
874 | if (isset($funcbacktrace['class']) && isset($backtrace[1])) { |
||
875 | $ret['class'] = $funcbacktrace['class']; |
||
876 | } |
||
877 | return $ret; |
||
878 | } |
||
879 | return false; |
||
880 | } |
||
881 | |||
882 | /** |
||
883 | * Standard error message generation callback |
||
884 | * |
||
885 | * This method may also be called by a custom error message generator |
||
886 | * to fill in template values from the params array, simply |
||
887 | * set the third parameter to the error message template string to use |
||
888 | * |
||
889 | * The special variable %__msg% is reserved: use it only to specify |
||
890 | * where a message passed in by the user should be placed in the template, |
||
891 | * like so: |
||
892 | * |
||
893 | * Error message: %msg% - internal error |
||
894 | * |
||
895 | * If the message passed like so: |
||
896 | * |
||
897 | * <code> |
||
898 | * $stack->push(ERROR_CODE, 'error', array(), 'server error 500'); |
||
899 | * </code> |
||
900 | * |
||
901 | * The returned error message will be "Error message: server error 500 - |
||
902 | * internal error" |
||
903 | * @param PEAR_ErrorStack |
||
904 | * @param array |
||
905 | * @param string|false Pre-generated error message template |
||
906 | * @static |
||
907 | * @return string |
||
908 | */ |
||
909 | function getErrorMessage(&$stack, $err, $template = false) |
||
910 | { |
||
911 | if ($template) { |
||
912 | $mainmsg = $template; |
||
913 | } else { |
||
914 | $mainmsg = $stack->getErrorMessageTemplate($err['code']); |
||
915 | } |
||
916 | $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg); |
||
917 | if (is_array($err['params']) && count($err['params'])) { |
||
918 | foreach ($err['params'] as $name => $val) { |
||
919 | if (is_array($val)) { |
||
920 | // @ is needed in case $val is a multi-dimensional array |
||
921 | $val = @implode(', ', $val); |
||
922 | } |
||
923 | if (is_object($val)) { |
||
924 | if (method_exists($val, '__toString')) { |
||
925 | $val = $val->__toString(); |
||
926 | } else { |
||
927 | PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING, |
||
928 | 'warning', array('obj' => get_class($val)), |
||
929 | 'object %obj% passed into getErrorMessage, but has no __toString() method'); |
||
930 | $val = 'Object'; |
||
931 | } |
||
932 | } |
||
933 | $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg); |
||
934 | } |
||
935 | } |
||
936 | return $mainmsg; |
||
937 | } |
||
938 | |||
939 | /** |
||
940 | * Standard Error Message Template generator from code |
||
941 | * @return string |
||
942 | */ |
||
943 | function getErrorMessageTemplate($code) |
||
944 | { |
||
945 | if (!isset($this->_errorMsgs[$code])) { |
||
946 | return '%__msg%'; |
||
947 | } |
||
948 | return $this->_errorMsgs[$code]; |
||
949 | } |
||
950 | |||
951 | /** |
||
952 | * Set the Error Message Template array |
||
953 | * |
||
954 | * The array format must be: |
||
955 | * <pre> |
||
956 | * array(error code => 'message template',...) |
||
957 | * </pre> |
||
958 | * |
||
959 | * Error message parameters passed into {@link push()} will be used as input |
||
960 | * for the error message. If the template is 'message %foo% was %bar%', and the |
||
961 | * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will |
||
962 | * be 'message one was six' |
||
963 | * @return string |
||
964 | */ |
||
965 | function setErrorMessageTemplate($template) |
||
966 | { |
||
967 | $this->_errorMsgs = $template; |
||
968 | } |
||
969 | |||
970 | |||
971 | /** |
||
972 | * emulate PEAR::raiseError() |
||
973 | * |
||
974 | * @return PEAR_Error |
||
975 | */ |
||
976 | function raiseError() |
||
977 | { |
||
978 | require_once 'PEAR.php'; |
||
979 | $args = func_get_args(); |
||
980 | return call_user_func_array(array('PEAR', 'raiseError'), $args); |
||
981 | } |
||
982 | } |
||
983 | $stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack'); |
||
984 | $stack->pushCallback(array('PEAR_ErrorStack', '_handleError')); |
||
985 | ?> |