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.
Completed
Push — master ( f8be1c...07c7d5 )
by やかみ
03:38
created

src/Http/Route.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
 * Route class
26
 *
27
 * Parses URIs and determines routing
28
 *
29
 * @package     Kotori
30
 * @subpackage  Http
31
 * @author      Kokororin
32
 * @link        https://kotori.love
33
 */
34
namespace Kotori\Http;
35
36
use Kotori\Core\Container;
37
use Kotori\Core\Helper;
38
use Kotori\Core\Middleware;
39
use Kotori\Debug\Hook;
40
use Kotori\Exception\ConfigException;
41
use Kotori\Exception\NotFoundException;
42
use Kotori\Exception\RouteNotFoundException;
43
use ReflectionClass;
44
use Symfony\Component\Finder\Finder;
45
use zpt\anno\Annotations;
46
47
class Route
48
{
49
    /**
50
     * Controllers Array
51
     *
52
     * @var array
53
     */
54
    protected $controllers = [];
55
56
    /**
57
     * Current controller
58
     *
59
     * @var string
60
     */
61
    protected $controller;
62
63
    /**
64
     * Current action
65
     *
66
     * @var string
67
     */
68
    protected $action;
69
70
    /**
71
     * Current URI string
72
     *
73
     * @var mixed
74
     */
75
    protected $uri = '';
76
77
    /**
78
     * Parsed URI Array
79
     *
80
     * @var array
81
     */
82
    protected $uris = [];
83
84
    /**
85
     * Parsed params
86
     *
87
     * @var array
88
     */
89
    protected $params = [];
90
91
    /**
92
     * Class constructor
93
     *
94
     * Initialize route class.
95
     *
96
     * @return void
97
     */
98 1
    public function __construct()
99
    {
100 1
        if (Container::get('request')->isCli()) {
101 1
            $this->uri = $this->parseArgv();
102
        } else {
103
            if (isset($_GET['_i'])) {
104
                $_SERVER['PATH_INFO'] = $_GET['_i'];
105
            }
106
107
            $_SERVER['PATH_INFO'] = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO']
108
            : (isset($_SERVER['ORIG_PATH_INFO']) ? $_SERVER['ORIG_PATH_INFO']
109
                : (isset($_SERVER['REDIRECT_PATH_INFO']) ? $_SERVER['REDIRECT_PATH_INFO'] : ''));
110
111
            $this->uri = $_SERVER['PATH_INFO'];
112
        }
113
114 1
        if (substr($this->uri, 0, 1) == '/') {
115
            $this->uri = ltrim($this->uri, '/');
116
        }
117
118 1
        if (trim($this->uri, '/') == '') {
119
            $this->uri = '/';
120
        }
121
122 1
        Hook::listen(__CLASS__);
123 1
    }
124
125
    /**
126
     * Map URL to controller and action
127
     *
128
     * @return void
129
     *
130
     * @throws \Kotori\Exception\RouteNotFoundException
131
     * @throws \Kotori\Exception\NotFoundException
132
     */
133
    public function dispatch()
134
    {
135
        if (strtolower(Container::get('config')->get('url_mode')) == 'query_string') {
136
            $this->uri = explode('?', $this->uri, 2);
137
            $_SERVER['QUERY_STRING'] = isset($this->uri[1]) ? $this->uri[1] : '';
138
            $this->uri = $this->uri[0];
139
            parse_str($_SERVER['QUERY_STRING'], $_GET);
140
        }
141
142
        if ($this->uri == 'favicon.ico') {
143
            return Container::get('response')->setStatus(404);
144
        }
145
146
        Middleware::register('before_route');
147
        $parsedRoute = $this->parseRoutes($this->uri);
148
        Middleware::register('after_route');
149
150
        if ($parsedRoute) {
151
            $this->uri = $parsedRoute;
152
        } else {
153
            if (Container::get('request')->isOptions()) {
154
                Container::get('response')->setStatus(204);
155
                exit;
156
            }
157
158
            throw new RouteNotFoundException('Request URI ' . $this->uri . ' is not Matched by any route.');
159
        }
160
161
        $this->uris = ($this->uri != '') ? explode('/', trim($this->uri, '/')) : [];
162
163
        // Clean uris
164
        foreach ($this->uris as $key => $value) {
165
            if ($value == '') {
166
                unset($this->uris[$key]);
167
            }
168
        }
169
170
        $this->uris = array_merge($this->uris);
171
172
        $this->controller = $this->getController();
173
        $this->action = $this->getAction();
174
175
        // If is already initialized
176
        $prefix = Container::get('config')->get('namespace_prefix');
177
178
        $controllerClassName = $prefix . 'controllers\\' . $this->controller;
179
180
        Middleware::register('before_controller');
181
182
        if (isset($this->controllers[$this->controller])) {
183
            $class = $this->controllers[$this->controller];
184
        } else {
185
            $class = new $controllerClassName();
186
            $this->controllers[$this->controller] = $class;
187
        }
188
189
        Middleware::register('after_controller');
190
191
        if (!class_exists($controllerClassName)) {
192
            throw new NotFoundException('Request Controller ' . $this->controller . ' is not Found.');
193
        }
194
195
        if (!method_exists($class, $this->action)) {
196
            throw new NotFoundException('Request Action ' . $this->action . ' is not Found.');
197
        }
198
199
        $callback = [$class, $this->action];
200
        if (!is_callable($callback)) {
201
            throw new NotFoundException($controllerClassName . '::' . $this->action . '() is not callable');
202
        }
203
204
        // Parse params from uri
205
        $this->params = $this->getParams();
206
207
        // Do some final cleaning of the params
208
        $_GET = array_merge($this->params, $_GET);
209
        $_REQUEST = array_merge($_POST, $_GET, $_COOKIE);
210
211
        if (Container::get('config')->get('app_debug')) {
212
            Container::get('response')->setHeader('X-Kotori-Hash', call_user_func(function () {
213
                $lockFile = Helper::getComposerVendorPath() . '/../composer.lock';
214
                if (!Helper::isFile($lockFile)) {
215
                    return 'unknown';
216
                } else {
217
                    $lockData = file_get_contents($lockFile);
218
                    $lockData = json_decode($lockData, true);
219
                    foreach ($lockData['packages'] as $package) {
220
                        if ($package['name'] == 'kokororin/kotori-php') {
221
                            return substr($package['source']['reference'], 0, 6);
222
                        }
223
                    }
224
                }
225
226
                return 'unknown';
227
            }));
228
        }
229
230
        Middleware::register('before_action');
231
        // Call the requested method
232
        call_user_func_array($callback, $this->params);
233
        Middleware::register('after_action');
234
    }
235
236
    /**
237
     * Returns the controller name
238
     *
239
     * @return      string
240
     *
241
     * @throws \Kotori\Exception\NotFoundException
242
     */
243
    public function getController()
244
    {
245
        if (isset($this->uris[0]) && '' !== $this->uris[0]) {
246
            $_controller = $this->uris[0];
247
        } else {
248
            throw new NotFoundException('Cannot dispatch controller name.');
249
        }
250
251
        return strip_tags($_controller);
252
    }
253
254
    /**
255
     * Returns the action name
256
     *
257
     * @return      string
258
     *
259
     * @throws \Kotori\Exception\NotFoundException
260
     */
261
    public function getAction()
262
    {
263
        if (isset($this->uris[1])) {
264
            $_action = $this->uris[1];
265
        } else {
266
            throw new NotFoundException('Cannot dispatch action name.');
267
        }
268
269
        return strip_tags($_action);
270
    }
271
272
    /**
273
     * Returns the request params
274
     *
275
     * @return array
276
     */
277
    public function getParams()
278
    {
279
        $params = $this->uris;
280
        unset($params[0], $params[1]);
281
        return array_merge($params);
282
    }
283
284
    /**
285
     * Returns the URI
286
     *
287
     * @return string
288
     */
289
    public function getUri()
290
    {
291
        return $this->uri;
292
    }
293
294
    /**
295
     * Parse Routes
296
     *
297
     * Matches any routes that may exist in URL_ROUTE array
298
     * against the URI to determine if the class/method need to be remapped.
299
     *
300
     * @param  string $uri
301
     * @return string
302
     */
303
    protected function parseRoutes($uri)
304
    {
305
        if (Container::get('config')->get('url_route_annotation')) {
306
            $finder = new Finder();
307
            $finder
308
                ->in(Container::get('config')->get('app_full_path') . '/controllers')
309
                ->name('*.php');
310
            $controllerNamespaces = [];
311
            $routes = [];
312
            foreach ($finder as $file) {
313
                array_push($controllerNamespaces, '\\' . Container::get('config')->get('namespace_prefix') . 'controllers\\' . $file->getBasename('.' . $file->getExtension()));
314
            }
315
316
            foreach ($controllerNamespaces as $namespace) {
317
                $classReflector = new ReflectionClass($namespace);
318
                $classAnnotations = new Annotations($classReflector);
0 ignored issues
show
$classAnnotations is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
319
320
                foreach ($classReflector->getMethods() as $methodReflector) {
321
                    $methodAnnotations = new Annotations($methodReflector);
322
                    if (!isset($methodAnnotations['route'])) {
323
                        continue;
324
                    } else {
325
                        $routeAnnotations = $methodAnnotations['route'];
326
                        if (!isset($routeAnnotations['uri'])) {
327
                            throw new ConfigException('Route annotations error');
328
                        }
329
330
                        $controllerName = $classReflector->getShortName();
331
                        $actionName = $methodReflector->getName();
0 ignored issues
show
Consider using $methodReflector->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
332
                        $route = $controllerName . '/' . $actionName;
333
                        if (isset($routeAnnotations['regexp'])) {
334
                            $route .= '/' . $routeAnnotations['regexp'];
335
                        }
336
337
                        if (!isset($routeAnnotations['method'])) {
338
                            $routes[$routeAnnotations['uri']] = $route;
339
                        } else {
340
                            $routes[$routeAnnotations['uri']][$routeAnnotations['method']] = $route;
341
                        }
342
343
                        unset($route);
344
                    }
345
                }
346
            }
347
        } else {
348
            $routes = Container::get('config')->get('url_route');
349
        }
350
351
        $hostName = Container::get('request')->getHostName();
352
353
        if (isset($routes[$hostName])) {
354
            $routes = $routes[$hostName];
355
        }
356
357
        // Get HTTP verb
358
        $httpVerb = isset($_SERVER['REQUEST_METHOD']) ? strtolower($_SERVER['REQUEST_METHOD']) : 'cli';
359
360
        if (null != $routes) {
361
            foreach ($routes as $key => $val) {
362
                // Check if route format is using HTTP verbs
363
                if (is_array($val)) {
364
                    $val = array_change_key_case($val, CASE_LOWER);
365
                    if (isset($val[$httpVerb])) {
366
                        $val = $val[$httpVerb];
367
                    } else {
368
                        continue;
369
                    }
370
                }
371
372
                // Does the RegEx match?
373
                if (preg_match('#^' . $key . '$#', $uri, $matches)) {
374
                    // Are we using callbacks to process back-references?
375
                    if (!is_string($val) && is_callable($val)) {
376
                        // Remove the original string from the matches array.
377
                        array_shift($matches);
378
379
                        // Execute the callback using the values in matches as its parameters.
380
                        $val = call_user_func_array($val, $matches);
381
                    }
382
                    // Are we using the default routing method for back-references?
383
                    elseif (strpos($val, '$') !== false && strpos($key, '(') !== false) {
384
                        $val = preg_replace('#^' . $key . '$#', $val, $uri);
385
                    }
386
387
                    return $val;
388
                }
389
            }
390
        }
391
392
    }
393
394
    /**
395
     * Parse CLI arguments
396
     *
397
     * Take each command line argument and assume it is a URI segment.
398
     *
399
     * @return  string
400
     */
401 1
    protected function parseArgv()
402
    {
403 1
        $args = array_slice($_SERVER['argv'], 1);
404 1
        return $args ? implode('/', $args) : '';
405
    }
406
407
    /**
408
     * Build Full URL
409
     *
410
     * @param  string $uri
411
     * @param  string $module
412
     * @return string
413
     *
414
     * @throws \Kotori\Exception\ConfigException
415
     */
416
    public function url($uri = '', $module = null)
417
    {
418
        if ($module != null) {
419
            $appNames = Container::get('config')->get('app_name');
420
            if (is_array($appNames)) {
421
                foreach ($appNames as &$appName) {
422
                    $appName = str_replace('./', '', $appName);
423
                }
424
425
                $appNames = array_flip($appNames);
426
                $baseUrl = $appNames[$module];
427
                $baseUrl = '//' . $baseUrl . '/';
428
            }
429
        } else {
430
            $baseUrl = Container::get('request')->getBaseUrl();
431
        }
432
433
        $uri = is_array($uri) ? implode('/', $uri) : trim($uri, '/');
434
        $prefix = $baseUrl . 'index.php?_i=';
435
436
        switch (strtolower(Container::get('config')->get('url_mode'))) {
437
            case 'path_info':
438
                return $uri == '' ? rtrim($baseUrl, '/') : $baseUrl . $uri;
439
            case 'query_string':
440
                return $uri == '' ? rtrim($baseUrl, '/') : $prefix . $uri;
441
            default:
442
                throw new ConfigException('`url_mode` Config ERROR');
443
        }
444
445
    }
446
447
}
448