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.

Handle   B
last analyzed

Complexity

Total Complexity 41

Size/Duplication

Total Lines 387
Duplicated Lines 3.1 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
dl 12
loc 387
ccs 0
cts 128
cp 0
rs 8.2769
c 0
b 0
f 0
wmc 41
lcom 1
cbo 8

11 Methods

Rating   Name   Duplication   Size   Complexity  
A setDebugHeader() 0 6 2
C getErrorType() 0 49 14
B renderHaltBody() 0 67 4
A renderLogBody() 0 4 1
A renderErrorText() 0 4 1
A getSourceCode() 0 16 3
B halt() 0 66 5
A error() 0 13 2
A exception() 6 14 3
B end() 6 21 5
A outputCliError() 0 6 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Handle often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Handle, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Kotori.php
4
 *
5
 * A Tiny Model-View-Controller PHP Framework
6
 *
7
 * This content is released under the Apache 2 License
8
 *
9
 * Copyright (c) 2015-2017 Kotori Technology. All rights reserved.
10
 *
11
 * Licensed under the Apache License, Version 2.0 (the "License");
12
 * you may not use this file except in compliance with the License.
13
 * You may obtain a copy of the License at
14
 *
15
 *     http://www.apache.org/licenses/LICENSE-2.0
16
 *
17
 * Unless required by applicable law or agreed to in writing, software
18
 * distributed under the License is distributed on an "AS IS" BASIS,
19
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
 * See the License for the specific language governing permissions and
21
 * limitations under the License.
22
 */
23
24
/**
25
 * Handle Class
26
 *
27
 * @package     Kotori
28
 * @subpackage  Core
29
 * @author      Kokororin
30
 * @link        https://kotori.love
31
 */
32
namespace Kotori\Core;
33
34
use Exception;
35
use Highlight\Highlighter;
36
use Kotori\Exception\ResponseException;
37
use Symfony\Component\Console\Application as ConsoleApp;
38
use Symfony\Component\Console\Output\ConsoleOutput;
39
use WyriHaximus\HtmlCompress\Factory as HtmlCompress;
40
41
abstract class Handle
42
{
43
    /**
44
     * Error Array
45
     *
46
     * @var array
47
     */
48
    public static $errors = [];
49
50
    /**
51
     * General Error Page
52
     *
53
     * Takes an error message as input
54
     * and displays it using the specified template.
55
     *
56
     * @param  string $message
57
     * @param  int    $code
58
     * @return void
59
     */
60
    public static function halt($message, $code = 404)
0 ignored issues
show
Coding Style introduced by
halt uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
61
    {
62
        Container::get('response')->setStatus($code);
63
64
        if (!Container::get('config')->get('app_debug')) {
65
            $message = '404 Not Found.';
66
        }
67
68
        if (Container::get('config')->get('app_debug')) {
69
            $tplPath = null;
70
        } else {
71
            $tplPath = Container::get('config')->get('error_tpl');
72
        }
73
74
        if ($tplPath == null || !Helper::isFile(Container::get('config')->get('app_full_path') . '/views/' . $tplPath . '.html')) {
75
            $tpl = '<!DOCTYPE html>
76
<html lang="en">
77
<head>
78
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
79
  <title>Oops! some error(s) occurred with your application</title>
80
  <meta name="robots" content="NONE,NOARCHIVE">
81
  <style type="text/css">
82
    html * { padding:0; margin:0; }
83
    body * { padding:10px 20px; }
84
    body * * { padding:0; }
85
    body { font-family:Avenir,Helvetica,Arial,sans-serif; -webkit-font-smoothing:antialiased;  -moz-osx-font-smoothing:grayscale;background:#eee; }
86
    body > div { border-bottom:1px solid #ddd; }
87
    h1 { font-weight:normal; color:#5d5d5d;}
88
    h1 span { font-size:60%; color:#666; font-weight:normal; }
89
    table { border-collapse:collapse; width:100%; }
90
    td, th { vertical-align:top; padding:2px 3px; }
91
    th { width:12em; text-align:right; color:#666; padding-right:.5em; }
92
    #info { background:#f6f6f6; }
93
    #info p { font-size:16px; margin:5px; color:#5d5d5d; }
94
    #info strong { font-size:17px; color:#696969; }
95
    #summary { background:#eee; }
96
    #explanation { background:#eee; border-bottom: 0px none; }
97
  </style>
98
</head>
99
<body>
100
  <div id="summary">
101
    <h1>Oops! some error(s) occurred with your application</span></h1>
102
  </div>
103
  <div id="info">
104
    <p><strong>Request Method: </strong>' . strtoupper($_SERVER['REQUEST_METHOD']) . '</p>
105
    <p><strong>Request URL: </strong>' . Container::get('request')->getBaseUrl() . ltrim($_SERVER['REQUEST_URI'], '/') . '</p>
106
      ' . $message . '
107
  </div>
108
109
  <div id="explanation">
110
    <p>
111
      You\'re seeing this error because you have <code>app_debug = True</code> in
112
      your index.php file. Change that to <code>False</code>, and Kotori.php
113
      will display a standard 404 page.
114
    </p>
115
  </div>
116
</body>
117
</html>';
118
        } else {
119
            $tpl = file_get_contents(Container::get('config')->get('app_full_path') . '/views/' . $tplPath . '.html');
120
        }
121
122
        $tpl = str_replace('{$message}', $message, $tpl);
123
        $tpl = HtmlCompress::construct()->compress($tpl);
124
        exit($tpl);
0 ignored issues
show
Coding Style Compatibility introduced by
The method halt() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
125
    }
126
127
    /**
128
     * Error Handler
129
     *
130
     * This function lets us invoke the exception class and
131
     * display errors using the standard error template located
132
     * in app/views/Public/error.html
133
     * This function will send the error page directly to the
134
     * browser and exit.
135
     *
136
     * @param string $errno
137
     * @param int    $errstr
138
     * @param string $errfile
139
     * @param int    $errline
140
     * @return void
141
     */
142
    public static function error($errno, $errstr, $errfile, $errline)
143
    {
144
        $type = self::getErrorType($errno);
145
        $text = self::renderErrorText($type, $errstr, $errline, $errfile);
146
        $txt = self::renderLogBody($type, $errstr, $errline, $errfile);
147
        array_push(self::$errors, $text);
148
        Container::get('logger')->warning($txt);
149
        if (Container::get('request')->isCli()) {
150
            self::outputCliError($errstr);
151
        } else {
152
            self::setDebugHeader($txt);
153
        }
154
    }
155
156
    /**
157
     * Exception Handler
158
     *
159
     * Sends uncaught exceptions to the logger and displays them
160
     * only if display_errors is On so that they don't show up in
161
     * production environments.
162
     *
163
     * @param  Exception $exception
164
     * @return void
165
     */
166
    public static function exception($exception)
167
    {
168
        $text = self::renderHaltBody(get_class($exception), $exception->getMessage(), $exception->getLine(), $exception->getFile());
169
        $txt = self::renderLogBody(get_class($exception), $exception->getMessage(), $exception->getLine(), $exception->getFile());
170
        Container::get('logger')->critical($txt);
171 View Code Duplication
        if (Container::get('request')->isCli()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
172
            self::outputCliError($exception->getMessage());
173
        } else {
174
            self::setDebugHeader($txt);
175
            self::halt($text, Container::get('config')->get('app_debug') ? 500 : 404);
176
        }
177
178
        exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method exception() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
179
    }
180
181
    /**
182
     * Shutdown Handler
183
     *
184
     * This is the shutdown handler that is declared in framework.
185
     * The main reason we use this is to simulate
186
     * a complete custom exception handler.
187
     *
188
     * E_STRICT is purposively neglected because such events may have
189
     * been caught. Duplication or none? None is preferred for now.
190
     *
191
     * @return  void
192
     */
193
    public static function end()
194
    {
195
        $last_error = error_get_last();
196
        if (isset($last_error) &&
197
            ($last_error['type'] & (E_ERROR | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING))) {
198
            $type = self::getErrorType($last_error['type']);
199
            $text = self::renderHaltBody($type, $last_error['message'], $last_error['line'], $last_error['file']);
200
201
            $txt = self::renderLogBody($type, $last_error['message'], $last_error['file'], $last_error['line']);
202
203
            Container::get('logger')->error($txt);
204 View Code Duplication
            if (Container::get('request')->isCli()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
205
                self::outputCliError($last_error['message']);
206
            } else {
207
                self::setDebugHeader($txt);
208
                self::halt($text, Container::get('config')->get('app_debug') ? 500 : 404);
209
            }
210
211
            exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method end() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
212
        }
213
    }
214
215
    /**
216
     * output debug info to header
217
     *
218
     * @param  string $txt
219
     * @return void
220
     */
221
    protected static function setDebugHeader($txt)
222
    {
223
        if (Container::get('config')->get('app_debug')) {
224
            Container::get('response')->setHeader('Kotori-Debug', str_replace("\r\n", ' ', $txt));
225
        }
226
    }
227
228
    /**
229
     * output error info to cli
230
     *
231
     * @param  string $message
232
     * @return void
233
     */
234
    protected static function outputCliError($message)
235
    {
236
        $application = new ConsoleApp();
237
        $output = new ConsoleOutput();
238
        $application->renderException(new ResponseException($message), $output);
239
    }
240
241
    /**
242
     * convert PHP ERROR to error detail
243
     *
244
     * @param  int $errno
245
     * @return string
246
     */
247
    protected static function getErrorType($errno)
248
    {
249
        switch ($errno) {
250
            case E_ERROR:
251
                $errtype = 'A fatal error that causes script termination.';
252
                break;
253
            case E_WARNING:
254
                $errtype = 'Run-time warning that does not cause script termination.';
255
                break;
256
            case E_PARSE:
257
                $errtype = 'Compile time parse error.';
258
                break;
259
            case E_NOTICE:
260
                $errtype = 'Run time notice caused due to error in code.';
261
                break;
262
            case E_CORE_ERROR:
263
                $errtype = 'Fatal errors that occur during PHP\'s initial startup (installation).';
264
                break;
265
            case E_CORE_WARNING:
266
                $errtype = 'Warnings that occur during PHP\'s initial startup.';
267
                break;
268
            case E_COMPILE_ERROR:
269
                $errtype = 'Fatal compile-time errors indication problem with script.';
270
                break;
271
            case E_COMPILE_WARNING:
272
                $errtype = 'Non-Fatal Run Time Warning generated by Zend Engine.';
273
                break;
274
            case E_USER_ERROR:
275
                $errtype = 'User-generated error message.';
276
                break;
277
            case E_USER_WARNING:
278
                $errtype = 'User-generated warning message.';
279
                break;
280
            case E_USER_NOTICE:
281
                $errtype = 'User-generated notice message.';
282
                break;
283
            case E_STRICT:
284
                $errtype = 'Run-time notices.';
285
                break;
286
            case E_RECOVERABLE_ERROR:
287
                $errtype = 'Catchable fatal error indicating a dangerous error.';
288
                break;
289
            default:
290
                $errtype = 'Unknown';
291
                break;
292
        }
293
294
        return $errtype;
295
    }
296
297
    /**
298
     * render Halt Body
299
     *
300
     * @param  string $type
301
     * @param  int    $message
302
     * @param  int    $line
303
     * @param  string $file
304
     * @return string
305
     */
306
    protected static function renderHaltBody($type, $message, $line, $file)
307
    {
308
        $text = '<p><strong>Error Type: </strong>' . $type . '</p>' . '<p><strong>Info: </strong>' . nl2br($message) . '</p>' . '<p><strong>Line: </strong>' . $line . '</p>' . '<p><strong>File: </strong>' . $file . '</p>';
309
        $source = self::getSourceCode($file, $line);
310
311
        $sourceLen = strlen(strval(count($source['source']) + $source['first']));
312
        $padding = 40 + ($sourceLen - 1) * 8;
313
        if (!empty($source)) {
314
            $text .= '<style>' . file_get_contents(Helper::getComposerVendorPath() . '/scrivo/highlight.php/styles/github.css') . '</style>';
315
            $text .= '<style>
316
.source-code {
317
    padding: 6px;
318
    border: 1px solid #ddd;
319
    background: #f9f9f9;
320
    overflow-x: auto;
321
}
322
323
.source-code pre {
324
    margin: 0;
325
}
326
327
.source-code pre ol {
328
    margin: 0;
329
    color: #4288ce;
330
    display: inline-block;
331
    min-width: 100%;
332
    box-sizing: border-box;
333
    font-size: 14px;
334
    font-family: Menlo,Monaco,Consolas,"Courier New",monospace;
335
    padding-left: ' . $padding . 'px;
336
}
337
338
.source-code pre li {
339
    border-left: 1px solid #ddd;
340
    height: 18px;
341
    line-height: 18px;
342
}
343
344
.source-code pre code {
345
    color: #333;
346
    height: 100%;
347
    display: inline-block;
348
    border-left: 1px solid #fff;
349
    font-size: 14px;
350
    font-family: Menlo,Monaco,Consolas,"Courier New",monospace;
351
}
352
353
.source-code pre li.line-error {
354
    background: #f8cbcb;
355
}
356
357
</style>';
358
            $text .= '<div class="source-code">
359
<pre id="code-block" class="hljs language-php">
360
    <ol start="' . $source['first'] . '">';
361
            $highlighter = new Highlighter();
362
            foreach ($source['source'] as $key => $value) {
363
                $currentLine = $key + $source['first'];
364
                $extendClass = ($currentLine == $line) ? ' line-error' : '';
365
                $text .= '<li class="line-' . $currentLine . $extendClass . '"><code>' . $highlighter->highlight('php', $value)->value . '</code></li>';
366
            }
367
368
            $text .= '</ol></pre></div>';
369
        }
370
371
        return $text;
372
    }
373
374
    /**
375
     * render log body
376
     *
377
     * @param  string $type
378
     * @param  int    $message
379
     * @param  string $file
380
     * @param  int    $line
381
     * @return string
382
     */
383
    protected static function renderLogBody($type, $message, $line, $file)
384
    {
385
        return '[Type] ' . $type . "\r\n" . '[Info] ' . $message . "\r\n" . '[Line] ' . $line . "\r\n" . '[File] ' . $file;
386
    }
387
388
    /**
389
     * render errors display in trace
390
     *
391
     * @param  string $type
392
     * @param  int $message
393
     * @param  string $file
394
     * @param  int $line
395
     * @return string
396
     */
397
    // @codingStandardsIgnoreStart
398
    protected static function renderErrorText($type, $message, $line, $file)
0 ignored issues
show
Unused Code introduced by
The parameter $type is not used and could be removed.

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

Loading history...
399
    {
400
        return $message . ' in ' . $file . ' on line ' . $line;
401
    }
402
    // @codingStandardsIgnoreEnd
403
404
    /**
405
     * Get source code from file
406
     *
407
     * @param  string $file
408
     * @param  int    $line
409
     * @return array
410
     */
411
    protected static function getSourceCode($file, $line)
412
    {
413
        $first = ($line - 9 > 0) ? $line - 9 : 1;
414
415
        try {
416
            $contents = file($file);
417
            $source = [
418
                'first' => $first,
419
                'source' => array_slice($contents, $first - 1, 19),
420
            ];
421
        } catch (Exception $e) {
422
            $source = [];
423
        }
424
425
        return $source;
426
    }
427
}
428