PEAR   F
last analyzed

Complexity

Total Complexity 104

Size/Duplication

Total Lines 700
Duplicated Lines 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 251
dl 0
loc 700
rs 2
c 2
b 1
f 0
wmc 104

21 Methods

Rating   Name   Duplication   Size   Complexity  
B delExpect() 0 22 8
A PEAR() 0 3 1
A __callStatic() 0 11 2
A _throwError() 0 9 2
A getSourceDateEpoch() 0 12 3
A expectError() 0 8 2
B staticPushErrorHandling() 0 33 9
B __construct() 0 23 7
B staticPopErrorHandling() 0 34 9
B _setErrorHandling() 0 37 10
A __call() 0 11 2
A getStaticProperty() 0 12 3
A popExpect() 0 3 1
A _pushErrorHandling() 0 19 3
A _popErrorHandling() 0 12 2
A _checkDelExpect() 0 16 4
A isError() 0 13 4
D _raiseError() 0 58 19
B loadExtension() 0 25 9
A _PEAR() 0 4 2
A registerShutdownFunc() 0 9 2

How to fix   Complexity   

Complex Class

Complex classes like PEAR often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use PEAR, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * PEAR, the PHP Extension and Application Repository
4
 *
5
 * PEAR class and PEAR_Error class
6
 *
7
 * PHP versions 4 and 5
8
 *
9
 * @category   pear
10
 * @package    PEAR
11
 * @author     Sterling Hughes <[email protected]>
12
 * @author     Stig Bakken <[email protected]>
13
 * @author     Tomas V.V.Cox <[email protected]>
14
 * @author     Greg Beaver <[email protected]>
15
 * @copyright  1997-2010 The Authors
16
 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
17
 * @link       http://pear.php.net/package/PEAR
18
 * @since      File available since Release 0.1
19
 */
20
21
/**#@+
22
 * ERROR constants
23
 */
24
define('PEAR_ERROR_RETURN', 1);
25
define('PEAR_ERROR_PRINT', 2);
26
define('PEAR_ERROR_TRIGGER', 4);
27
define('PEAR_ERROR_DIE', 8);
28
define('PEAR_ERROR_CALLBACK', 16);
29
/**
30
 * WARNING: obsolete
31
 * @deprecated
32
 */
33
define('PEAR_ERROR_EXCEPTION', 32);
34
/**#@-*/
35
36
if ('WIN' == substr(PHP_OS, 0, 3)) {
37
    define('OS_WINDOWS', true);
38
    define('OS_UNIX', false);
39
    define('PEAR_OS', 'Windows');
40
} else {
41
    define('OS_WINDOWS', false);
42
    define('OS_UNIX', true);
43
    define('PEAR_OS', 'Unix'); // blatant assumption
44
}
45
46
$GLOBALS['_PEAR_default_error_mode']     = PEAR_ERROR_RETURN;
47
$GLOBALS['_PEAR_default_error_options']  = E_USER_NOTICE;
48
$GLOBALS['_PEAR_destructor_object_list'] = [];
49
$GLOBALS['_PEAR_shutdown_funcs']         = [];
50
$GLOBALS['_PEAR_error_handler_stack']    = [];
51
52
@ini_set('track_errors', true);
0 ignored issues
show
Bug introduced by
true of type true is incompatible with the type string expected by parameter $value of ini_set(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

52
@ini_set('track_errors', /** @scrutinizer ignore-type */ true);
Loading history...
53
54
/**
55
 * Base class for other PEAR classes.  Provides rudimentary
56
 * emulation of destructors.
57
 *
58
 * If you want a destructor in your class, inherit PEAR and make a
59
 * destructor method called _yourclassname (same name as the
60
 * constructor, but with a "_" prefix).  Also, in your constructor you
61
 * have to call the PEAR constructor: $this->PEAR();.
62
 * The destructor method will be called without parameters.  Note that
63
 * at in some SAPI implementations (such as Apache), any output during
64
 * the request shutdown (in which destructors are called) seems to be
65
 * discarded.  If you need to get any debug information from your
66
 * destructor, use error_log(), syslog() or something similar.
67
 *
68
 * IMPORTANT! To use the emulated destructors you need to create the
69
 * objects by reference: $obj =& new PEAR_child;
70
 *
71
 * @category    pear
72
 * @package     PEAR
73
 * @author      Stig Bakken <[email protected]>
74
 * @author      Tomas V.V. Cox <[email protected]>
75
 * @author      Greg Beaver <[email protected]>
76
 * @copyright   1997-2006 The PHP Group
77
 * @license     http://opensource.org/licenses/bsd-license.php New BSD License
78
 * @version     Release: 1.10.12
79
 * @link        http://pear.php.net/package/PEAR
80
 * @see         PEAR_Error
81
 * @since       Class available since PHP 4.0.2
82
 * @link        http://pear.php.net/manual/en/core.pear.php#core.pear.pear
83
 */
84
class PEAR
85
{
86
    /**
87
     * Whether to enable internal debug messages.
88
     *
89
     * @var     bool
90
     * @access  private
91
     */
92
    public $_debug = false;
93
    /**
94
     * Default error mode for this object.
95
     *
96
     * @var     int
97
     * @access  private
98
     */
99
    public $_default_error_mode = null;
100
    /**
101
     * Default error options used for this object when error mode
102
     * is PEAR_ERROR_TRIGGER.
103
     *
104
     * @var     int
105
     * @access  private
106
     */
107
    public $_default_error_options = null;
108
    /**
109
     * Default error handler (callback) for this object, if error mode is
110
     * PEAR_ERROR_CALLBACK.
111
     *
112
     * @var     string
113
     * @access  private
114
     */
115
    public $_default_error_handler = '';
116
    /**
117
     * Which class to use for error objects.
118
     *
119
     * @var     string
120
     * @access  private
121
     */
122
    public $_error_class = 'PEAR_Error';
123
    /**
124
     * An array of expected errors.
125
     *
126
     * @var     array
127
     * @access  private
128
     */
129
    public $_expected_errors = [];
130
    /**
131
     * List of methods that can be called both statically and non-statically.
132
     * @var array
133
     */
134
    protected static $bivalentMethods = [
135
        'setErrorHandling'  => true,
136
        'raiseError'        => true,
137
        'throwError'        => true,
138
        'pushErrorHandling' => true,
139
        'popErrorHandling'  => true,
140
    ];
141
142
    /**
143
     * Constructor.  Registers this object in
144
     * $_PEAR_destructor_object_list for destructor emulation if a
145
     * destructor object exists.
146
     *
147
     * @param string $error_class (optional) which class to use for
148
     *                            error objects, defaults to PEAR_Error.
149
     * @access public
150
     * @return void
151
     */
152
    public function __construct($error_class = null)
153
    {
154
        $classname = strtolower(get_class($this));
155
        if ($this->_debug) {
156
            print "PEAR constructor called, class=$classname\n";
157
        }
158
159
        if (null !== $error_class) {
160
            $this->_error_class = $error_class;
161
        }
162
163
        while ($classname && strcasecmp($classname, 'pear')) {
164
            $destructor = "_$classname";
165
            if (method_exists($this, $destructor)) {
166
                global $_PEAR_destructor_object_list;
167
                $_PEAR_destructor_object_list[] = $this;
168
                if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
169
                    register_shutdown_function('_PEAR_call_destructors');
170
                    $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
171
                }
172
                break;
173
            } else {
174
                $classname = get_parent_class($classname);
175
            }
176
        }
177
    }
178
179
    /**
180
     * Only here for backwards compatibility.
181
     * E.g. Archive_Tar calls $this->PEAR() in its constructor.
182
     *
183
     * @param string $error_class Which class to use for error objects,
184
     *                            defaults to PEAR_Error.
185
     */
186
    public function PEAR($error_class = null)
187
    {
188
        self::__construct($error_class);
0 ignored issues
show
Bug Best Practice introduced by
The method PEAR::__construct() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

188
        self::/** @scrutinizer ignore-call */ 
189
              __construct($error_class);
Loading history...
189
    }
190
191
    /**
192
     * Destructor (the emulated type of...).  Does nothing right now,
193
     * but is included for forward compatibility, so subclass
194
     * destructors should always call it.
195
     *
196
     * See the note in the class desciption about output from
197
     * destructors.
198
     *
199
     * @access public
200
     * @return void
201
     */
202
    public function _PEAR()
203
    {
204
        if ($this->_debug) {
205
            printf("PEAR destructor called, class=%s\n", strtolower(get_class($this)));
206
        }
207
    }
208
209
    public function __call($method, $arguments)
210
    {
211
        if (!isset(self::$bivalentMethods[$method])) {
212
            trigger_error(
213
                'Call to undefined method PEAR::' . $method . '()',
214
                E_USER_ERROR
215
            );
216
        }
217
        return call_user_func_array(
218
            [get_class(), '_' . $method],
219
            array_merge([$this], $arguments)
220
        );
221
    }
222
223
    public static function __callStatic($method, $arguments)
224
    {
225
        if (!isset(self::$bivalentMethods[$method])) {
226
            trigger_error(
227
                'Call to undefined method PEAR::' . $method . '()',
228
                E_USER_ERROR
229
            );
230
        }
231
        return call_user_func_array(
232
            [get_class(), '_' . $method],
233
            array_merge([null], $arguments)
234
        );
235
    }
236
237
    /**
238
     * If you have a class that's mostly/entirely static, and you need static
239
     * properties, you can use this method to simulate them. Eg. in your method(s)
240
     * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar');
241
     * You MUST use a reference, or they will not persist!
242
     *
243
     * @param string $class The calling classname, to prevent clashes
244
     * @param string $var   The variable to retrieve.
245
     * @return mixed   A reference to the variable. If not set it will be
246
     *                      auto initialised to NULL.
247
     */
248
    public static function &getStaticProperty($class, $var)
249
    {
250
        static $properties;
251
        if (!isset($properties[$class])) {
252
            $properties[$class] = [];
253
        }
254
255
        if (!array_key_exists($var, $properties[$class])) {
256
            $properties[$class][$var] = null;
257
        }
258
259
        return $properties[$class][$var];
260
    }
261
262
    /**
263
     * Use this function to register a shutdown method for static
264
     * classes.
265
     *
266
     * @param mixed $func The function name (or array of class/method) to call
267
     * @param mixed $args The arguments to pass to the function
268
     *
269
     * @return void
270
     */
271
    public static function registerShutdownFunc($func, $args = [])
272
    {
273
        // if we are called statically, there is a potential
274
        // that no shutdown func is registered.  Bug #6445
275
        if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
276
            register_shutdown_function('_PEAR_call_destructors');
277
            $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
278
        }
279
        $GLOBALS['_PEAR_shutdown_funcs'][] = [$func, $args];
280
    }
281
282
    /**
283
     * Tell whether a value is a PEAR error.
284
     *
285
     * @param mixed $data     the value to test
286
     * @param int   $code     if $data is an error object, return true
287
     *                        only if $code is a string and
288
     *                        $obj->getMessage() == $code or
289
     *                        $code is an integer and $obj->getCode() == $code
290
     *
291
     * @return  bool    true if parameter is an error
292
     */
293
    public static function isError($data, $code = null)
294
    {
295
        if (!is_a($data, 'PEAR_Error')) {
296
            return false;
297
        }
298
299
        if (null === $code) {
300
            return true;
301
        } elseif (is_string($code)) {
0 ignored issues
show
introduced by
The condition is_string($code) is always false.
Loading history...
302
            return $data->getMessage() == $code;
303
        }
304
305
        return $data->getCode() == $code;
306
    }
307
308
    /**
309
     * Sets how errors generated by this object should be handled.
310
     * Can be invoked both in objects and statically.  If called
311
     * statically, setErrorHandling sets the default behaviour for all
312
     * PEAR objects.  If called in an object, setErrorHandling sets
313
     * the default behaviour for that object.
314
     *
315
     * @param object $object
316
     *        Object the method was called on (non-static mode)
317
     *
318
     * @param int    $mode
319
     *        One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
320
     *        PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
321
     *        PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION.
322
     *
323
     * @param mixed  $options
324
     *        When $mode is PEAR_ERROR_TRIGGER, this is the error level (one
325
     *        of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
326
     *
327
     *        When $mode is PEAR_ERROR_CALLBACK, this parameter is expected
328
     *        to be the callback function or method.  A callback
329
     *        function is a string with the name of the function, a
330
     *        callback method is an array of two elements: the element
331
     *        at index 0 is the object, and the element at index 1 is
332
     *        the name of the method to call in the object.
333
     *
334
     *        When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is
335
     *        a printf format string used when printing the error
336
     *        message.
337
     *
338
     * @access public
339
     * @return void
340
     * @see    PEAR_ERROR_RETURN
341
     * @see    PEAR_ERROR_PRINT
342
     * @see    PEAR_ERROR_TRIGGER
343
     * @see    PEAR_ERROR_DIE
344
     * @see    PEAR_ERROR_CALLBACK
345
     * @see    PEAR_ERROR_EXCEPTION
346
     *
347
     * @since  PHP 4.0.5
348
     */
349
    protected static function _setErrorHandling(
350
        $object,
351
        $mode = null,
352
        $options = null
353
    ) {
354
        if (null !== $object) {
355
            $setmode    = &$object->_default_error_mode;
356
            $setoptions = &$object->_default_error_options;
357
        } else {
358
            $setmode    = &$GLOBALS['_PEAR_default_error_mode'];
359
            $setoptions = &$GLOBALS['_PEAR_default_error_options'];
360
        }
361
362
        switch ($mode) {
363
            case PEAR_ERROR_EXCEPTION:
0 ignored issues
show
Deprecated Code introduced by
The constant PEAR_ERROR_EXCEPTION has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

363
            case /** @scrutinizer ignore-deprecated */ PEAR_ERROR_EXCEPTION:
Loading history...
364
            case PEAR_ERROR_RETURN:
365
            case PEAR_ERROR_PRINT:
366
            case PEAR_ERROR_TRIGGER:
367
            case PEAR_ERROR_DIE:
368
            case null:
369
                $setmode    = $mode;
370
                $setoptions = $options;
371
                break;
372
373
            case PEAR_ERROR_CALLBACK:
374
                $setmode = $mode;
375
                // class/object method callback
376
                if (is_callable($options)) {
377
                    $setoptions = $options;
378
                } else {
379
                    trigger_error('invalid error callback', E_USER_WARNING);
380
                }
381
                break;
382
383
            default:
384
                trigger_error('invalid error mode', E_USER_WARNING);
385
                break;
386
        }
387
    }
388
389
    /**
390
     * This method is used to tell which errors you expect to get.
391
     * Expected errors are always returned with error mode
392
     * PEAR_ERROR_RETURN.  Expected error codes are stored in a stack,
393
     * and this method pushes a new element onto it.  The list of
394
     * expected errors are in effect until they are popped off the
395
     * stack with the popExpect() method.
396
     *
397
     * Note that this method can not be called statically
398
     *
399
     * @param mixed $code a single error code or an array of error codes to expect
400
     *
401
     * @return int     the new depth of the "expected errors" stack
402
     * @access public
403
     */
404
    public function expectError($code = '*')
405
    {
406
        if (is_array($code)) {
407
            array_push($this->_expected_errors, $code);
408
        } else {
409
            array_push($this->_expected_errors, [$code]);
410
        }
411
        return count($this->_expected_errors);
412
    }
413
414
    /**
415
     * This method pops one element off the expected error codes
416
     * stack.
417
     *
418
     * @return array   the list of error codes that were popped
419
     */
420
    public function popExpect()
421
    {
422
        return array_pop($this->_expected_errors);
423
    }
424
425
    /**
426
     * This method checks unsets an error code if available
427
     *
428
     * @param mixed error code
429
     * @return bool true if the error code was unset, false otherwise
430
     * @access private
431
     * @since  PHP 4.3.0
432
     */
433
    public function _checkDelExpect($error_code)
434
    {
435
        $deleted = false;
436
        foreach ($this->_expected_errors as $key => $error_array) {
437
            if (in_array($error_code, $error_array)) {
438
                unset($this->_expected_errors[$key][array_search($error_code, $error_array)]);
439
                $deleted = true;
440
            }
441
442
            // clean up empty arrays
443
            if (0 == count($this->_expected_errors[$key])) {
444
                unset($this->_expected_errors[$key]);
445
            }
446
        }
447
448
        return $deleted;
449
    }
450
451
    /**
452
     * This method deletes all occurrences of the specified element from
453
     * the expected error codes stack.
454
     *
455
     * @param mixed $error_code error code that should be deleted
456
     * @return mixed list of error codes that were deleted or error
457
     * @access public
458
     * @since  PHP 4.3.0
459
     */
460
    public function delExpect($error_code)
461
    {
462
        $deleted = false;
463
        if ((is_array($error_code) && (0 != count($error_code)))) {
464
            // $error_code is a non-empty array here; we walk through it trying
465
            // to unset all values
466
            foreach ($error_code as $key => $error) {
467
                $deleted = $this->_checkDelExpect($error) ? true : false;
468
            }
469
470
            return $deleted ? true : self::raiseError('The expected error you submitted does not exist'); // IMPROVE ME
0 ignored issues
show
Bug introduced by
The method raiseError() does not exist on PEAR. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

470
            return $deleted ? true : self::/** @scrutinizer ignore-call */ raiseError('The expected error you submitted does not exist'); // IMPROVE ME
Loading history...
471
        } elseif (!empty($error_code)) {
472
            // $error_code comes alone, trying to unset it
473
            if ($this->_checkDelExpect($error_code)) {
474
                return true;
475
            }
476
477
            return self::raiseError('The expected error you submitted does not exist'); // IMPROVE ME
478
        }
479
480
        // $error_code is empty
481
        return self::raiseError('The expected error you submitted is empty'); // IMPROVE ME
482
    }
483
484
    /**
485
     * This method is a wrapper that returns an instance of the
486
     * configured error class with this object's default error
487
     * handling applied.  If the $mode and $options parameters are not
488
     * specified, the object's defaults are used.
489
     *
490
     * @param mixed  $message     a text error message or a PEAR error object
491
     *
492
     * @param int    $code        a numeric error code (it is up to your class
493
     *                            to define these if you want to use codes)
494
     *
495
     * @param int    $mode        One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
496
     *                            PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
497
     *                            PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION.
498
     *
499
     * @param mixed  $options     If $mode is PEAR_ERROR_TRIGGER, this parameter
500
     *                            specifies the PHP-internal error level (one of
501
     *                            E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
502
     *                            If $mode is PEAR_ERROR_CALLBACK, this
503
     *                            parameter specifies the callback function or
504
     *                            method.  In other error modes this parameter
505
     *                            is ignored.
506
     *
507
     * @param string $userinfo    If you need to pass along for example debug
508
     *                            information, this parameter is meant for that.
509
     *
510
     * @param string $error_class The returned error object will be
511
     *                            instantiated from this class, if specified.
512
     *
513
     * @param bool   $skipmsg     If true, raiseError will only pass error codes,
514
     *                            the error message parameter will be dropped.
515
     *
516
     * @return object   a PEAR error object
517
     * @see   PEAR::setErrorHandling
518
     * @since PHP 4.0.5
519
     */
520
    protected static function _raiseError(
521
        $object,
522
        $message = null,
523
        $code = null,
524
        $mode = null,
525
        $options = null,
526
        $userinfo = null,
527
        $error_class = null,
528
        $skipmsg = false
529
    ) {
530
        // The error is yet a PEAR error object
531
        if (is_object($message)) {
532
            $code                          = $message->getCode();
533
            $userinfo                      = $message->getUserInfo();
534
            $error_class                   = $message->getType();
535
            $message->error_message_prefix = '';
536
            $message                       = $message->getMessage();
537
        }
538
539
        if (null !== $object
540
            && isset($object->_expected_errors)
541
            && count($object->_expected_errors) > 0
542
            && count($exp = end($object->_expected_errors))) {
543
            if ('*' === $exp[0]
544
                || (is_int(reset($exp)) && in_array($code, $exp))
545
                || (is_string(reset($exp)) && in_array($message, $exp))) {
546
                $mode = PEAR_ERROR_RETURN;
547
            }
548
        }
549
550
        // No mode given, try global ones
551
        if (null === $mode) {
552
            // Class error handler
553
            if (null !== $object && isset($object->_default_error_mode)) {
554
                $mode    = $object->_default_error_mode;
555
                $options = $object->_default_error_options;
556
                // Global error handler
557
            } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) {
558
                $mode    = $GLOBALS['_PEAR_default_error_mode'];
559
                $options = $GLOBALS['_PEAR_default_error_options'];
560
            }
561
        }
562
563
        if (null !== $error_class) {
564
            $ec = $error_class;
565
        } elseif (null !== $object && isset($object->_error_class)) {
566
            $ec = $object->_error_class;
567
        } else {
568
            $ec = 'PEAR_Error';
569
        }
570
571
        if ($skipmsg) {
572
            $a = new $ec($code, $mode, $options, $userinfo);
573
        } else {
574
            $a = new $ec($message, $code, $mode, $options, $userinfo);
575
        }
576
577
        return $a;
578
    }
579
580
    /**
581
     * Simpler form of raiseError with fewer options.  In most cases
582
     * message, code and userinfo are enough.
583
     *
584
     * @param mixed  $message  a text error message or a PEAR error object
585
     *
586
     * @param int    $code     a numeric error code (it is up to your class
587
     *                         to define these if you want to use codes)
588
     *
589
     * @param string $userinfo If you need to pass along for example debug
590
     *                         information, this parameter is meant for that.
591
     *
592
     * @return object   a PEAR error object
593
     * @see PEAR::raiseError
594
     */
595
    protected static function _throwError($object, $message = null, $code = null, $userinfo = null)
596
    {
597
        if (null !== $object) {
598
            $a = $object->raiseError($message, $code, null, null, $userinfo);
599
            return $a;
600
        }
601
602
        $a = self::raiseError($message, $code, null, null, $userinfo);
603
        return $a;
604
    }
605
606
    public static function staticPushErrorHandling($mode, $options = null)
607
    {
608
        $stack       = &$GLOBALS['_PEAR_error_handler_stack'];
609
        $def_mode    = &$GLOBALS['_PEAR_default_error_mode'];
610
        $def_options = &$GLOBALS['_PEAR_default_error_options'];
611
        $stack[]     = [$def_mode, $def_options];
612
        switch ($mode) {
613
            case PEAR_ERROR_EXCEPTION:
0 ignored issues
show
Deprecated Code introduced by
The constant PEAR_ERROR_EXCEPTION has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

613
            case /** @scrutinizer ignore-deprecated */ PEAR_ERROR_EXCEPTION:
Loading history...
614
            case PEAR_ERROR_RETURN:
615
            case PEAR_ERROR_PRINT:
616
            case PEAR_ERROR_TRIGGER:
617
            case PEAR_ERROR_DIE:
618
            case null:
619
                $def_mode    = $mode;
620
                $def_options = $options;
621
                break;
622
623
            case PEAR_ERROR_CALLBACK:
624
                $def_mode = $mode;
625
                // class/object method callback
626
                if (is_callable($options)) {
627
                    $def_options = $options;
628
                } else {
629
                    trigger_error('invalid error callback', E_USER_WARNING);
630
                }
631
                break;
632
633
            default:
634
                trigger_error('invalid error mode', E_USER_WARNING);
635
                break;
636
        }
637
        $stack[] = [$mode, $options];
638
        return true;
639
    }
640
641
    public static function staticPopErrorHandling()
642
    {
643
        $stack      = &$GLOBALS['_PEAR_error_handler_stack'];
644
        $setmode    = &$GLOBALS['_PEAR_default_error_mode'];
645
        $setoptions = &$GLOBALS['_PEAR_default_error_options'];
646
        array_pop($stack);
647
        [$mode, $options] = $stack[count($stack) - 1];
648
        array_pop($stack);
649
        switch ($mode) {
650
            case PEAR_ERROR_EXCEPTION:
0 ignored issues
show
Deprecated Code introduced by
The constant PEAR_ERROR_EXCEPTION has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

650
            case /** @scrutinizer ignore-deprecated */ PEAR_ERROR_EXCEPTION:
Loading history...
651
            case PEAR_ERROR_RETURN:
652
            case PEAR_ERROR_PRINT:
653
            case PEAR_ERROR_TRIGGER:
654
            case PEAR_ERROR_DIE:
655
            case null:
656
                $setmode    = $mode;
657
                $setoptions = $options;
658
                break;
659
660
            case PEAR_ERROR_CALLBACK:
661
                $setmode = $mode;
662
                // class/object method callback
663
                if (is_callable($options)) {
664
                    $setoptions = $options;
665
                } else {
666
                    trigger_error('invalid error callback', E_USER_WARNING);
667
                }
668
                break;
669
670
            default:
671
                trigger_error('invalid error mode', E_USER_WARNING);
672
                break;
673
        }
674
        return true;
675
    }
676
677
    /**
678
     * Push a new error handler on top of the error handler options stack. With this
679
     * you can easily override the actual error handler for some code and restore
680
     * it later with popErrorHandling.
681
     *
682
     * @param mixed $mode    (same as setErrorHandling)
683
     * @param mixed $options (same as setErrorHandling)
684
     *
685
     * @return bool Always true
686
     *
687
     * @see PEAR::setErrorHandling
688
     */
689
    protected static function _pushErrorHandling($object, $mode, $options = null)
690
    {
691
        $stack = &$GLOBALS['_PEAR_error_handler_stack'];
692
        if (null !== $object) {
693
            $def_mode    = &$object->_default_error_mode;
694
            $def_options = &$object->_default_error_options;
695
        } else {
696
            $def_mode    = &$GLOBALS['_PEAR_default_error_mode'];
697
            $def_options = &$GLOBALS['_PEAR_default_error_options'];
698
        }
699
        $stack[] = [$def_mode, $def_options];
700
701
        if (null !== $object) {
702
            $object->setErrorHandling($mode, $options);
703
        } else {
704
            self::setErrorHandling($mode, $options);
0 ignored issues
show
Bug introduced by
The method setErrorHandling() does not exist on PEAR. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

704
            self::/** @scrutinizer ignore-call */ 
705
                  setErrorHandling($mode, $options);
Loading history...
705
        }
706
        $stack[] = [$mode, $options];
707
        return true;
708
    }
709
710
    /**
711
     * Pop the last error handler used
712
     *
713
     * @return bool Always true
714
     *
715
     * @see PEAR::pushErrorHandling
716
     */
717
    protected static function _popErrorHandling($object)
718
    {
719
        $stack = &$GLOBALS['_PEAR_error_handler_stack'];
720
        array_pop($stack);
721
        [$mode, $options] = $stack[count($stack) - 1];
722
        array_pop($stack);
723
        if (null !== $object) {
724
            $object->setErrorHandling($mode, $options);
725
        } else {
726
            self::setErrorHandling($mode, $options);
727
        }
728
        return true;
729
    }
730
731
    /**
732
     * OS independent PHP extension load. Remember to take care
733
     * on the correct extension name for case sensitive OSes.
734
     *
735
     * @param string $ext The extension name
736
     * @return bool Success or not on the dl() call
737
     */
738
    public static function loadExtension($ext)
739
    {
740
        if (extension_loaded($ext)) {
741
            return true;
742
        }
743
744
        // if either returns true dl() will produce a FATAL error, stop that
745
        if (false === function_exists('dl')
746
            || 1 != ini_get('enable_dl')) {
747
            return false;
748
        }
749
750
        if (OS_WINDOWS) {
751
            $suffix = '.dll';
752
        } elseif (PHP_OS == 'HP-UX') {
753
            $suffix = '.sl';
754
        } elseif (PHP_OS == 'AIX') {
755
            $suffix = '.a';
756
        } elseif (PHP_OS == 'OSX') {
757
            $suffix = '.bundle';
758
        } else {
759
            $suffix = '.so';
760
        }
761
762
        return @dl('php_' . $ext . $suffix) || @dl($ext . $suffix);
763
    }
764
765
    /**
766
     * Get SOURCE_DATE_EPOCH environment variable
767
     * See https://reproducible-builds.org/specs/source-date-epoch/
768
     *
769
     * @return int
770
     * @access public
771
     */
772
    public static function getSourceDateEpoch()
773
    {
774
        if ($source_date_epoch = getenv('SOURCE_DATE_EPOCH')) {
775
            if (preg_match('/^\d+$/', $source_date_epoch)) {
776
                return (int)$source_date_epoch;
777
            } else {
778
                //  "If the value is malformed, the build process SHOULD exit with a non-zero error code."
779
                self::raiseError("Invalid SOURCE_DATE_EPOCH: $source_date_epoch");
780
                exit(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
781
            }
782
        } else {
783
            return time();
784
        }
785
    }
786
}
787
788
function _PEAR_call_destructors()
789
{
790
    global $_PEAR_destructor_object_list;
791
    if (is_array($_PEAR_destructor_object_list)
792
        && count($_PEAR_destructor_object_list)) {
793
        reset($_PEAR_destructor_object_list);
794
795
        $destructLifoExists = PEAR::getStaticProperty('PEAR', 'destructlifo');
796
797
        if ($destructLifoExists) {
798
            $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list);
799
        }
800
801
        foreach ($_PEAR_destructor_object_list as $k => $objref) {
802
            $classname = get_class($objref);
803
            while ($classname) {
804
                $destructor = "_$classname";
805
                if (method_exists($objref, $destructor)) {
806
                    $objref->$destructor();
807
                    break;
808
                } else {
809
                    $classname = get_parent_class($classname);
810
                }
811
            }
812
        }
813
        // Empty the object list to ensure that destructors are
814
        // not called more than once.
815
        $_PEAR_destructor_object_list = [];
816
    }
817
818
    // Now call the shutdown functions
819
    if (isset($GLOBALS['_PEAR_shutdown_funcs'])
820
        && is_array($GLOBALS['_PEAR_shutdown_funcs'])
821
        && !empty($GLOBALS['_PEAR_shutdown_funcs'])) {
822
        foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) {
823
            call_user_func_array($value[0], $value[1]);
824
        }
825
    }
826
}
827
828
/**
829
 * Standard PEAR error class for PHP 4
830
 *
831
 * This class is supserseded by {@link PEAR_Exception} in PHP 5
832
 *
833
 * @category   pear
834
 * @package    PEAR
835
 * @author     Stig Bakken <[email protected]>
836
 * @author     Tomas V.V. Cox <[email protected]>
837
 * @author     Gregory Beaver <[email protected]>
838
 * @copyright  1997-2006 The PHP Group
839
 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
840
 * @version    Release: 1.10.12
841
 * @link       http://pear.php.net/manual/en/core.pear.pear-error.php
842
 * @see        PEAR::raiseError(), PEAR::throwError()
843
 * @since      Class available since PHP 4.0.2
844
 */
845
class PEAR_Error
846
{
847
    public $error_message_prefix = '';
848
    public $mode                 = PEAR_ERROR_RETURN;
849
    public $level                = E_USER_NOTICE;
850
    public $code                 = -1;
851
    public $message              = '';
852
    public $userinfo             = '';
853
    public $backtrace            = null;
854
855
    /**
856
     * PEAR_Error constructor
857
     *
858
     * @param string $message  message
859
     *
860
     * @param int    $code     (optional) error code
861
     *
862
     * @param int    $mode     (optional) error mode, one of: PEAR_ERROR_RETURN,
863
     *                         PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER,
864
     *                         PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION
865
     *
866
     * @param mixed  $options  (optional) error level, _OR_ in the case of
867
     *                         PEAR_ERROR_CALLBACK, the callback function or object/method
868
     *                         tuple.
869
     *
870
     * @param string $userinfo (optional) additional user/debug info
871
     *
872
     * @access public
873
     *
874
     */
875
    public function __construct(
876
        $message = 'unknown error',
877
        $code = null,
878
        $mode = null,
879
        $options = null,
880
        $userinfo = null
881
    ) {
882
        if (null === $mode) {
883
            $mode = PEAR_ERROR_RETURN;
884
        }
885
        $this->message  = $message;
886
        $this->code     = $code;
887
        $this->mode     = $mode;
888
        $this->userinfo = $userinfo;
889
890
        $skiptrace = PEAR::getStaticProperty('PEAR_Error', 'skiptrace');
891
892
        if (!$skiptrace) {
893
            $this->backtrace = debug_backtrace();
894
            if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) {
895
                unset($this->backtrace[0]['object']);
896
            }
897
        }
898
899
        if ($mode & PEAR_ERROR_CALLBACK) {
900
            $this->level    = E_USER_NOTICE;
901
            $this->callback = $options;
0 ignored issues
show
Bug Best Practice introduced by
The property callback does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
902
        } else {
903
            if (null === $options) {
904
                $options = E_USER_NOTICE;
905
            }
906
907
            $this->level    = $options;
908
            $this->callback = null;
909
        }
910
911
        if ($this->mode & PEAR_ERROR_PRINT) {
912
            if (null === $options || is_int($options)) {
913
                $format = '%s';
914
            } else {
915
                $format = $options;
916
            }
917
918
            printf($format, $this->getMessage());
919
        }
920
921
        if ($this->mode & PEAR_ERROR_TRIGGER) {
922
            trigger_error($this->getMessage(), $this->level);
923
        }
924
925
        if ($this->mode & PEAR_ERROR_DIE) {
926
            $msg = $this->getMessage();
927
            if (null === $options || is_int($options)) {
928
                $format = '%s';
929
                if ("\n" != substr($msg, -1)) {
930
                    $msg .= "\n";
931
                }
932
            } else {
933
                $format = $options;
934
            }
935
            printf($format, $msg);
936
            exit($code);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
937
        }
938
939
        if ($this->mode & PEAR_ERROR_CALLBACK && is_callable($this->callback)) {
940
            call_user_func($this->callback, $this);
0 ignored issues
show
Bug introduced by
It seems like $this->callback can also be of type null; however, parameter $callback of call_user_func() does only seem to accept callable, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

940
            call_user_func(/** @scrutinizer ignore-type */ $this->callback, $this);
Loading history...
941
        }
942
943
        if ($this->mode & PEAR_ERROR_EXCEPTION) {
0 ignored issues
show
Deprecated Code introduced by
The constant PEAR_ERROR_EXCEPTION has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

943
        if ($this->mode & /** @scrutinizer ignore-deprecated */ PEAR_ERROR_EXCEPTION) {
Loading history...
944
            trigger_error('PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions', E_USER_WARNING);
945
            eval('$e = new Exception($this->message, $this->code);throw($e);');
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
946
        }
947
    }
948
949
    /**
950
     * Only here for backwards compatibility.
951
     *
952
     * Class "Cache_Error" still uses it, among others.
953
     *
954
     * @param string $message  Message
955
     * @param int    $code     Error code
956
     * @param int    $mode     Error mode
957
     * @param mixed  $options  See __construct()
958
     * @param string $userinfo Additional user/debug info
959
     */
960
    public function PEAR_Error(
961
        $message = 'unknown error',
962
        $code = null,
963
        $mode = null,
964
        $options = null,
965
        $userinfo = null
966
    ) {
967
        self::__construct($message, $code, $mode, $options, $userinfo);
0 ignored issues
show
Bug Best Practice introduced by
The method PEAR_Error::__construct() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

967
        self::/** @scrutinizer ignore-call */ 
968
              __construct($message, $code, $mode, $options, $userinfo);
Loading history...
968
    }
969
970
    /**
971
     * Get the error mode from an error object.
972
     *
973
     * @return int error mode
974
     * @access public
975
     */
976
    public function getMode()
977
    {
978
        return $this->mode;
979
    }
980
981
    /**
982
     * Get the callback function/method from an error object.
983
     *
984
     * @return mixed callback function or object/method array
985
     * @access public
986
     */
987
    public function getCallback()
988
    {
989
        return $this->callback;
990
    }
991
992
    /**
993
     * Get the error message from an error object.
994
     *
995
     * @return  string  full error message
996
     * @access public
997
     */
998
    public function getMessage()
999
    {
1000
        return ($this->error_message_prefix . $this->message);
1001
    }
1002
1003
    /**
1004
     * Get error code from an error object
1005
     *
1006
     * @return int error code
1007
     * @access public
1008
     */
1009
    public function getCode()
1010
    {
1011
        return $this->code;
1012
    }
1013
1014
    /**
1015
     * Get the name of this error/exception.
1016
     *
1017
     * @return string error/exception name (type)
1018
     * @access public
1019
     */
1020
    public function getType()
1021
    {
1022
        return get_class($this);
1023
    }
1024
1025
    /**
1026
     * Get additional user-supplied information.
1027
     *
1028
     * @return string user-supplied information
1029
     * @access public
1030
     */
1031
    public function getUserInfo()
1032
    {
1033
        return $this->userinfo;
1034
    }
1035
1036
    /**
1037
     * Get additional debug information supplied by the application.
1038
     *
1039
     * @return string debug information
1040
     * @access public
1041
     */
1042
    public function getDebugInfo()
1043
    {
1044
        return $this->getUserInfo();
1045
    }
1046
1047
    /**
1048
     * Get the call backtrace from where the error was generated.
1049
     * Supported with PHP 4.3.0 or newer.
1050
     *
1051
     * @param int $frame (optional) what frame to fetch
1052
     * @return array Backtrace, or NULL if not available.
1053
     * @access public
1054
     */
1055
    public function getBacktrace($frame = null)
1056
    {
1057
        if (defined('PEAR_IGNORE_BACKTRACE')) {
1058
            return null;
1059
        }
1060
        if (null === $frame) {
1061
            return $this->backtrace;
1062
        }
1063
        return $this->backtrace[$frame];
1064
    }
1065
1066
    public function addUserInfo($info)
1067
    {
1068
        if (empty($this->userinfo)) {
1069
            $this->userinfo = $info;
1070
        } else {
1071
            $this->userinfo .= " ** $info";
1072
        }
1073
    }
1074
1075
    public function __toString()
1076
    {
1077
        return $this->getMessage();
1078
    }
1079
1080
    /**
1081
     * Make a string representation of this object.
1082
     *
1083
     * @return string a string with an object summary
1084
     * @access public
1085
     */
1086
    public function toString()
1087
    {
1088
        $modes  = [];
1089
        $levels = [
1090
            E_USER_NOTICE  => 'notice',
1091
            E_USER_WARNING => 'warning',
1092
            E_USER_ERROR   => 'error',
1093
        ];
1094
        if ($this->mode & PEAR_ERROR_CALLBACK) {
1095
            if (is_array($this->callback)) {
1096
                $callback = (is_object($this->callback[0]) ? strtolower(get_class($this->callback[0])) : $this->callback[0]) . '::' . $this->callback[1];
1097
            } else {
1098
                $callback = $this->callback;
1099
            }
1100
            return sprintf(
1101
                '[%s: message="%s" code=%d mode=callback ' . 'callback=%s prefix="%s" info="%s"]',
1102
                strtolower(get_class($this)),
1103
                $this->message,
1104
                $this->code,
1105
                $callback,
1106
                $this->error_message_prefix,
1107
                $this->userinfo
1108
            );
1109
        }
1110
        if ($this->mode & PEAR_ERROR_PRINT) {
1111
            $modes[] = 'print';
1112
        }
1113
        if ($this->mode & PEAR_ERROR_TRIGGER) {
1114
            $modes[] = 'trigger';
1115
        }
1116
        if ($this->mode & PEAR_ERROR_DIE) {
1117
            $modes[] = 'die';
1118
        }
1119
        if ($this->mode & PEAR_ERROR_RETURN) {
1120
            $modes[] = 'return';
1121
        }
1122
        return sprintf(
1123
            '[%s: message="%s" code=%d mode=%s level=%s ' . 'prefix="%s" info="%s"]',
1124
            strtolower(get_class($this)),
1125
            $this->message,
1126
            $this->code,
1127
            implode('|', $modes),
1128
            $levels[$this->level],
1129
            $this->error_message_prefix,
1130
            $this->userinfo
1131
        );
1132
    }
1133
}
1134
1135
/*
1136
 * Local Variables:
1137
 * mode: php
1138
 * tab-width: 4
1139
 * c-basic-offset: 4
1140
 * End:
1141
 */
1142