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 ( 9bdeaa...17400b )
by やかみ
03:43
created

Route::getRoutes()   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 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 4
ccs 0
cts 2
cp 0
crap 2
rs 10
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
     * Parsed routes
93
     *
94
     * @var array
95
     */
96
    protected $routes = [];
97
98
    /**
99
     * Class constructor
100
     *
101
     * Initialize route class.
102
     *
103
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
104
     */
105 1
    public function __construct()
0 ignored issues
show
Coding Style introduced by
__construct uses the super-global variable $_GET 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...
Coding Style introduced by
__construct 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...
106
    {
107 1
        if (Container::get('request')->isCli()) {
108 1
            $this->uri = $this->parseArgv();
109
        } else {
110
            if (isset($_GET['_i'])) {
111
                $_SERVER['PATH_INFO'] = $_GET['_i'];
112
            }
113
114
            $_SERVER['PATH_INFO'] = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO']
115
            : (isset($_SERVER['ORIG_PATH_INFO']) ? $_SERVER['ORIG_PATH_INFO']
116
                : (isset($_SERVER['REDIRECT_PATH_INFO']) ? $_SERVER['REDIRECT_PATH_INFO'] : ''));
117
118
            $this->uri = $_SERVER['PATH_INFO'];
119
        }
120
121 1
        if (substr($this->uri, 0, 1) == '/') {
122
            $this->uri = ltrim($this->uri, '/');
123
        }
124
125 1
        if (trim($this->uri, '/') == '') {
126
            $this->uri = '/';
127
        }
128
129 1
        Hook::listen(__CLASS__);
130 1
    }
131
132
    /**
133
     * Map URL to controller and action
134
     *
135
     * @return void
136
     *
137
     * @throws \Kotori\Exception\RouteNotFoundException
138
     * @throws \Kotori\Exception\NotFoundException
139
     */
140
    public function dispatch()
0 ignored issues
show
Coding Style introduced by
dispatch 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...
Coding Style introduced by
dispatch uses the super-global variable $_GET 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...
Coding Style introduced by
dispatch uses the super-global variable $_REQUEST 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...
Coding Style introduced by
dispatch uses the super-global variable $_POST 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...
Coding Style introduced by
dispatch uses the super-global variable $_COOKIE 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...
141
    {
142
        if (strtolower(Container::get('config')->get('url_mode')) == 'query_string') {
143
            $this->uri = explode('?', $this->uri, 2);
144
            $_SERVER['QUERY_STRING'] = isset($this->uri[1]) ? $this->uri[1] : '';
145
            $this->uri = $this->uri[0];
146
            parse_str($_SERVER['QUERY_STRING'], $_GET);
147
        }
148
149
        if ($this->uri == 'favicon.ico') {
150
            return Container::get('response')->setStatus(404);
151
        }
152
153
        Middleware::register('before_route');
154
        $parsedRoute = $this->parseRoutes($this->uri);
155
        Middleware::register('after_route');
156
157
        if ($parsedRoute) {
158
            $this->uri = $parsedRoute;
159
        } else {
160
            if (Container::get('request')->isOptions()) {
161
                Container::get('response')->setStatus(204);
162
                exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method dispatch() 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...
163
            }
164
165
            throw new RouteNotFoundException('Request URI ' . $this->uri . ' is not Matched by any route.');
166
        }
167
168
        $this->uris = ($this->uri != '') ? explode('/', trim($this->uri, '/')) : [];
169
170
        // Clean uris
171
        foreach ($this->uris as $key => $value) {
172
            if ($value == '') {
173
                unset($this->uris[$key]);
174
            }
175
        }
176
177
        $this->uris = array_merge($this->uris);
178
179
        $this->controller = $this->getController();
180
        $this->action = $this->getAction();
181
182
        // If is already initialized
183
        $prefix = Container::get('config')->get('namespace_prefix');
184
185
        $controllerClassName = $prefix . 'controllers\\' . $this->controller;
186
187
        Middleware::register('before_controller');
188
189
        if (isset($this->controllers[$this->controller])) {
190
            $class = $this->controllers[$this->controller];
191
        } else {
192
            $class = new $controllerClassName();
193
            $this->controllers[$this->controller] = $class;
194
        }
195
196
        Middleware::register('after_controller');
197
198
        if (!class_exists($controllerClassName)) {
199
            throw new NotFoundException('Request Controller ' . $this->controller . ' is not Found.');
200
        }
201
202
        if (!method_exists($class, $this->action)) {
203
            throw new NotFoundException('Request Action ' . $this->action . ' is not Found.');
204
        }
205
206
        $callback = [$class, $this->action];
207
        if (!is_callable($callback)) {
208
            throw new NotFoundException($controllerClassName . '::' . $this->action . '() is not callable');
209
        }
210
211
        // Parse params from uri
212
        $this->params = $this->getParams();
213
214
        // Do some final cleaning of the params
215
        $_GET = array_merge($this->params, $_GET);
216
        $_REQUEST = array_merge($_POST, $_GET, $_COOKIE);
217
218
        if (Container::get('config')->get('app_debug')) {
219
            Container::get('response')->setHeader('X-Kotori-Hash', call_user_func(function () {
220
                $lockFile = Helper::getComposerVendorPath() . '/../composer.lock';
221
                if (!Helper::isFile($lockFile)) {
222
                    return 'unknown';
223
                } else {
224
                    $lockData = file_get_contents($lockFile);
225
                    $lockData = json_decode($lockData, true);
226
                    foreach ($lockData['packages'] as $package) {
227
                        if ($package['name'] == 'kokororin/kotori-php') {
228
                            return substr($package['source']['reference'], 0, 6);
229
                        }
230
                    }
231
                }
232
233
                return 'unknown';
234
            }));
235
        }
236
237
        Middleware::register('before_action');
238
        // Call the requested method
239
        call_user_func_array($callback, $this->params);
240
        Middleware::register('after_action');
241
    }
242
243
    /**
244
     * Returns the controller name
245
     *
246
     * @return      string
247
     *
248
     * @throws \Kotori\Exception\NotFoundException
249
     */
250
    public function getController()
251
    {
252
        if (isset($this->uris[0]) && '' !== $this->uris[0]) {
253
            $_controller = $this->uris[0];
254
        } else {
255
            throw new NotFoundException('Cannot dispatch controller name.');
256
        }
257
258
        return strip_tags($_controller);
259
    }
260
261
    /**
262
     * Returns the action name
263
     *
264
     * @return      string
265
     *
266
     * @throws \Kotori\Exception\NotFoundException
267
     */
268
    public function getAction()
269
    {
270
        if (isset($this->uris[1])) {
271
            $_action = $this->uris[1];
272
        } else {
273
            throw new NotFoundException('Cannot dispatch action name.');
274
        }
275
276
        return strip_tags($_action);
277
    }
278
279
    /**
280
     * Returns the request params
281
     *
282
     * @return array
283
     */
284
    public function getParams()
285
    {
286
        $params = $this->uris;
287
        unset($params[0], $params[1]);
288
        return array_merge($params);
289
    }
290
291
    /**
292
     * Returns the URI
293
     *
294
     * @return string
295
     */
296
    public function getUri()
297
    {
298
        return $this->uri;
299
    }
300
301
    /**
302
     * Returns routes
303
     *
304
     * @return array
305
     */
306
    public function getRoutes()
307
    {
308
        return $this->routes;
309
    }
310
311
    /**
312
     * Parse Routes
313
     *
314
     * Matches any routes that may exist in URL_ROUTE array
315
     * against the URI to determine if the class/method need to be remapped.
316
     *
317
     * @param  string $uri
318
     * @return string
319
     */
320
    protected function parseRoutes($uri)
0 ignored issues
show
Coding Style introduced by
parseRoutes 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...
321
    {
322
        if (Container::get('config')->get('url_route_annotation')) {
323
            $finder = new Finder();
324
            $finder
325
                ->in(Container::get('config')->get('app_full_path') . '/controllers')
326
                ->name('*.php');
327
            $controllerNamespaces = [];
328
            foreach ($finder as $file) {
329
                array_push($controllerNamespaces, '\\' . Container::get('config')->get('namespace_prefix') . 'controllers\\' . $file->getBasename('.' . $file->getExtension()));
330
            }
331
332
            foreach ($controllerNamespaces as $namespace) {
333
                $classReflector = new ReflectionClass($namespace);
334
                $classAnnotations = new Annotations($classReflector);
0 ignored issues
show
Unused Code introduced by
$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...
335
336
                foreach ($classReflector->getMethods() as $methodReflector) {
337
                    $methodAnnotations = new Annotations($methodReflector);
338
                    if (!isset($methodAnnotations['route'])) {
339
                        continue;
340
                    } else {
341
                        $routeAnnotations = $methodAnnotations['route'];
342
                        if (!isset($routeAnnotations['uri'])) {
343
                            throw new ConfigException('Route annotations error');
344
                        }
345
346
                        $controllerName = $classReflector->getShortName();
347
                        $actionName = $methodReflector->getName();
0 ignored issues
show
Bug introduced by
Consider using $methodReflector->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
348
                        $route = $controllerName . '/' . $actionName;
349
                        if (isset($routeAnnotations['params'])) {
350
                            $route .= '/' . $routeAnnotations['params'];
351
                        }
352
353
                        if (!isset($routeAnnotations['method'])) {
354
                            $this->routes[$routeAnnotations['uri']] = $route;
355
                        } else {
356
                            $this->routes[$routeAnnotations['uri']][$routeAnnotations['method']] = $route;
357
                        }
358
359
                        unset($route);
360
                    }
361
                }
362
            }
363
        } else {
364
            $this->routes = Container::get('config')->get('url_route');
365
        }
366
367
        $hostName = Container::get('request')->getHostName();
368
369
        if (isset($this->routes[$hostName])) {
370
            $this->routes = $this->routes[$hostName];
371
        }
372
373
        // Get HTTP verb
374
        $httpVerb = isset($_SERVER['REQUEST_METHOD']) ? strtolower($_SERVER['REQUEST_METHOD']) : 'cli';
375
376
        if (null != $this->routes) {
377
            foreach ($this->routes as $key => $val) {
378
                // Check if route format is using HTTP verbs
379
                if (is_array($val)) {
380
                    $val = array_change_key_case($val, CASE_LOWER);
381
                    if (isset($val[$httpVerb])) {
382
                        $val = $val[$httpVerb];
383
                    } else {
384
                        continue;
385
                    }
386
                }
387
388
                // Does the RegEx match?
389
                if (preg_match('#^' . $key . '$#', $uri, $matches)) {
390
                    // Are we using callbacks to process back-references?
391
                    if (!is_string($val) && is_callable($val)) {
392
                        // Remove the original string from the matches array.
393
                        array_shift($matches);
394
395
                        // Execute the callback using the values in matches as its parameters.
396
                        $val = call_user_func_array($val, $matches);
397
                    }
398
                    // Are we using the default routing method for back-references?
399
                    elseif (strpos($val, '$') !== false && strpos($key, '(') !== false) {
400
                        $val = preg_replace('#^' . $key . '$#', $val, $uri);
401
                    }
402
403
                    return $val;
404
                }
405
            }
406
        }
407
408
    }
409
410
    /**
411
     * Parse CLI arguments
412
     *
413
     * Take each command line argument and assume it is a URI segment.
414
     *
415
     * @return  string
416
     */
417 1
    protected function parseArgv()
0 ignored issues
show
Coding Style introduced by
parseArgv 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...
418
    {
419 1
        $args = array_slice($_SERVER['argv'], 1);
420 1
        return $args ? implode('/', $args) : '';
421
    }
422
423
    /**
424
     * Build Full URL
425
     *
426
     * @param  string $uri
427
     * @param  string $module
428
     * @return string
429
     *
430
     * @throws \Kotori\Exception\ConfigException
431
     */
432
    public function url($uri = '', $module = null)
433
    {
434
        if ($module != null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $module of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
435
            $appNames = Container::get('config')->get('app_name');
436
            if (is_array($appNames)) {
437
                foreach ($appNames as &$appName) {
438
                    $appName = str_replace('./', '', $appName);
439
                }
440
441
                $appNames = array_flip($appNames);
442
                $baseUrl = $appNames[$module];
443
                $baseUrl = '//' . $baseUrl . '/';
444
            }
445
        } else {
446
            $baseUrl = Container::get('request')->getBaseUrl();
447
        }
448
449
        $uri = is_array($uri) ? implode('/', $uri) : trim($uri, '/');
450
        $prefix = $baseUrl . 'index.php?_i=';
0 ignored issues
show
Bug introduced by
The variable $baseUrl does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
451
452
        switch (strtolower(Container::get('config')->get('url_mode'))) {
453
            case 'path_info':
454
                return $uri == '' ? rtrim($baseUrl, '/') : $baseUrl . $uri;
455
            case 'query_string':
456
                return $uri == '' ? rtrim($baseUrl, '/') : $prefix . $uri;
457
            default:
458
                throw new ConfigException('`url_mode` Config ERROR');
459
        }
460
461
    }
462
463
}
464