Subversion-Projekte lars-tiefland.laravel_shop

Revision

Zur aktuellen Revision | Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 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 callable
31
     */
32
    protected $dumper;
33
 
34
    /**
35
     * @var bool
36
     */
37
    private $addTraceToOutput = true;
38
 
39
    /**
40
     * @var bool|integer
41
     */
42
    private $addTraceFunctionArgsToOutput = false;
43
 
44
    /**
45
     * @var integer
46
     */
47
    private $traceFunctionArgsOutputLimit = 1024;
48
 
49
    /**
50
     * @var bool
51
     */
52
    private $addPreviousToOutput = true;
53
 
54
    /**
55
     * @var bool
56
     */
57
    private $loggerOnly = false;
58
 
59
    /**
60
     * Constructor.
61
     * @throws InvalidArgumentException     If argument is not null or a LoggerInterface
62
     * @param  \Psr\Log\LoggerInterface|null $logger
63
     */
64
    public function __construct($logger = null)
65
    {
66
        $this->setLogger($logger);
67
    }
68
 
69
    /**
70
     * Set the output logger interface.
71
     * @throws InvalidArgumentException     If argument is not null or a LoggerInterface
72
     * @param  \Psr\Log\LoggerInterface|null $logger
73
     */
74
    public function setLogger($logger = null)
75
    {
76
        if (! (is_null($logger)
77
            || $logger instanceof LoggerInterface)) {
78
            throw new InvalidArgumentException(
79
                'Argument to ' . __METHOD__ .
80
                " must be a valid Logger Interface (aka. Monolog), " .
81
                get_class($logger) . ' given.'
82
            );
83
        }
84
 
85
        $this->logger = $logger;
86
    }
87
 
88
    /**
89
     * @return \Psr\Log\LoggerInterface|null
90
     */
91
    public function getLogger()
92
    {
93
        return $this->logger;
94
    }
95
 
96
    /**
97
     * Set var dumper callback function.
98
     *
99
     * @param  callable $dumper
100
     * @return static
101
     */
102
    public function setDumper(callable $dumper)
103
    {
104
        $this->dumper = $dumper;
105
        return $this;
106
    }
107
 
108
    /**
109
     * Add error trace to output.
110
     * @param  bool|null  $addTraceToOutput
111
     * @return bool|static
112
     */
113
    public function addTraceToOutput($addTraceToOutput = null)
114
    {
115
        if (func_num_args() == 0) {
116
            return $this->addTraceToOutput;
117
        }
118
 
119
        $this->addTraceToOutput = (bool) $addTraceToOutput;
120
        return $this;
121
    }
122
 
123
    /**
124
     * Add previous exceptions to output.
125
     * @param  bool|null $addPreviousToOutput
126
     * @return bool|static
127
     */
128
    public function addPreviousToOutput($addPreviousToOutput = null)
129
    {
130
        if (func_num_args() == 0) {
131
            return $this->addPreviousToOutput;
132
        }
133
 
134
        $this->addPreviousToOutput = (bool) $addPreviousToOutput;
135
        return $this;
136
    }
137
 
138
    /**
139
     * Add error trace function arguments to output.
140
     * Set to True for all frame args, or integer for the n first frame args.
141
     * @param  bool|integer|null $addTraceFunctionArgsToOutput
142
     * @return static|bool|integer
143
     */
144
    public function addTraceFunctionArgsToOutput($addTraceFunctionArgsToOutput = null)
145
    {
146
        if (func_num_args() == 0) {
147
            return $this->addTraceFunctionArgsToOutput;
148
        }
149
 
150
        if (! is_integer($addTraceFunctionArgsToOutput)) {
151
            $this->addTraceFunctionArgsToOutput = (bool) $addTraceFunctionArgsToOutput;
152
        } else {
153
            $this->addTraceFunctionArgsToOutput = $addTraceFunctionArgsToOutput;
154
        }
155
        return $this;
156
    }
157
 
158
    /**
159
     * Set the size limit in bytes of frame arguments var_dump output.
160
     * If the limit is reached, the var_dump output is discarded.
161
     * Prevent memory limit errors.
162
     * @var integer
163
     * @return static
164
     */
165
    public function setTraceFunctionArgsOutputLimit($traceFunctionArgsOutputLimit)
166
    {
167
        $this->traceFunctionArgsOutputLimit = (integer) $traceFunctionArgsOutputLimit;
168
        return $this;
169
    }
170
 
171
    /**
172
     * Create plain text response and return it as a string
173
     * @return string
174
     */
175
    public function generateResponse()
176
    {
177
        $exception = $this->getException();
178
        $message = $this->getExceptionOutput($exception);
179
 
180
        if ($this->addPreviousToOutput) {
181
            $previous = $exception->getPrevious();
182
            while ($previous) {
183
                $message .= "\n\nCaused by\n" . $this->getExceptionOutput($previous);
184
                $previous = $previous->getPrevious();
185
            }
186
        }
187
 
188
 
189
        return $message . $this->getTraceOutput() . "\n";
190
    }
191
 
192
    /**
193
     * Get the size limit in bytes of frame arguments var_dump output.
194
     * If the limit is reached, the var_dump output is discarded.
195
     * Prevent memory limit errors.
196
     * @return integer
197
     */
198
    public function getTraceFunctionArgsOutputLimit()
199
    {
200
        return $this->traceFunctionArgsOutputLimit;
201
    }
202
 
203
    /**
204
     * Only output to logger.
205
     * @param  bool|null $loggerOnly
206
     * @return static|bool
207
     */
208
    public function loggerOnly($loggerOnly = null)
209
    {
210
        if (func_num_args() == 0) {
211
            return $this->loggerOnly;
212
        }
213
 
214
        $this->loggerOnly = (bool) $loggerOnly;
215
        return $this;
216
    }
217
 
218
    /**
219
     * Test if handler can output to stdout.
220
     * @return bool
221
     */
222
    private function canOutput()
223
    {
224
        return !$this->loggerOnly();
225
    }
226
 
227
    /**
228
     * Get the frame args var_dump.
229
     * @param  \Whoops\Exception\Frame $frame [description]
230
     * @param  integer                 $line  [description]
231
     * @return string
232
     */
233
    private function getFrameArgsOutput(Frame $frame, $line)
234
    {
235
        if ($this->addTraceFunctionArgsToOutput() === false
236
            || $this->addTraceFunctionArgsToOutput() < $line) {
237
            return '';
238
        }
239
 
240
        // Dump the arguments:
241
        ob_start();
242
        $this->dump($frame->getArgs());
243
        if (ob_get_length() > $this->getTraceFunctionArgsOutputLimit()) {
244
            // The argument var_dump is to big.
245
            // Discarded to limit memory usage.
246
            ob_clean();
247
            return sprintf(
248
                "\n%sArguments dump length greater than %d Bytes. Discarded.",
249
                self::VAR_DUMP_PREFIX,
250
                $this->getTraceFunctionArgsOutputLimit()
251
            );
252
        }
253
 
254
        return sprintf(
255
            "\n%s",
256
            preg_replace('/^/m', self::VAR_DUMP_PREFIX, ob_get_clean())
257
        );
258
    }
259
 
260
    /**
261
     * Dump variable.
262
     *
263
     * @param mixed $var
264
     * @return void
265
     */
266
    protected function dump($var)
267
    {
268
        if ($this->dumper) {
269
            call_user_func($this->dumper, $var);
270
        } else {
271
            var_dump($var);
272
        }
273
    }
274
 
275
    /**
276
     * Get the exception trace as plain text.
277
     * @return string
278
     */
279
    private function getTraceOutput()
280
    {
281
        if (! $this->addTraceToOutput()) {
282
            return '';
283
        }
284
        $inspector = $this->getInspector();
285
        $frames = $inspector->getFrames();
286
 
287
        $response = "\nStack trace:";
288
 
289
        $line = 1;
290
        foreach ($frames as $frame) {
291
            /** @var Frame $frame */
292
            $class = $frame->getClass();
293
 
294
            $template = "\n%3d. %s->%s() %s:%d%s";
295
            if (! $class) {
296
                // Remove method arrow (->) from output.
297
                $template = "\n%3d. %s%s() %s:%d%s";
298
            }
299
 
300
            $response .= sprintf(
301
                $template,
302
                $line,
303
                $class,
304
                $frame->getFunction(),
305
                $frame->getFile(),
306
                $frame->getLine(),
307
                $this->getFrameArgsOutput($frame, $line)
308
            );
309
 
310
            $line++;
311
        }
312
 
313
        return $response;
314
    }
315
 
316
    /**
317
     * Get the exception as plain text.
318
     * @param \Throwable $exception
319
     * @return string
320
     */
321
    private function getExceptionOutput($exception)
322
    {
323
        return sprintf(
324
            "%s: %s in file %s on line %d",
325
            get_class($exception),
326
            $exception->getMessage(),
327
            $exception->getFile(),
328
            $exception->getLine()
329
        );
330
    }
331
 
332
    /**
333
     * @return int
334
     */
335
    public function handle()
336
    {
337
        $response = $this->generateResponse();
338
 
339
        if ($this->getLogger()) {
340
            $this->getLogger()->error($response);
341
        }
342
 
343
        if (! $this->canOutput()) {
344
            return Handler::DONE;
345
        }
346
 
347
        echo $response;
348
 
349
        return Handler::QUIT;
350
    }
351
 
352
    /**
353
     * @return string
354
     */
355
    public function contentType()
356
    {
357
        return 'text/plain';
358
    }
359
}