Completed
Push — master ( 4bbb33...2abce9 )
by Denis
11s
created

PlainTextHandler::contentType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
/**
3
* Whoops - php errors for cool kids
4
* @author Filipe Dobreira <http://github.com/filp>
5
* Plaintext handler for command line and logs.
6
* @author Pierre-Yves Landuré <https://howto.biapy.com/>
7
*/
8
9
namespace Whoops\Handler;
10
11
use InvalidArgumentException;
12
use Psr\Log\LoggerInterface;
13
use Whoops\Exception\Frame;
14
15
/**
16
* Handler outputing plaintext error messages. Can be used
17
* directly, or will be instantiated automagically by Whoops\Run
18
* if passed to Run::pushHandler
19
*/
20
class PlainTextHandler extends Handler
21
{
22
    const VAR_DUMP_PREFIX = '   | ';
23
24
    /**
25
     * @var \Psr\Log\LoggerInterface
26
     */
27
    protected $logger;
28
29
    /**
30
     * @var bool
31
     */
32
    private $addTraceToOutput = true;
33
34
    /**
35
     * @var bool|integer
36
     */
37
    private $addTraceFunctionArgsToOutput = false;
38
39
    /**
40
     * @var integer
41
     */
42
    private $traceFunctionArgsOutputLimit = 1024;
43
44
    /**
45
     * @var bool
46
     */
47
    private $loggerOnly = false;
48
49
    /**
50
     * Constructor.
51
     * @throws InvalidArgumentException     If argument is not null or a LoggerInterface
52
     * @param  \Psr\Log\LoggerInterface|null $logger
53
     */
54 1
    public function __construct($logger = null)
55
    {
56 1
        $this->setLogger($logger);
57
    }
58
59
    /**
60
     * Set the output logger interface.
61
     * @throws InvalidArgumentException     If argument is not null or a LoggerInterface
62
     * @param  \Psr\Log\LoggerInterface|null $logger
63
     */
64 2
    public function setLogger($logger = null)
65
    {
66 2
        if (! (is_null($logger)
67 2
            || $logger instanceof LoggerInterface)) {
68 2
            throw new InvalidArgumentException(
69 2
                'Argument to ' . __METHOD__ .
70 2
                " must be a valid Logger Interface (aka. Monolog), " .
71 2
                get_class($logger) . ' given.'
72 2
            );
73
        }
74
75 1
        $this->logger = $logger;
76 1
    }
77
78
    /**
79
     * @return \Psr\Log\LoggerInterface|null
80
     */
81
    public function getLogger()
82
    {
83
        return $this->logger;
84
    }
85
86
    /**
87
     * Add error trace to output.
88
     * @param  bool|null  $addTraceToOutput
89
     * @return bool|$this
90
     */
91 4
    public function addTraceToOutput($addTraceToOutput = null)
92
    {
93 4
        if (func_num_args() == 0) {
94 4
            return $this->addTraceToOutput;
95
        }
96
97 4
        $this->addTraceToOutput = (bool) $addTraceToOutput;
98 4
        return $this;
99
    }
100
101
    /**
102
     * Add error trace function arguments to output.
103
     * Set to True for all frame args, or integer for the n first frame args.
104
     * @param  bool|integer|null $addTraceFunctionArgsToOutput
105
     * @return null|bool|integer
106
     */
107 2
    public function addTraceFunctionArgsToOutput($addTraceFunctionArgsToOutput = null)
108
    {
109 2
        if (func_num_args() == 0) {
110 2
            return $this->addTraceFunctionArgsToOutput;
111
        }
112
113 2
        if (! is_integer($addTraceFunctionArgsToOutput)) {
114 1
            $this->addTraceFunctionArgsToOutput = (bool) $addTraceFunctionArgsToOutput;
115 1
        } else {
116 2
            $this->addTraceFunctionArgsToOutput = $addTraceFunctionArgsToOutput;
117
        }
118 2
    }
119
120
    /**
121
     * Set the size limit in bytes of frame arguments var_dump output.
122
     * If the limit is reached, the var_dump output is discarded.
123
     * Prevent memory limit errors.
124
     * @var integer
125
     */
126 1
    public function setTraceFunctionArgsOutputLimit($traceFunctionArgsOutputLimit)
127
    {
128 1
        $this->traceFunctionArgsOutputLimit = (integer) $traceFunctionArgsOutputLimit;
129 1
    }
130
131
    /**
132
     * Create plain text response and return it as a string
133
     * @return string
134
     */
135
    public function generateResponse()
136
    {
137
        $exception = $this->getException();
138
        return sprintf("%s: %s in file %s on line %d%s\n",
139
            get_class($exception),
140
            $exception->getMessage(),
141
            $exception->getFile(),
142
            $exception->getLine(),
143
            $this->getTraceOutput()
144
        );
145
    }
146
147
    /**
148
     * Get the size limit in bytes of frame arguments var_dump output.
149
     * If the limit is reached, the var_dump output is discarded.
150
     * Prevent memory limit errors.
151
     * @return integer
152
     */
153 1
    public function getTraceFunctionArgsOutputLimit()
154
    {
155 1
        return $this->traceFunctionArgsOutputLimit;
156
    }
157
158
    /**
159
     * Only output to logger.
160
     * @param  bool|null $loggerOnly
161
     * @return null|bool
162
     */
163 1
    public function loggerOnly($loggerOnly = null)
164
    {
165 1
        if (func_num_args() == 0) {
166 1
            return $this->loggerOnly;
167
        }
168
169 1
        $this->loggerOnly = (bool) $loggerOnly;
170 1
    }
171
172
    /**
173
     * Test if handler can output to stdout.
174
     * @return bool
175
     */
176 2
    private function canOutput()
177
    {
178 2
        return !$this->loggerOnly();
179
    }
180
181
    /**
182
     * Get the frame args var_dump.
183
     * @param  \Whoops\Exception\Frame $frame [description]
184
     * @param  integer                 $line  [description]
185
     * @return string
186
     */
187 1
    private function getFrameArgsOutput(Frame $frame, $line)
188
    {
189 1
        if ($this->addTraceFunctionArgsToOutput() === false
190 1
            || $this->addTraceFunctionArgsToOutput() < $line) {
191 1
            return '';
192
        }
193
194
        // Dump the arguments:
195 1
        ob_start();
196 1
        var_dump($frame->getArgs());
197 1
        if (ob_get_length() > $this->getTraceFunctionArgsOutputLimit()) {
198
            // The argument var_dump is to big.
199
            // Discarded to limit memory usage.
200
            ob_clean();
201
            return sprintf(
202
                "\n%sArguments dump length greater than %d Bytes. Discarded.",
203
                self::VAR_DUMP_PREFIX,
204
                $this->getTraceFunctionArgsOutputLimit()
205
            );
206
        }
207
208 1
        return sprintf("\n%s",
209 1
            preg_replace('/^/m', self::VAR_DUMP_PREFIX, ob_get_clean())
210 1
        );
211
    }
212
213
    /**
214
     * Get the exception trace as plain text.
215
     * @return string
216
     */
217 2
    private function getTraceOutput()
218
    {
219 2
        if (! $this->addTraceToOutput()) {
220
            return '';
221
        }
222 2
        $inspector = $this->getInspector();
223 2
        $frames = $inspector->getFrames();
224
225 2
        $response = "\nStack trace:";
226
227 2
        $line = 1;
228 2
        foreach ($frames as $frame) {
229
            /** @var Frame $frame */
230 2
            $class = $frame->getClass();
231
232 2
            $template = "\n%3d. %s->%s() %s:%d%s";
233 2
            if (! $class) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $class of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
234
                // Remove method arrow (->) from output.
235
                $template = "\n%3d. %s%s() %s:%d%s";
236
            }
237
238 2
            $response .= sprintf(
239 2
                $template,
240 2
                $line,
241 2
                $class,
242 2
                $frame->getFunction(),
243 2
                $frame->getFile(),
244 2
                $frame->getLine(),
245 2
                $this->getFrameArgsOutput($frame, $line)
246 2
            );
247
248 2
            $line++;
249 2
        }
250
251 2
        return $response;
252
    }
253
254
    /**
255
     * @return int
256
     */
257 3
    public function handle()
258
    {
259 3
        $response = $this->generateResponse();
260
261 3
        if ($this->getLogger()) {
262
            $this->getLogger()->error($response);
263
        }
264
265 3
        if (! $this->canOutput()) {
266
            return Handler::DONE;
267
        }
268
269 3
        echo $response;
270
271 3
        return Handler::QUIT;
272
    }
273
274
    /**
275
     * @return string
276
     */
277
    public function contentType()
278
    {
279
        return 'text/plain';
280
    }
281
}
282