GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Output::sendError()   A
last analyzed

Complexity

Conditions 5
Paths 12

Size

Total Lines 43
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 26
nc 12
nop 2
dl 0
loc 43
rs 9.1928
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of the O2System Framework package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @author         Steeve Andrian Salim
9
 * @copyright      Copyright (c) Steeve Andrian Salim
10
 */
11
12
// ------------------------------------------------------------------------
13
14
namespace O2System\Kernel\Cli;
15
16
// ------------------------------------------------------------------------
17
18
use O2System\Gear\Trace;
19
use O2System\Kernel\Cli\Writers\Format;
20
use O2System\Kernel\Cli\Writers\Line;
21
use O2System\Kernel\Cli\Writers\Table;
22
use O2System\Spl\Exceptions\Abstracts\AbstractException;
23
use O2System\Spl\Exceptions\ErrorException;
24
use O2System\Spl\Traits\Collectors\FilePathCollectorTrait;
25
26
/**
27
 * Class Output
28
 *
29
 * @package O2System\Kernel\Http
30
 */
31
class Output
32
{
33
    use FilePathCollectorTrait;
34
35
    // ------------------------------------------------------------------------
36
37
    /**
38
     * Output::__construct
39
     */
40
    public function __construct()
41
    {
42
        // Set Output Views Directory
43
        $this->setFileDirName('Views');
44
        $this->addFilePath(PATH_KERNEL);
45
46
        // Autoload exception and error language file
47
        language()->loadFile(['exception', 'error']);
48
49
        // Register Kernel defined handler
50
        $this->register();
51
    }
52
53
    // ------------------------------------------------------------------------
54
55
    /**
56
     * Output::register
57
     *
58
     * Register Kernel defined error, exception and shutdown handler.
59
     *
60
     * @return void
61
     */
62
    public function register()
63
    {
64
        set_error_handler([&$this, 'errorHandler']);
65
        set_exception_handler([&$this, 'exceptionHandler']);
66
        register_shutdown_function([&$this, 'shutdownHandler']);
67
    }
68
69
    // ------------------------------------------------------------------------
70
71
    /**
72
     * Output::shutdownHandler
73
     *
74
     * Kernel defined shutdown handler function.
75
     *
76
     * @return void
77
     * @throws \O2System\Spl\Exceptions\ErrorException
78
     */
79
    public function shutdownHandler()
80
    {
81
        $lastError = error_get_last();
82
83
        if (is_array($lastError)) {
0 ignored issues
show
introduced by
The condition is_array($lastError) is always true.
Loading history...
84
            $this->errorHandler(
85
                $lastError[ 'type' ],
86
                $lastError[ 'message' ],
87
                $lastError[ 'file' ],
88
                $lastError[ 'line' ]
89
            );
90
        }
91
92
        // Execute shutdown service
93
        if(services()->has('shutdown')) {
94
            shutdown()->execute();
95
        }
96
    }
97
98
    // ------------------------------------------------------------------------
99
100
    /**
101
     * Output::errorHandler
102
     *
103
     * Kernel defined error handler function.
104
     *
105
     * @param int    $errno      The first parameter, errno, contains the level of the error raised, as an integer.
106
     * @param string $errstr     The second parameter, errstr, contains the error message, as a string.
107
     * @param string $errfile    The third parameter is optional, errfile, which contains the filename that the error
108
     *                           was raised in, as a string.
109
     * @param string $errline    The fourth parameter is optional, errline, which contains the line number the error
110
     *                           was raised at, as an integer.
111
     * @param array  $errcontext The fifth parameter is optional, errcontext, which is an array that points to the
112
     *                           active symbol table at the point the error occurred. In other words, errcontext will
113
     *                           contain an array of every variable that existed in the scope the error was triggered
114
     *                           in. User error handler must not modify error context.
115
     *
116
     * @return bool If the function returns FALSE then the normal error handler continues.
117
     * @throws ErrorException
118
     */
119
    public function errorHandler($errno, $errstr, $errfile, $errline, array $errcontext = [])
0 ignored issues
show
Unused Code introduced by
The parameter $errcontext is not used and could be removed. ( Ignorable by Annotation )

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

119
    public function errorHandler($errno, $errstr, $errfile, $errline, /** @scrutinizer ignore-unused */ array $errcontext = [])

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
120
    {
121
        $isFatalError = (((E_ERROR | E_COMPILE_ERROR | E_CORE_ERROR | E_USER_ERROR) & $errno) === $errno);
122
123
        // When the error is fatal the Kernel will throw it as an exception.
124
        if ($isFatalError) {
125
            throw new ErrorException($errstr, $errno, $errfile, $errline);
0 ignored issues
show
Bug introduced by
$errline of type string is incompatible with the type integer expected by parameter $line of O2System\Spl\Exceptions\...xception::__construct(). ( Ignorable by Annotation )

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

125
            throw new ErrorException($errstr, $errno, $errfile, /** @scrutinizer ignore-type */ $errline);
Loading history...
126
        }
127
128
        // Should we ignore the error? We'll get the current error_reporting
129
        // level and add its bits with the severity bits to find out.
130
        if (($errno & error_reporting()) !== $errno) {
131
            return false;
132
        }
133
134
        $error = new ErrorException($errstr, $errno, $errfile, $errline);
135
        
136
        // Logged the error
137
        if(services()->has('logger')) {
138
            logger()->error(
139
                implode(
140
                    ' ',
141
                    [
142
                        '[ ' . $error->getStringSeverity() . ' ] ',
143
                        $error->getMessage(),
144
                        $error->getFile() . ':' . $error->getLine(),
145
                    ]
146
                )
147
            );
148
        }
149
150
        $errdisplay = str_ireplace(['off', 'none', 'no', 'false', 'null'], 0, ini_get('display_errors'));
151
152
        // Should we display the error?
153
        if ($errdisplay == 1) {
154
            output()->write(
0 ignored issues
show
Bug introduced by
The method write() does not exist on O2System\Kernel\Http\Output. ( Ignorable by Annotation )

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

154
            output()->/** @scrutinizer ignore-call */ write(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
155
                (new Format())
156
                    ->setContextualClass(Format::DANGER)
157
                    ->setString(language()->getLine('E_CAUGHT_ERROR'))
158
                    ->setNewLinesAfter(1)
159
            );
160
161
            output()->write(
162
                (new Format())
163
                    ->setContextualClass(Format::WARNING)
164
                    ->setString('[ ' . language()->getLine($error->getStringSeverity()) . ' ] ' . $error->getMessage())
165
                    ->setNewLinesAfter(1)
166
            );
167
168
            output()->write(
169
                (new Format())
170
                    ->setContextualClass(Format::INFO)
171
                    ->setString($error->getFile() . ':' . $error->getLine())
172
                    ->setNewLinesAfter(1)
173
            );
174
        }
175
    }
176
177
    // ------------------------------------------------------------------------
178
179
    /**
180
     * Output::write
181
     *
182
     * Write text to console.
183
     *
184
     * @param string $text
185
     * @param string $type
186
     */
187
    public function write($text, $type = 'stdout')
188
    {
189
        if (in_array($type, ['stdout', 'stderr']) && ! empty($text)) {
190
            $f = fopen('php://' . $type, 'w');
191
192
            if (is_array($text)) {
0 ignored issues
show
introduced by
The condition is_array($text) is always false.
Loading history...
193
                $text = json_encode($text);
194
            }
195
196
            fwrite($f, $text);
0 ignored issues
show
Bug introduced by
It seems like $f can also be of type false; however, parameter $handle of fwrite() does only seem to accept resource, 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

196
            fwrite(/** @scrutinizer ignore-type */ $f, $text);
Loading history...
197
            fclose($f);
0 ignored issues
show
Bug introduced by
It seems like $f can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, 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

197
            fclose(/** @scrutinizer ignore-type */ $f);
Loading history...
198
        }
199
    }
200
201
    // ------------------------------------------------------------------------
202
203
    /**
204
     * Output::exceptionHandler
205
     *
206
     * Kernel defined exception handler function.
207
     *
208
     * @param \Exception|\Error|\O2System\Spl\Exceptions\Abstracts\AbstractException $exception Throwable exception.
209
     *
210
     * @return void
211
     */
212
    public function exceptionHandler($exception)
213
    {
214
        // Standard PHP Libraries Error
215
        if ($exception instanceof \Error) {
216
            $error = new ErrorException(
217
                $exception->getMessage(),
218
                $exception->getCode(),
219
                $exception->getFile(),
220
                $exception->getLine()
221
            );
222
223
            output()->write(
224
                (new Format())
225
                    ->setContextualClass(Format::DANGER)
226
                    ->setString(language()->getLine('E_CAUGHT_ERROR'))
227
                    ->setNewLinesAfter(1)
228
            );
229
230
            output()->write(
231
                (new Format())
232
                    ->setContextualClass(Format::WARNING)
233
                    ->setString('[ ' . language()->getLine($error->getStringSeverity()) . ' ] ' . $error->getMessage())
234
                    ->setNewLinesAfter(1)
235
            );
236
237
            output()->write(
238
                (new Format())
239
                    ->setContextualClass(Format::INFO)
240
                    ->setString($error->getFile() . ':' . $error->getLine())
241
                    ->setNewLinesAfter(1)
242
            );
243
244
            exit(EXIT_ERROR);
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...
245
        } elseif ($exception instanceof AbstractException) {
246
247
            output()->write(
248
                (new Format())
249
                    ->setContextualClass(Format::DANGER)
250
                    ->setString(language()->getLine($exception->getHeader()))
251
                    ->setNewLinesAfter(1)
252
            );
253
254
            output()->write(
255
                (new Format())
256
                    ->setContextualClass(Format::DANGER)
257
                    ->setString('[ ' . language()->getLine($exception->getCode()) . ' ] ' . language()->getLine($exception->getDescription()))
258
                    ->setNewLinesAfter(1)
259
            );
260
261
            output()->write(
262
                (new Format())
263
                    ->setContextualClass(Format::DANGER)
264
                    ->setString($exception->getMessage())
265
                    ->setNewLinesAfter(1)
266
            );
267
268
            output()->write(
269
                (new Format())
270
                    ->setString($debugTitle = language()->getLine('E_DEBUG_BACKTRACE') . ':')
271
                    ->setContextualClass(Format::INFO)
272
                    ->setNewLinesBefore(1)
273
                    ->setNewLinesAfter(1)
274
            );
275
276
            output()->write((new Line(strlen($debugTitle) * 2))
277
                ->setContextualClass(Line::INFO)
278
                ->setNewLinesAfter(2));
279
280
            $table = new Table();
281
            $table->isShowBorder = false;
282
283
            $i = 1;
284
            foreach ($exception->getChronology() as $chronology) {
285
                $table
286
                    ->addRow()
287
                    ->addColumn($i . '. ' . $chronology->call)
288
                    ->addRow()
289
                    ->addColumn($chronology->file . ':' . $chronology->line)
290
                    ->addRow()
291
                    ->addColumn('');
292
293
                $i++;
294
            }
295
296
            output()->write(
297
                (new Format())
298
                    ->setContextualClass(Format::INFO)
299
                    ->setString($table->render())
300
                    ->setNewLinesAfter(2)
301
            );
302
        } // Standard PHP Libraries Exception
303
        elseif ($exception instanceof \Exception) {
0 ignored issues
show
introduced by
$exception is always a sub-type of Exception.
Loading history...
304
            output()->write(
305
                (new Format())
306
                    ->setContextualClass(Format::DANGER)
307
                    ->setString('[ ' . language()->getLine($exception->getCode()) . ' ] ' . language()->getLine($exception->getMessage()))
308
                    ->setNewLinesAfter(1)
309
            );
310
311
            output()->write(
312
                (new Format())
313
                    ->setContextualClass(Format::DANGER)
314
                    ->setString($exception->getMessage())
315
                    ->setNewLinesAfter(1)
316
            );
317
318
            output()->write(
319
                (new Format())
320
                    ->setString($debugTitle = language()->getLine('E_DEBUG_BACKTRACE') . ':')
321
                    ->setContextualClass(Format::INFO)
322
                    ->setNewLinesBefore(1)
323
                    ->setNewLinesAfter(1)
324
            );
325
326
            output()->write((new Line(strlen($debugTitle) * 2))
327
                ->setContextualClass(Line::INFO)
328
                ->setNewLinesAfter(2));
329
330
            $table = new Table();
331
            $table->isShowBorder = false;
332
333
            $trace = new Trace($exception->getTrace());
334
335
            $i = 1;
336
            foreach ($trace->getChronology() as $chronology) {
337
                $table
338
                    ->addRow()
339
                    ->addColumn($i . '. ' . $chronology->call)
340
                    ->addRow()
341
                    ->addColumn($chronology->file . ':' . $chronology->line)
342
                    ->addRow()
343
                    ->addColumn('');
344
345
                $i++;
346
            }
347
348
            output()->write(
349
                (new Format())
350
                    ->setContextualClass(Format::INFO)
351
                    ->setString($table->render())
352
                    ->setNewLinesAfter(2)
353
            );
354
        }
355
    }
356
357
    // ------------------------------------------------------------------------
358
359
    /**
360
     * Output::sendError
361
     *
362
     * @param int               $code
363
     * @param null|array|string $vars
364
     */
365
    public function sendError($code = 204, $vars = null)
366
    {
367
        static $errors = [];
368
369
        if (empty($errors)) {
370
            $errors = require(str_replace('Cli', 'Config', __DIR__) . DIRECTORY_SEPARATOR . 'Errors.php');
371
        }
372
373
        if (isset($errors[ $code ])) {
374
            $languageKey = $errors[ $code ];
375
        }
376
377
        $languageKey = strtoupper($code . '_' . $languageKey);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $languageKey does not seem to be defined for all execution paths leading up to this point.
Loading history...
378
379
        $error = [
380
            'code'    => $code,
381
            'title'   => language()->getLine($languageKey . '_TITLE'),
382
            'message' => language()->getLine($languageKey . '_MESSAGE'),
383
        ];
384
385
        $this->statusCode = $code;
0 ignored issues
show
Bug Best Practice introduced by
The property statusCode does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
386
        $this->reasonPhrase = $error[ 'title' ];
0 ignored issues
show
Bug Best Practice introduced by
The property reasonPhrase does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
387
388
        if (is_string($vars)) {
389
            $error[ 'message' ] = $vars;
390
        } elseif (is_array($vars)) {
391
            $error = array_merge($error, $vars);
392
        }
393
394
        $this->write(
395
            (new Format())
396
                ->setContextualClass(Format::DANGER)
397
                ->setString($error[ 'code' ] . ' - ' . $error[ 'title' ])
398
                ->setNewLinesAfter(1)
399
        );
400
401
        $this->write(
402
            (new Format())
403
                ->setString($error[ 'message' ])
404
                ->setNewLinesAfter(1)
405
        );
406
407
        exit(EXIT_ERROR);
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...
408
    }
409
410
    // ------------------------------------------------------------------------
411
412
    /**
413
     * Output::verbose
414
     *
415
     * Write verbose text to console.
416
     *
417
     * @param string $text
418
     * @param string $type
419
     */
420
    public function verbose($text, $type = 'stdout')
421
    {
422
        if (isset($_ENV[ 'VERBOSE' ]) and $_ENV[ 'VERBOSE' ] === true) {
423
            $this->write($text, $type);
424
        }
425
    }
426
}