Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
71.43% covered (warning)
71.43%
20 / 28
28.57% covered (danger)
28.57%
2 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
WarningLoggerTrait
71.43% covered (warning)
71.43%
20 / 28
28.57% covered (danger)
28.57%
2 / 7
16.94
0.00% covered (danger)
0.00%
0 / 1
 logLn
n/a
0 / 0
n/a
0 / 0
0
 warningHandler
77.78% covered (warning)
77.78%
14 / 18
0.00% covered (danger)
0.00%
0 / 1
7.54
 activateWarningLogger
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 deactivateWarningLogger
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 disableWarningsTemporarily
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 reenableWarnings
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getWarningCount
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 resetWarningCount
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace WebPConvert\Convert\Converters\BaseTraits;
4
5/**
6 * Trait for handling warnings (by logging them)
7 *
8 * This trait is currently only used in the AbstractConverter class. It has been extracted into a
9 * trait in order to bundle the methods concerning options.
10 *
11 * @package    WebPConvert
12 * @author     Bjørn Rosell <it@rosell.dk>
13 * @since      Class available since Release 2.0.0
14 */
15trait WarningLoggerTrait
16{
17    abstract public function logLn($msg, $style = '');
18
19    /** @var string|array|null  Previous error handler (stored in order to be able pass warnings on) */
20    private $previousErrorHandler;
21
22    /** @var boolean  Suppress ALL warnings? (both from log and from bubbling up) */
23    private $suppressWarnings;
24
25    /** @var int  Count number of warnings */
26    private $warningCounter;
27
28    /**
29     *  Handle warnings and notices during conversion by logging them and passing them on.
30     *
31     *  The function is a callback used with "set_error_handler".
32     *  It is declared public because it needs to be accessible from the point where the warning is triggered.
33     *
34     *  PS: The fifth parameter ($errcontext) of an error handler is deprecated since PHP 7.2, however we have
35     *      it here to avoid calling another error handler with too few parameters (see #266)
36     *
37     *  @param  integer  $errno
38     *  @param  string   $errstr
39     *  @param  string   $errfile
40     *  @param  integer  $errline
41     *  @param  array    $errcontext
42     *
43     *  @return false|null|void
44     */
45    public function warningHandler($errno, $errstr, $errfile, $errline, $errcontext = null)
46    {
47        /*
48        We do NOT do the following (even though it is generally recommended):
49
50        if (!(error_reporting() & $errno)) {
51            // This error code is not included in error_reporting, so let it fall
52            // through to the standard PHP error handler
53            return false;
54        }
55
56        - Because we want to log all warnings and errors (also the ones that was suppressed with @)
57        https://secure.php.net/manual/en/language.operators.errorcontrol.php
58
59        If we were to decide suppressing the ones with @, I could do this:
60
61        if (error_reporting() == 0) {
62            /// @ sign temporary disabled error reporting
63            return;
64        }
65        [https://stackoverflow.com/questions/7380782/error-suppression-operator-and-set-error-handler]
66
67        However, that would also disable the warnings on systems with error reporting set to E_NONE.
68        And I really want the conversion log file to contain these warnings on all systems.
69
70        If it was possible to suppress the warnings with @ without suppressing warnings on systems
71        with error reporting set to E_NONE, I would do that.
72        */
73
74        $this->warningCounter++;
75        if ($this->suppressWarnings) {
76            return;
77        }
78
79        $errorTypes = [
80            E_WARNING =>             "Warning",
81            E_NOTICE =>              "Notice",
82            E_STRICT =>              "Strict Notice",
83            E_DEPRECATED =>          "Deprecated",
84            E_USER_DEPRECATED =>     "User Deprecated",
85
86            /*
87            The following can never be catched by a custom error handler:
88            E_PARSE, E_ERROR, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING
89
90            We do do not currently trigger the following:
91            E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE
92
93            But we may want to do that at some point, like this:
94            trigger_error('Your version of Gd is very old', E_USER_WARNING);
95            in that case, remember to add them to this array
96            */
97        ];
98
99        if (isset($errorTypes[$errno])) {
100            $errType = $errorTypes[$errno];
101        } else {
102            $errType = "Unknown error/warning/notice ($errno)";
103        }
104
105        $msg = $errType . ': ' . $errstr . ' in ' . $errfile . ', line ' . $errline . ', PHP ' . PHP_VERSION .
106            ' (' . PHP_OS . ')';
107        $this->logLn('');
108        $this->logLn($msg, 'italic');
109        $this->logLn('');
110
111        if (!is_null($this->previousErrorHandler)) {
112            // If previousErrorHandler is this very error handler, exit to avoid recursion
113            // (this could happen if ::activateWarningLogger() were called twice)
114            if (is_array($this->previousErrorHandler) &&
115                isset($this->previousErrorHandler[0]) &&
116                ($this->previousErrorHandler[0] == $this)
117            ) {
118                return false;
119            } else {
120                return call_user_func($this->previousErrorHandler, $errno, $errstr, $errfile, $errline, $errcontext);
121            }
122        } else {
123            return false;
124        }
125    }
126
127    /**
128     *  Activate warning logger.
129     *
130     *  Sets the error handler and stores the previous so our error handler can bubble up warnings
131     *
132     *  @return  void
133     */
134    protected function activateWarningLogger()
135    {
136        $this->suppressWarnings = false;
137        $this->warningCounter = 0;
138        $this->previousErrorHandler = set_error_handler(
139            array($this, "warningHandler"),
140            E_WARNING | E_USER_WARNING | E_NOTICE | E_USER_NOTICE
141        );
142    }
143
144    /**
145     *  Deactivate warning logger.
146     *
147     *  Restores the previous error handler.
148     *
149     *  @return  void
150     */
151    protected function deactivateWarningLogger()
152    {
153        restore_error_handler();
154    }
155
156    protected function disableWarningsTemporarily()
157    {
158        $this->suppressWarnings = true;
159    }
160
161    protected function reenableWarnings()
162    {
163        $this->suppressWarnings = false;
164    }
165
166    protected function getWarningCount()
167    {
168        return $this->warningCounter;
169    }
170
171    protected function resetWarningCount()
172    {
173        $this->warningCounter = 0;
174    }
175}