Subversion Repositories Applications.gtt

Rev

Rev 94 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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