PEAR_Error::getMessage()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
//
3
// +----------------------------------------------------------------------+
4
// | PEAR, the PHP Extension and Application Repository                   |
5
// +----------------------------------------------------------------------+
6
// | Copyright (c) 1997-2004 The PHP Group                                |
7
// +----------------------------------------------------------------------+
8
// | This source file is subject to version 2.0 of the PHP license,       |
9
// | that is bundled with this package in the file LICENSE, and is        |
10
// | available through the world-wide-web at the following url:           |
11
// | https://www.php.net/license/3_0.txt.                                  |
12
// | If you did not receive a copy of the PHP license and are unable to   |
13
// | obtain it through the world-wide-web, please send a note to          |
14
// | [email protected] so we can mail you a copy immediately.               |
15
// +----------------------------------------------------------------------+
16
// | Authors: Sterling Hughes <[email protected]>                          |
17
// |          Stig Bakken <[email protected]>                                   |
18
// |          Tomas V.V.Cox <[email protected]>                             |
19
// +----------------------------------------------------------------------+
20
//
21
//
22
23
define('PEAR_ERROR_RETURN', 1);
24
define('PEAR_ERROR_PRINT', 2);
25
define('PEAR_ERROR_TRIGGER', 4);
26
define('PEAR_ERROR_DIE', 8);
27
define('PEAR_ERROR_CALLBACK', 16);
28
/**
29
 * WARNING: obsolete
30
 * @deprecated
31
 */
32
define('PEAR_ERROR_EXCEPTION', 32);
33
define(
34
    'PEAR_ZE2',
35
    function_exists('version_compare')
36
    && version_compare(zend_version(), '2-dev', 'ge')
37
);
38
39
if (0 === mb_strpos(PHP_OS, 'WIN')) {
40
    define('OS_WINDOWS', true);
41
    define('OS_UNIX', false);
42
    define('PEAR_OS', 'Windows');
43
} else {
44
    define('OS_WINDOWS', false);
45
    define('OS_UNIX', true);
46
    define('PEAR_OS', 'Unix'); // blatant assumption
47
}
48
49
// instant backwards compatibility
50
if (!defined('PATH_SEPARATOR')) {
51
    if (OS_WINDOWS) {
52
        define('PATH_SEPARATOR', ';');
53
    } else {
54
        define('PATH_SEPARATOR', ':');
55
    }
56
}
57
58
$GLOBALS['_PEAR_default_error_mode']     = PEAR_ERROR_RETURN;
59
$GLOBALS['_PEAR_default_error_options']  = E_USER_NOTICE;
60
$GLOBALS['_PEAR_destructor_object_list'] = [];
61
$GLOBALS['_PEAR_shutdown_funcs']         = [];
62
$GLOBALS['_PEAR_errorHandler_stack']     = [];
63
64
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

64
ini_set('track_errors', /** @scrutinizer ignore-type */ true);
Loading history...
65
66
/**
67
 * Base class for other PEAR classes.  Provides rudimentary
68
 * emulation of destructors.
69
 *
70
 * If you want a destructor in your class, inherit PEAR and make a
71
 * destructor method called _yourclassname (same name as the
72
 * constructor, but with a "_" prefix).  Also, in your constructor you
73
 * have to call the PEAR constructor: $this->PEAR();.
74
 * The destructor method will be called without parameters.  Note that
75
 * at in some SAPI implementations (such as Apache), any output during
76
 * the request shutdown (in which destructors are called) seems to be
77
 * discarded.  If you need to get any debug information from your
78
 * destructor, use error_log(), syslog() or something similar.
79
 *
80
 * IMPORTANT! To use the emulated destructors you need to create the
81
 * objects by reference: $obj = new PEAR_child;
82
 *
83
 * @since  PHP 4.0.2
84
 * @author Stig Bakken <[email protected]>
85
 * @see    https://pear.php.net/manual/
86
 */
87
class PEAR
88
{
89
    // {{{ properties
90
    /**
91
     * Whether to enable internal debug messages.
92
     *
93
     * @var bool
94
     */
95
    public $_debug = false;
96
    /**
97
     * Default error mode for this object.
98
     *
99
     * @var int
100
     */
101
    public $_default_error_mode = null;
102
    /**
103
     * Default error options used for this object when error mode
104
     * is PEAR_ERROR_TRIGGER.
105
     *
106
     * @var int
107
     */
108
    public $_default_error_options = null;
109
    /**
110
     * Default error handler (callback) for this object, if error mode is
111
     * PEAR_ERROR_CALLBACK.
112
     *
113
     * @var string
114
     */
115
    public $_default_errorHandler = '';
116
    /**
117
     * Which class to use for error objects.
118
     *
119
     * @var string
120
     */
121
    public $_error_class = 'PEAR_Error';
122
    /**
123
     * An array of expected errors.
124
     *
125
     * @var array
126
     */
127
    public $_expected_errors = [];
128
    // }}}
129
130
    // {{{ constructor
131
132
    /**
133
     * Constructor.  Registers this object in
134
     * $_PEAR_destructor_object_list for destructor emulation if a
135
     * destructor object exists.
136
     *
137
     * @param null $error_class    (optional) which class to use for
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $error_class is correct as it would always require null to be passed?
Loading history...
138
     *                             error objects, defaults to PEAR_Error.
139
     */
140
    public function __construct($error_class = null)
141
    {
142
        $classname = get_class($this);
143
        if ($this->_debug) {
144
            print "PEAR constructor called, class=$classname\n";
145
        }
146
        if (null !== $error_class) {
0 ignored issues
show
introduced by
The condition null !== $error_class is always false.
Loading history...
147
            $this->_error_class = $error_class;
148
        }
149
        while ($classname) {
150
            $destructor = "_$classname";
151
            if (method_exists($this, $destructor)) {
152
                global $_PEAR_destructor_object_list;
153
                $_PEAR_destructor_object_list[] = &$this;
154
                break;
155
            }
156
            $classname = get_parent_class($classname);
157
        }
158
    }
159
160
    // }}}
161
    // {{{ destructor
162
163
    /**
164
     * Destructor (the emulated type of...).  Does nothing right now,
165
     * but is included for forward compatibility, so subclass
166
     * destructors should always call it.
167
     *
168
     * See the note in the class desciption about output from
169
     * destructors.
170
     */
171
    public function _PEAR(): void
172
    {
173
        if ($this->_debug) {
174
            printf("PEAR destructor called, class=%s\n", get_class($this));
175
        }
176
    }
177
178
    // }}}
179
    // {{{ getStaticProperty()
180
181
    /**
182
     * If you have a class that's mostly/entirely static, and you need static
183
     * properties, you can use this method to simulate them. Eg. in your method(s)
184
     * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar');
185
     * You MUST use a reference, or they will not persist!
186
     *
187
     * @param string $class  The calling classname, to prevent clashes
188
     * @param string $var    The variable to retrieve.
189
     * @return mixed  A reference to the variable. If not set it will be
190
     *                       auto initialised to NULL.
191
     */
192
    public function &getStaticProperty(string $class, string $var)
193
    {
194
        static $properties;
195
196
        return $properties[$class][$var];
197
    }
198
199
    // }}}
200
    // {{{ registerShutdownFunc()
201
202
    /**
203
     * Use this function to register a shutdown method for static
204
     * classes.
205
     *
206
     * @param mixed $func The function name (or array of class/method) to call
207
     * @param mixed $args The arguments to pass to the function
208
     */
209
    public function registerShutdownFunc($func, $args = []): void
210
    {
211
        $GLOBALS['_PEAR_shutdown_funcs'][] = [$func, $args];
212
    }
213
214
    // }}}
215
    // {{{ isError()
216
217
    /**
218
     * Tell whether a value is a PEAR error.
219
     *
220
     * @param mixed $data  the value to test
221
     * @param null  $code  if $data is an error object, return true
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $code is correct as it would always require null to be passed?
Loading history...
222
     *                     only if $code is a string and
223
     *                     $obj->getMessage() == $code or
224
     *                     $code is an integer and $obj->getCode() == $code
225
     * @return bool  true if parameter is an error
226
     */
227
    public function isError($data, $code = null): bool
228
    {
229
        if (is_a($data, 'PEAR_Error')) {
230
            if (null === $code) {
0 ignored issues
show
introduced by
The condition null === $code is always true.
Loading history...
231
                return true;
232
            } elseif (is_string($code)) {
233
                return $data->getMessage() == $code;
234
            }
235
236
            return $data->getCode() == $code;
237
        }
238
239
        return false;
240
    }
241
242
    // }}}
243
    // {{{ setErrorHandling()
244
245
    /**
246
     * Sets how errors generated by this object should be handled.
247
     * Can be invoked both in objects and statically.  If called
248
     * statically, setErrorHandling sets the default behaviour for all
249
     * PEAR objects.  If called in an object, setErrorHandling sets
250
     * the default behaviour for that object.
251
     *
252
     * @param null  $mode
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $mode is correct as it would always require null to be passed?
Loading history...
253
     *                       One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
254
     *                       PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
255
     *                       PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION.
256
     *
257
     * @param mixed $options
258
     *                       When $mode is PEAR_ERROR_TRIGGER, this is the error level (one
259
     *                       of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
260
     *
261
     *        When $mode is PEAR_ERROR_CALLBACK, this parameter is expected
262
     *        to be the callback function or method.  A callback
263
     *        function is a string with the name of the function, a
264
     *        callback method is an array of two elements: the element
265
     *        at index 0 is the object, and the element at index 1 is
266
     *        the name of the method to call in the object.
267
     *
268
     *        When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is
269
     *        a printf format string used when printing the error
270
     *        message.
271
     *
272
     * @see    PEAR_ERROR_RETURN
273
     * @see    PEAR_ERROR_PRINT
274
     * @see    PEAR_ERROR_TRIGGER
275
     * @see    PEAR_ERROR_DIE
276
     * @see    PEAR_ERROR_CALLBACK
277
     * @see    PEAR_ERROR_EXCEPTION
278
     *
279
     * @since  PHP 4.0.5
280
     */
281
    public function setErrorHandling($mode = null, $options = null): void
282
    {
283
        if (isset($this) && $this instanceof self) {
284
            $setmode    = &$this->_default_error_mode;
285
            $setoptions = &$this->_default_error_options;
286
        } else {
287
            $setmode    = &$GLOBALS['_PEAR_default_error_mode'];
288
            $setoptions = &$GLOBALS['_PEAR_default_error_options'];
289
        }
290
291
        switch ($mode) {
292
            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

292
            case /** @scrutinizer ignore-deprecated */ PEAR_ERROR_EXCEPTION:
Loading history...
293
            case PEAR_ERROR_RETURN:
294
            case PEAR_ERROR_PRINT:
295
            case PEAR_ERROR_TRIGGER:
296
            case PEAR_ERROR_DIE:
297
            case null:
298
                $setmode    = $mode;
299
                $setoptions = $options;
300
                break;
301
            case PEAR_ERROR_CALLBACK:
302
                $setmode = $mode;
303
                // class/object method callback
304
                if (is_callable($options)) {
305
                    $setoptions = $options;
306
                } else {
307
                    trigger_error('invalid error callback', E_USER_WARNING);
308
                }
309
                break;
310
            default:
311
                trigger_error('invalid error mode', E_USER_WARNING);
312
                break;
313
        }
314
    }
315
316
    // }}}
317
    // {{{ expectError()
318
319
    /**
320
     * This method is used to tell which errors you expect to get.
321
     * Expected errors are always returned with error mode
322
     * PEAR_ERROR_RETURN.  Expected error codes are stored in a stack,
323
     * and this method pushes a new element onto it.  The list of
324
     * expected errors are in effect until they are popped off the
325
     * stack with the popExpect() method.
326
     *
327
     * Note that this method can not be called statically
328
     *
329
     * @param mixed $code a single error code or an array of error codes to expect
330
     *
331
     * @return int the new depth of the "expected errors" stack
332
     */
333
    public function expectError($code = '*'): int
334
    {
335
        if (is_array($code)) {
336
            $this->_expected_errors[] = $code;
337
        } else {
338
            $this->_expected_errors[] = [$code];
339
        }
340
341
        return count($this->_expected_errors);
342
    }
343
344
    // }}}
345
    // {{{ popExpect()
346
347
    /**
348
     * This method pops one element off the expected error codes
349
     * stack.
350
     *
351
     * @return array the list of error codes that were popped
352
     */
353
    public function popExpect(): array
354
    {
355
        return array_pop($this->_expected_errors);
356
    }
357
358
    // }}}
359
    // {{{ _checkDelExpect()
360
361
    /**
362
     * This method checks unsets an error code if available
363
     *
364
     * @param mixed $error_code
365
     * @return bool true if the error code was unset, false otherwise
366
     * @since  PHP 4.3.0
367
     */
368
    public function _checkDelExpect($error_code): bool
369
    {
370
        $deleted = false;
371
372
        foreach ($this->_expected_errors as $key => $error_array) {
373
            if (in_array($error_code, $error_array, true)) {
374
                unset($this->_expected_errors[$key][array_search($error_code, $error_array, true)]);
375
                $deleted = true;
376
            }
377
378
            // clean up empty arrays
379
            if (0 == count($this->_expected_errors[$key])) {
380
                unset($this->_expected_errors[$key]);
381
            }
382
        }
383
384
        return $deleted;
385
    }
386
387
    // }}}
388
    // {{{ delExpect()
389
390
    /**
391
     * This method deletes all occurences of the specified element from
392
     * the expected error codes stack.
393
     *
394
     * @param mixed $error_code error code that should be deleted
395
     * @return bool|\PEAR_Error list of error codes that were deleted or error
396
     * @since  PHP 4.3.0
397
     */
398
    public function delExpect($error_code)
399
    {
400
        $deleted = false;
401
402
        if (is_array($error_code) && (0 != count($error_code))) {
403
            // $error_code is a non-empty array here;
404
            // we walk through it trying to unset all
405
            // values
406
            foreach ($error_code as $key => $error) {
407
                if ($this->_checkDelExpect($error)) {
408
                    $deleted = true;
409
                } else {
410
                    $deleted = false;
411
                }
412
            }
413
414
            return $deleted ? true : self::raiseError('The expected error you submitted does not exist'); // IMPROVE ME
0 ignored issues
show
Bug Best Practice introduced by
The method PEAR::raiseError() 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

414
            return $deleted ? true : self::/** @scrutinizer ignore-call */ raiseError('The expected error you submitted does not exist'); // IMPROVE ME
Loading history...
415
        } elseif (!empty($error_code)) {
416
            // $error_code comes alone, trying to unset it
417
            if ($this->_checkDelExpect($error_code)) {
418
                return true;
419
            }
420
421
            return self::raiseError('The expected error you submitted does not exist'); // IMPROVE ME
422
        }
423
        // $error_code is empty
424
        return self::raiseError('The expected error you submitted is empty'); // IMPROVE ME
425
    }
426
427
    // }}}
428
    // {{{ raiseError()
429
430
    /**
431
     * This method is a wrapper that returns an instance of the
432
     * configured error class with this object's default error
433
     * handling applied.  If the $mode and $options parameters are not
434
     * specified, the object's defaults are used.
435
     *
436
     * @param mixed $message      a text error message or a PEAR error object
437
     *
438
     * @param null  $code         a numeric error code (it is up to your class
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $code is correct as it would always require null to be passed?
Loading history...
439
     *                            to define these if you want to use codes)
440
     *
441
     * @param null  $mode         One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $mode is correct as it would always require null to be passed?
Loading history...
442
     *                            PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
443
     *                            PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION.
444
     *
445
     * @param mixed $options      If $mode is PEAR_ERROR_TRIGGER, this parameter
446
     *                            specifies the PHP-internal error level (one of
447
     *                            E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
448
     *                            If $mode is PEAR_ERROR_CALLBACK, this
449
     *                            parameter specifies the callback function or
450
     *                            method.  In other error modes this parameter
451
     *                            is ignored.
452
     *
453
     * @param null  $userinfo     If you need to pass along for example debug
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $userinfo is correct as it would always require null to be passed?
Loading history...
454
     *                            information, this parameter is meant for that.
455
     *
456
     * @param null  $error_class  The returned error object will be
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $error_class is correct as it would always require null to be passed?
Loading history...
457
     *                            instantiated from this class, if specified.
458
     *
459
     * @param bool  $skipmsg      If true, raiseError will only pass error codes,
460
     *                            the error message parameter will be dropped.
461
     *
462
     * @return PEAR_Error a PEAR error object
463
     * @see    PEAR::setErrorHandling
464
     * @since  PHP 4.0.5
465
     */
466
    public function raiseError(
467
        $message = null, $code = null, $mode = null, $options = null, $userinfo = null, $error_class = null, bool $skipmsg = false
468
    ): PEAR_Error {
469
        // The error is yet a PEAR error object
470
        if (is_object($message)) {
471
            $code                          = $message->getCode();
472
            $userinfo                      = $message->getUserInfo();
473
            $error_class                   = $message->getType();
474
            $message->error_message_prefix = '';
475
            $message                       = $message->getMessage();
476
        }
477
478
        if (isset($this) && isset($this->_expected_errors) && count($this->_expected_errors) > 0 && count($exp = end($this->_expected_errors))) {
479
            if ('*' === $exp[0]
480
                || (is_int(reset($exp)) && in_array($code, $exp, true))
481
                || (is_string(reset($exp)) && in_array($message, $exp, true))) {
482
                $mode = PEAR_ERROR_RETURN;
483
            }
484
        }
485
        // No mode given, try global ones
486
        if (null === $mode) {
487
            // Class error handler
488
            if (isset($this) && isset($this->_default_error_mode)) {
489
                $mode    = $this->_default_error_mode;
490
                $options = $this->_default_error_options;
491
                // Global error handler
492
            } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) {
493
                $mode    = $GLOBALS['_PEAR_default_error_mode'];
494
                $options = $GLOBALS['_PEAR_default_error_options'];
495
            }
496
        }
497
498
        if (null !== $error_class) {
499
            $ec = $error_class;
500
        } elseif (isset($this) && isset($this->_error_class)) {
501
            $ec = $this->_error_class;
502
        } else {
503
            $ec = 'PEAR_Error';
504
        }
505
        if ($skipmsg) {
506
            return new $ec($code, $mode, $options, $userinfo);
507
        }
508
509
        return new $ec($message, $code, $mode, $options, $userinfo);
510
    }
511
512
    // }}}
513
    // {{{ throwError()
514
515
    /**
516
     * Simpler form of raiseError with fewer options.  In most cases
517
     * message, code and userinfo are enough.
518
     *
519
     * @param null $message
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $message is correct as it would always require null to be passed?
Loading history...
520
     *
521
     * @param null $code
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $code is correct as it would always require null to be passed?
Loading history...
522
     * @param null $userinfo
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $userinfo is correct as it would always require null to be passed?
Loading history...
523
     * @return object
524
     */
525
    public function throwError(
526
        $message = null, $code = null, $userinfo = null
527
    ) {
528
        if (isset($this) && $this instanceof self) {
529
            return $this->raiseError($message, $code, null, null, $userinfo);
530
        }
531
532
        return self::raiseError($message, $code, null, null, $userinfo);
0 ignored issues
show
Bug Best Practice introduced by
The method PEAR::raiseError() 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

532
        return self::/** @scrutinizer ignore-call */ raiseError($message, $code, null, null, $userinfo);
Loading history...
533
    }
534
535
    // }}}
536
    // {{{ pushErrorHandling()
537
538
    /**
539
     * Push a new error handler on top of the error handler options stack. With this
540
     * you can easily override the actual error handler for some code and restore
541
     * it later with popErrorHandling.
542
     *
543
     * @param mixed $mode    (same as setErrorHandling)
544
     * @param mixed $options (same as setErrorHandling)
545
     *
546
     * @return bool Always true
547
     *
548
     * @see PEAR::setErrorHandling
549
     */
550
    public function pushErrorHandling($mode, $options = null): bool
551
    {
552
        $stack = &$GLOBALS['_PEAR_errorHandler_stack'];
553
        if (isset($this) && $this instanceof self) {
554
            $def_mode    = &$this->_default_error_mode;
555
            $def_options = &$this->_default_error_options;
556
        } else {
557
            $def_mode    = &$GLOBALS['_PEAR_default_error_mode'];
558
            $def_options = &$GLOBALS['_PEAR_default_error_options'];
559
        }
560
        $stack[] = [$def_mode, $def_options];
561
562
        if (isset($this) && $this instanceof self) {
563
            $this->setErrorHandling($mode, $options);
564
        } else {
565
            self::setErrorHandling($mode, $options);
0 ignored issues
show
Bug Best Practice introduced by
The method PEAR::setErrorHandling() 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

565
            self::/** @scrutinizer ignore-call */ 
566
                  setErrorHandling($mode, $options);
Loading history...
566
        }
567
        $stack[] = [$mode, $options];
568
569
        return true;
570
    }
571
572
    // }}}
573
    // {{{ popErrorHandling()
574
575
    /**
576
     * Pop the last error handler used
577
     *
578
     * @return bool Always true
579
     *
580
     * @see PEAR::pushErrorHandling
581
     */
582
    public function popErrorHandling(): bool
583
    {
584
        $stack = &$GLOBALS['_PEAR_errorHandler_stack'];
585
        array_pop($stack);
586
        [$mode, $options] = $stack[count($stack) - 1];
587
        array_pop($stack);
588
        if (isset($this) && $this instanceof self) {
589
            $this->setErrorHandling($mode, $options);
590
        } else {
591
            self::setErrorHandling($mode, $options);
0 ignored issues
show
Bug Best Practice introduced by
The method PEAR::setErrorHandling() 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

591
            self::/** @scrutinizer ignore-call */ 
592
                  setErrorHandling($mode, $options);
Loading history...
592
        }
593
594
        return true;
595
    }
596
597
    // }}}
598
    // {{{ loadExtension()
599
600
    /**
601
     * OS independant PHP extension load. Remember to take care
602
     * on the correct extension name for case sensitive OSes.
603
     *
604
     * @param string $ext The extension name
605
     * @return bool   Success or not on the dl() call
606
     */
607
    public function loadExtension(string $ext): bool
608
    {
609
        if (!extension_loaded($ext)) {
610
            // if either returns true dl() will produce a FATAL error, stop that
611
            if ((1 != ini_get('enable_dl')) || (1 == ini_get('safe_mode'))) {
612
                return false;
613
            }
614
            if (OS_WINDOWS) {
615
                $suffix = '.dll';
616
            } elseif (PHP_OS === 'HP-UX') {
617
                $suffix = '.sl';
618
            } elseif (PHP_OS === 'AIX') {
619
                $suffix = '.a';
620
            } elseif (PHP_OS === 'OSX') {
621
                $suffix = '.bundle';
622
            } else {
623
                $suffix = '.so';
624
            }
625
626
            return @dl('php_' . $ext . $suffix) || @dl($ext . $suffix);
627
        }
628
629
        return true;
630
    }
631
    // }}}
632
}
633
634
// {{{ _PEAR_call_destructors()
635
636
function _PEAR_call_destructors(): void
637
{
638
    global $_PEAR_destructor_object_list;
639
    if (is_array($_PEAR_destructor_object_list)
640
        && count($_PEAR_destructor_object_list)) {
641
        reset($_PEAR_destructor_object_list);
642
        foreach ($_PEAR_destructor_object_list as $objref) {
643
            $classname = get_class($objref);
644
            while ($classname) {
645
                $destructor = "_$classname";
646
                if (method_exists($objref, $destructor)) {
647
                    $objref->$destructor();
648
                    break;
649
                }
650
                $classname = get_parent_class($classname);
651
            }
652
        }
653
        // Empty the object list to ensure that destructors are
654
        // not called more than once.
655
        $_PEAR_destructor_object_list = [];
656
    }
657
658
    // Now call the shutdown functions
659
    if (is_array($GLOBALS['_PEAR_shutdown_funcs']) && !empty($GLOBALS['_PEAR_shutdown_funcs'])) {
660
        foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) {
661
            call_user_func_array($value[0], $value[1]);
662
        }
663
    }
664
}
665
666
// }}}
667
668
/**
669
 * Class PEAR_Error
670
 */
671
class PEAR_Error
672
{
673
    // {{{ properties
674
675
    public $error_message_prefix = '';
676
    public $mode                 = PEAR_ERROR_RETURN;
677
    public $level                = E_USER_NOTICE;
678
    public $code                 = -1;
679
    public $message              = '';
680
    public $userinfo             = '';
681
    public $backtrace            = null;
682
    // }}}
683
    // {{{ constructor
684
685
    /**
686
     * PEAR_Error constructor
687
     *
688
     * @param string $message  message
689
     *
690
     * @param null   $code     (optional) error code
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $code is correct as it would always require null to be passed?
Loading history...
691
     *
692
     * @param null   $mode     (optional) error mode, one of: PEAR_ERROR_RETURN,
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $mode is correct as it would always require null to be passed?
Loading history...
693
     *                         PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER,
694
     *                         PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION
695
     *
696
     * @param mixed  $options  (optional) error level, _OR_ in the case of
697
     *                         PEAR_ERROR_CALLBACK, the callback function or object/method
698
     *                         tuple.
699
     *
700
     * @param null   $userinfo (optional) additional user/debug info
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $userinfo is correct as it would always require null to be passed?
Loading history...
701
     */
702
    public function __construct(
703
        string $message = 'unknown error', $code = null, $mode = null, $options = null, $userinfo = null
704
    ) {
705
        if (null === $mode) {
0 ignored issues
show
introduced by
The condition null === $mode is always true.
Loading history...
706
            $mode = PEAR_ERROR_RETURN;
707
        }
708
        $this->message  = $message;
709
        $this->code     = $code;
710
        $this->mode     = $mode;
711
        $this->userinfo = $userinfo;
712
        if (function_exists('debug_backtrace')) {
713
            $this->backtrace = debug_backtrace();
714
        }
715
        if ($mode & PEAR_ERROR_CALLBACK) {
716
            $this->level    = E_USER_NOTICE;
717
            $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...
718
        } else {
719
            if (null === $options) {
720
                $options = E_USER_NOTICE;
721
            }
722
            $this->level    = $options;
723
            $this->callback = null;
724
        }
725
        if ($this->mode & PEAR_ERROR_PRINT) {
726
            if (null === $options || is_int($options)) {
727
                $format = '%s';
728
            } else {
729
                $format = $options;
730
            }
731
            printf($format, $this->getMessage());
732
        }
733
        if ($this->mode & PEAR_ERROR_TRIGGER) {
734
            trigger_error($this->getMessage(), $this->level);
735
        }
736
        if ($this->mode & PEAR_ERROR_DIE) {
737
            $msg = $this->getMessage();
738
            if (null === $options || is_int($options)) {
739
                $format = '%s';
740
                if ("\n" !== mb_substr($msg, -1)) {
741
                    $msg .= "\n";
742
                }
743
            } else {
744
                $format = $options;
745
            }
746
            exit(sprintf($format, $msg));
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...
747
        }
748
        if ($this->mode & PEAR_ERROR_CALLBACK) {
749
            if (is_callable($this->callback)) {
750
                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

750
                call_user_func(/** @scrutinizer ignore-type */ $this->callback, $this);
Loading history...
751
            }
752
        }
753
        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

753
        if ($this->mode & /** @scrutinizer ignore-deprecated */ PEAR_ERROR_EXCEPTION) {
Loading history...
754
            trigger_error('PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_ErrorStack for exceptions', E_USER_WARNING);
755
            eval('$e = new Exception($this->message, $this->code);$e->PEAR_Error = $this;throw($e);');
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
756
        }
757
    }
758
759
    // }}}
760
    // {{{ getMode()
761
762
    /**
763
     * Get the error mode from an error object.
764
     *
765
     * @return int error mode
766
     */
767
    public function getMode(): ?int
768
    {
769
        return $this->mode;
770
    }
771
772
    // }}}
773
    // {{{ getCallback()
774
775
    /**
776
     * Get the callback function/method from an error object.
777
     *
778
     * @return mixed callback function or object/method array
779
     */
780
    public function getCallback()
781
    {
782
        return $this->callback;
783
    }
784
785
    // }}}
786
    // {{{ getMessage()
787
788
    /**
789
     * Get the error message from an error object.
790
     *
791
     * @return string full error message
792
     */
793
    public function getMessage(): string
794
    {
795
        return ($this->error_message_prefix . $this->message);
796
    }
797
798
    // }}}
799
    // {{{ getCode()
800
801
    /**
802
     * Get error code from an error object
803
     *
804
     * @return int error code
805
     */
806
    public function getCode(): ?int
807
    {
808
        return $this->code;
809
    }
810
811
    // }}}
812
    // {{{ getType()
813
814
    /**
815
     * Get the name of this error/exception.
816
     *
817
     * @return string error/exception name (type)
818
     */
819
    public function getType(): string
820
    {
821
        return get_class($this);
822
    }
823
824
    // }}}
825
    // {{{ getUserInfo()
826
827
    /**
828
     * Get additional user-supplied information.
829
     *
830
     * @return string user-supplied information
831
     */
832
    public function getUserInfo(): ?string
833
    {
834
        return $this->userinfo;
835
    }
836
837
    // }}}
838
    // {{{ getDebugInfo()
839
840
    /**
841
     * Get additional debug information supplied by the application.
842
     *
843
     * @return string debug information
844
     */
845
    public function getDebugInfo(): ?string
846
    {
847
        return $this->getUserInfo();
848
    }
849
850
    // }}}
851
    // {{{ getBacktrace()
852
853
    /**
854
     * Get the call backtrace from where the error was generated.
855
     * Supported with PHP 4.3.0 or newer.
856
     *
857
     * @param null $frame (optional) what frame to fetch
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $frame is correct as it would always require null to be passed?
Loading history...
858
     * @return array Backtrace, or NULL if not available.
859
     */
860
    public function getBacktrace($frame = null): ?array
861
    {
862
        if (null === $frame) {
0 ignored issues
show
introduced by
The condition null === $frame is always true.
Loading history...
863
            return $this->backtrace;
864
        }
865
866
        return $this->backtrace[$frame];
867
    }
868
869
    // }}}
870
    // {{{ addUserInfo()
871
872
    /**
873
     * @param string $info
874
     */
875
    public function addUserInfo($info): void
876
    {
877
        if (empty($this->userinfo)) {
878
            $this->userinfo = $info;
879
        } else {
880
            $this->userinfo .= " ** $info";
881
        }
882
    }
883
884
    // }}}
885
    // {{{ toString()
886
887
    /**
888
     * Make a string representation of this object.
889
     *
890
     * @return string a string with an object summary
891
     */
892
    public function toString(): string
893
    {
894
        $modes  = [];
895
        $levels = [
896
            E_USER_NOTICE  => 'notice',
897
            E_USER_WARNING => 'warning',
898
            E_USER_ERROR   => 'error',
899
        ];
900
        if ($this->mode & PEAR_ERROR_CALLBACK) {
901
            if (is_array($this->callback)) {
902
                $callback = get_class($this->callback[0]) . '::' . $this->callback[1];
903
            } else {
904
                $callback = $this->callback;
905
            }
906
907
            return sprintf('[%s: message="%s" code=%d mode=callback ' . 'callback=%s prefix="%s" info="%s"]', get_class($this), $this->message, $this->code, $callback, $this->error_message_prefix, $this->userinfo);
908
        }
909
        if ($this->mode & PEAR_ERROR_PRINT) {
910
            $modes[] = 'print';
911
        }
912
        if ($this->mode & PEAR_ERROR_TRIGGER) {
913
            $modes[] = 'trigger';
914
        }
915
        if ($this->mode & PEAR_ERROR_DIE) {
916
            $modes[] = 'die';
917
        }
918
        if ($this->mode & PEAR_ERROR_RETURN) {
919
            $modes[] = 'return';
920
        }
921
922
        return sprintf('[%s: message="%s" code=%d mode=%s level=%s ' . 'prefix="%s" info="%s"]', get_class($this), $this->message, $this->code, implode('|', $modes), $levels[$this->level], $this->error_message_prefix, $this->userinfo);
923
    }
924
    // }}}
925
}
926
927
register_shutdown_function('_PEAR_call_destructors');
928
929
/*
930
 * Local Variables:
931
 * mode: php
932
 * tab-width: 4
933
 * c-basic-offset: 4
934
 * End:
935
 */
936