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 ( cd2d3a...6886d6 )
by Robert
09:38
created

UrlManager::init()   D

Complexity

Conditions 9
Paths 14

Size

Total Lines 27
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 13.4798

Importance

Changes 0
Metric Value
dl 0
loc 27
rs 4.909
c 0
b 0
f 0
ccs 13
cts 21
cp 0.619
cc 9
eloc 18
nc 14
nop 0
crap 13.4798
1
<?php
2
/**
3
 * @link http://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license http://www.yiiframework.com/license/
6
 */
7
8
namespace yii\web;
9
10
use Yii;
11
use yii\base\Component;
12
use yii\base\InvalidConfigException;
13
use yii\caching\Cache;
14
use yii\di\Instance;
15
16
/**
17
 * UrlManager handles HTTP request parsing and creation of URLs based on a set of rules.
18
 *
19
 * UrlManager is configured as an application component in [[\yii\base\Application]] by default.
20
 * You can access that instance via `Yii::$app->urlManager`.
21
 *
22
 * You can modify its configuration by adding an array to your application config under `components`
23
 * as it is shown in the following example:
24
 *
25
 * ```php
26
 * 'urlManager' => [
27
 *     'enablePrettyUrl' => true,
28
 *     'rules' => [
29
 *         // your rules go here
30
 *     ],
31
 *     // ...
32
 * ]
33
 * ```
34
 *
35
 * @property string $baseUrl The base URL that is used by [[createUrl()]] to prepend to created URLs.
36
 * @property string $hostInfo The host info (e.g. "http://www.example.com") that is used by
37
 * [[createAbsoluteUrl()]] to prepend to created URLs.
38
 * @property string $scriptUrl The entry script URL that is used by [[createUrl()]] to prepend to created
39
 * URLs.
40
 *
41
 * @author Qiang Xue <[email protected]>
42
 * @since 2.0
43
 */
44
class UrlManager extends Component
45
{
46
    /**
47
     * @var boolean whether to enable pretty URLs. Instead of putting all parameters in the query
48
     * string part of a URL, pretty URLs allow using path info to represent some of the parameters
49
     * and can thus produce more user-friendly URLs, such as "/news/Yii-is-released", instead of
50
     * "/index.php?r=news%2Fview&id=100".
51
     */
52
    public $enablePrettyUrl = false;
53
    /**
54
     * @var boolean whether to enable strict parsing. If strict parsing is enabled, the incoming
55
     * requested URL must match at least one of the [[rules]] in order to be treated as a valid request.
56
     * Otherwise, the path info part of the request will be treated as the requested route.
57
     * This property is used only when [[enablePrettyUrl]] is `true`.
58
     */
59
    public $enableStrictParsing = false;
60
    /**
61
     * @var array the rules for creating and parsing URLs when [[enablePrettyUrl]] is `true`.
62
     * This property is used only if [[enablePrettyUrl]] is `true`. Each element in the array
63
     * is the configuration array for creating a single URL rule. The configuration will
64
     * be merged with [[ruleConfig]] first before it is used for creating the rule object.
65
     *
66
     * A special shortcut format can be used if a rule only specifies [[UrlRule::pattern|pattern]]
67
     * and [[UrlRule::route|route]]: `'pattern' => 'route'`. That is, instead of using a configuration
68
     * array, one can use the key to represent the pattern and the value the corresponding route.
69
     * For example, `'post/<id:\d+>' => 'post/view'`.
70
     *
71
     * For RESTful routing the mentioned shortcut format also allows you to specify the
72
     * [[UrlRule::verb|HTTP verb]] that the rule should apply for.
73
     * You can do that  by prepending it to the pattern, separated by space.
74
     * For example, `'PUT post/<id:\d+>' => 'post/update'`.
75
     * You may specify multiple verbs by separating them with comma
76
     * like this: `'POST,PUT post/index' => 'post/create'`.
77
     * The supported verbs in the shortcut format are: GET, HEAD, POST, PUT, PATCH and DELETE.
78
     * Note that [[UrlRule::mode|mode]] will be set to PARSING_ONLY when specifying verb in this way
79
     * so you normally would not specify a verb for normal GET request.
80
     *
81
     * Here is an example configuration for RESTful CRUD controller:
82
     *
83
     * ```php
84
     * [
85
     *     'dashboard' => 'site/index',
86
     *
87
     *     'POST <controller:[\w-]+>s' => '<controller>/create',
88
     *     '<controller:[\w-]+>s' => '<controller>/index',
89
     *
90
     *     'PUT <controller:[\w-]+>/<id:\d+>'    => '<controller>/update',
91
     *     'DELETE <controller:[\w-]+>/<id:\d+>' => '<controller>/delete',
92
     *     '<controller:[\w-]+>/<id:\d+>'        => '<controller>/view',
93
     * ];
94
     * ```
95
     *
96
     * Note that if you modify this property after the UrlManager object is created, make sure
97
     * you populate the array with rule objects instead of rule configurations.
98
     */
99
    public $rules = [];
100
    /**
101
     * @var string the URL suffix used when [[enablePrettyUrl]] is `true`.
102
     * For example, ".html" can be used so that the URL looks like pointing to a static HTML page.
103
     * This property is used only if [[enablePrettyUrl]] is `true`.
104
     */
105
    public $suffix;
106
    /**
107
     * @var boolean whether to show entry script name in the constructed URL. Defaults to `true`.
108
     * This property is used only if [[enablePrettyUrl]] is `true`.
109
     */
110
    public $showScriptName = true;
111
    /**
112
     * @var string the GET parameter name for route. This property is used only if [[enablePrettyUrl]] is `false`.
113
     */
114
    public $routeParam = 'r';
115
    /**
116
     * @var Cache|string the cache object or the application component ID of the cache object.
117
     * Compiled URL rules will be cached through this cache object, if it is available.
118
     *
119
     * After the UrlManager object is created, if you want to change this property,
120
     * you should only assign it with a cache object.
121
     * Set this property to `false` if you do not want to cache the URL rules.
122
     */
123
    public $cache = 'cache';
124
    /**
125
     * @var array the default configuration of URL rules. Individual rule configurations
126
     * specified via [[rules]] will take precedence when the same property of the rule is configured.
127
     */
128
    public $ruleConfig = ['class' => 'yii\web\UrlRule'];
129
    /**
130
     * @var UrlNormalizer|array|string|false the configuration for [[UrlNormalizer]] used by this UrlManager.
131
     * The default value is `false`, which means normalization will be skipped.
132
     * If you wish to enable URL normalization, you should configure this property manually.
133
     * For example:
134
     *
135
     * ```php
136
     * [
137
     *     'class' => 'yii\web\UrlNormalizer',
138
     *     'collapseSlashes' => true,
139
     *     'normalizeTrailingSlash' => true,
140
     * ]
141
     * ```
142
     *
143
     * @since 2.0.10
144
     */
145
    public $normalizer = false;
146
147
    /**
148
     * @var string the cache key for cached rules
149
     * @since 2.0.8
150
     */
151
    protected $cacheKey = __CLASS__;
152
153
    private $_baseUrl;
154
    private $_scriptUrl;
155
    private $_hostInfo;
156
    private $_ruleCache;
157
158
159
    /**
160
     * Initializes UrlManager.
161
     */
162 40
    public function init()
163
    {
164 40
        parent::init();
165
166 40
        if ($this->normalizer !== false) {
167 2
            $this->normalizer = Instance::ensure($this->normalizer, UrlNormalizer::className());
168 2
        }
169
170 40
        if (!$this->enablePrettyUrl || empty($this->rules)) {
171 33
            return;
172
        }
173 9
        if (is_string($this->cache)) {
174 1
            $this->cache = Yii::$app->get($this->cache, false);
175 1
        }
176 9
        if ($this->cache instanceof Cache) {
177
            $cacheKey = $this->cacheKey;
178
            $hash = md5(json_encode($this->rules));
179
            if (($data = $this->cache->get($cacheKey)) !== false && isset($data[1]) && $data[1] === $hash) {
180
                $this->rules = $data[0];
181
            } else {
182
                $this->rules = $this->buildRules($this->rules);
183
                $this->cache->set($cacheKey, [$this->rules, $hash]);
184
            }
185
        } else {
186 9
            $this->rules = $this->buildRules($this->rules);
187
        }
188 9
    }
189
190
    /**
191
     * Adds additional URL rules.
192
     *
193
     * This method will call [[buildRules()]] to parse the given rule declarations and then append or insert
194
     * them to the existing [[rules]].
195
     *
196
     * Note that if [[enablePrettyUrl]] is `false`, this method will do nothing.
197
     *
198
     * @param array $rules the new rules to be added. Each array element represents a single rule declaration.
199
     * Please refer to [[rules]] for the acceptable rule format.
200
     * @param boolean $append whether to add the new rules by appending them to the end of the existing rules.
201
     */
202
    public function addRules($rules, $append = true)
203
    {
204
        if (!$this->enablePrettyUrl) {
205
            return;
206
        }
207
        $rules = $this->buildRules($rules);
208
        if ($append) {
209
            $this->rules = array_merge($this->rules, $rules);
210
        } else {
211
            $this->rules = array_merge($rules, $this->rules);
212
        }
213
    }
214
215
    /**
216
     * Builds URL rule objects from the given rule declarations.
217
     * @param array $rules the rule declarations. Each array element represents a single rule declaration.
218
     * Please refer to [[rules]] for the acceptable rule formats.
219
     * @return UrlRuleInterface[] the rule objects built from the given rule declarations
220
     * @throws InvalidConfigException if a rule declaration is invalid
221
     */
222 9
    protected function buildRules($rules)
223
    {
224 9
        $compiledRules = [];
225 9
        $verbs = 'GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS';
226 9
        foreach ($rules as $key => $rule) {
227 9
            if (is_string($rule)) {
228 8
                $rule = ['route' => $rule];
229 8
                if (preg_match("/^((?:($verbs),)*($verbs))\\s+(.*)$/", $key, $matches)) {
230 1
                    $rule['verb'] = explode(',', $matches[1]);
231
                    // rules that do not apply for GET requests should not be use to create urls
232 1
                    if (!in_array('GET', $rule['verb'])) {
233 1
                        $rule['mode'] = UrlRule::PARSING_ONLY;
234 1
                    }
235 1
                    $key = $matches[4];
236 1
                }
237 8
                $rule['pattern'] = $key;
238 8
            }
239 9
            if (is_array($rule)) {
240 9
                $rule = Yii::createObject(array_merge($this->ruleConfig, $rule));
241 9
            }
242 9
            if (!$rule instanceof UrlRuleInterface) {
243
                throw new InvalidConfigException('URL rule class must implement UrlRuleInterface.');
244
            }
245 9
            $compiledRules[] = $rule;
246 9
        }
247 9
        return $compiledRules;
248
    }
249
250
    /**
251
     * Parses the user request.
252
     * @param Request $request the request component
253
     * @return array|boolean the route and the associated parameters. The latter is always empty
254
     * if [[enablePrettyUrl]] is `false`. `false` is returned if the current request cannot be successfully parsed.
255
     */
256 3
    public function parseRequest($request)
257
    {
258 3
        if ($this->enablePrettyUrl) {
259
            /* @var $rule UrlRule */
260 3
            foreach ($this->rules as $rule) {
261 3
                if (($result = $rule->parseRequest($this, $request)) !== false) {
262 3
                    return $result;
263
                }
264 3
            }
265
266 1
            if ($this->enableStrictParsing) {
267 1
                return false;
268
            }
269
270 1
            Yii::trace('No matching URL rules. Using default URL parsing logic.', __METHOD__);
271
272 1
            $suffix = (string) $this->suffix;
273 1
            $pathInfo = $request->getPathInfo();
274 1
            $normalized = false;
275 1
            if ($this->normalizer !== false) {
276 1
                $pathInfo = $this->normalizer->normalizePathInfo($pathInfo, $suffix, $normalized);
277 1
            }
278 1
            if ($suffix !== '' && $pathInfo !== '') {
279 1
                $n = strlen($this->suffix);
280 1
                if (substr_compare($pathInfo, $this->suffix, -$n, $n) === 0) {
281 1
                    $pathInfo = substr($pathInfo, 0, -$n);
282 1
                    if ($pathInfo === '') {
283
                        // suffix alone is not allowed
284
                        return false;
285
                    }
286 1
                } else {
287
                    // suffix doesn't match
288 1
                    return false;
289
                }
290 1
            }
291
292 1
            if ($normalized) {
293
                // pathInfo was changed by normalizer - we need also normalize route
294 1
                return $this->normalizer->normalizeRoute([$pathInfo, []]);
295
            } else {
296 1
                return [$pathInfo, []];
297
            }
298
        } else {
299 1
            Yii::trace('Pretty URL not enabled. Using default URL parsing logic.', __METHOD__);
300 1
            $route = $request->getQueryParam($this->routeParam, '');
301 1
            if (is_array($route)) {
302 1
                $route = '';
303 1
            }
304
305 1
            return [(string) $route, []];
306
        }
307
    }
308
309
    /**
310
     * Creates a URL using the given route and query parameters.
311
     *
312
     * You may specify the route as a string, e.g., `site/index`. You may also use an array
313
     * if you want to specify additional query parameters for the URL being created. The
314
     * array format must be:
315
     *
316
     * ```php
317
     * // generates: /index.php?r=site%2Findex&param1=value1&param2=value2
318
     * ['site/index', 'param1' => 'value1', 'param2' => 'value2']
319
     * ```
320
     *
321
     * If you want to create a URL with an anchor, you can use the array format with a `#` parameter.
322
     * For example,
323
     *
324
     * ```php
325
     * // generates: /index.php?r=site%2Findex&param1=value1#name
326
     * ['site/index', 'param1' => 'value1', '#' => 'name']
327
     * ```
328
     *
329
     * The URL created is a relative one. Use [[createAbsoluteUrl()]] to create an absolute URL.
330
     *
331
     * Note that unlike [[\yii\helpers\Url::toRoute()]], this method always treats the given route
332
     * as an absolute route.
333
     *
334
     * @param string|array $params use a string to represent a route (e.g. `site/index`),
335
     * or an array to represent a route with query parameters (e.g. `['site/index', 'param1' => 'value1']`).
336
     * @return string the created URL
337
     */
338 27
    public function createUrl($params)
339
    {
340 27
        $params = (array) $params;
341 27
        $anchor = isset($params['#']) ? '#' . $params['#'] : '';
342 27
        unset($params['#'], $params[$this->routeParam]);
343
344 27
        $route = trim($params[0], '/');
345 27
        unset($params[0]);
346
347 27
        $baseUrl = $this->showScriptName || !$this->enablePrettyUrl ? $this->getScriptUrl() : $this->getBaseUrl();
348
349 27
        if ($this->enablePrettyUrl) {
350 7
            $cacheKey = $route . '?';
351 7
            foreach ($params as $key => $value) {
352 5
                if ($value !== null) {
353 5
                    $cacheKey .= $key . '&';
354 5
                }
355 7
            }
356
357 7
            $url = $this->getUrlFromCache($cacheKey, $route, $params);
358
359 7
            if ($url === false) {
360 7
                $cacheable = true;
361 7
                foreach ($this->rules as $rule) {
362
                    /* @var $rule UrlRule */
363 7
                    if (!empty($rule->defaults) && $rule->mode !== UrlRule::PARSING_ONLY) {
364
                        // if there is a rule with default values involved, the matching result may not be cached
365 1
                        $cacheable = false;
366 1
                    }
367 7
                    if (($url = $rule->createUrl($this, $route, $params)) !== false) {
368 6
                        if ($cacheable) {
369 6
                            $this->setRuleToCache($cacheKey, $rule);
370 6
                        }
371 6
                        break;
372
                    }
373 7
                }
374 7
            }
375
376 7
            if ($url !== false) {
377 6
                if (strpos($url, '://') !== false) {
378 3
                    if ($baseUrl !== '' && ($pos = strpos($url, '/', 8)) !== false) {
379 2
                        return substr($url, 0, $pos) . $baseUrl . substr($url, $pos) . $anchor;
380
                    } else {
381 1
                        return $url . $baseUrl . $anchor;
382
                    }
383
                } else {
384 4
                    return "$baseUrl/{$url}{$anchor}";
385
                }
386
            }
387
388 2
            if ($this->suffix !== null) {
389 1
                $route .= $this->suffix;
390 1
            }
391 2
            if (!empty($params) && ($query = http_build_query($params)) !== '') {
392 2
                $route .= '?' . $query;
393 2
            }
394
395 2
            return "$baseUrl/{$route}{$anchor}";
396
        } else {
397 21
            $url = "$baseUrl?{$this->routeParam}=" . urlencode($route);
398 21
            if (!empty($params) && ($query = http_build_query($params)) !== '') {
399 19
                $url .= '&' . $query;
400 19
            }
401
402 21
            return $url . $anchor;
403
        }
404
    }
405
406
    /**
407
     * Get URL from internal cache if exists
408
     * @param string $cacheKey generated cache key to store data.
409
     * @param string $route the route (e.g. `site/index`).
410
     * @param array $params rule params.
411
     * @return boolean|string the created URL
412
     * @see createUrl()
413
     * @since 2.0.8
414
     */
415 7
    protected function getUrlFromCache($cacheKey, $route, $params)
416
    {
417 7
        if (!empty($this->_ruleCache[$cacheKey])) {
418 4
            foreach ($this->_ruleCache[$cacheKey] as $rule) {
419
                /* @var $rule UrlRule */
420 4
                if (($url = $rule->createUrl($this, $route, $params)) !== false) {
421 4
                    return $url;
422
                }
423
            }
424
        } else {
425 7
            $this->_ruleCache[$cacheKey] = [];
426
        }
427 7
        return false;
428
    }
429
430
    /**
431
     * Store rule (e.g. [[UrlRule]]) to internal cache
432
     * @param $cacheKey
433
     * @param UrlRuleInterface $rule
434
     * @since 2.0.8
435
     */
436 6
    protected function setRuleToCache($cacheKey, UrlRuleInterface $rule)
437
    {
438 6
        $this->_ruleCache[$cacheKey][] = $rule;
439 6
    }
440
441
    /**
442
     * Creates an absolute URL using the given route and query parameters.
443
     *
444
     * This method prepends the URL created by [[createUrl()]] with the [[hostInfo]].
445
     *
446
     * Note that unlike [[\yii\helpers\Url::toRoute()]], this method always treats the given route
447
     * as an absolute route.
448
     *
449
     * @param string|array $params use a string to represent a route (e.g. `site/index`),
450
     * or an array to represent a route with query parameters (e.g. `['site/index', 'param1' => 'value1']`).
451
     * @param string $scheme the scheme to use for the url (either `http` or `https`). If not specified
452
     * the scheme of the current request will be used.
453
     * @return string the created URL
454
     * @see createUrl()
455
     */
456 10
    public function createAbsoluteUrl($params, $scheme = null)
457
    {
458 10
        $params = (array) $params;
459 10
        $url = $this->createUrl($params);
460 10
        if (strpos($url, '://') === false) {
461 8
            $url = $this->getHostInfo() . $url;
462 8
        }
463 10
        if (is_string($scheme) && ($pos = strpos($url, '://')) !== false) {
464 4
            $url = $scheme . substr($url, $pos);
465 4
        }
466
467 10
        return $url;
468
    }
469
470
    /**
471
     * Returns the base URL that is used by [[createUrl()]] to prepend to created URLs.
472
     * It defaults to [[Request::baseUrl]].
473
     * This is mainly used when [[enablePrettyUrl]] is `true` and [[showScriptName]] is `false`.
474
     * @return string the base URL that is used by [[createUrl()]] to prepend to created URLs.
475
     * @throws InvalidConfigException if running in console application and [[baseUrl]] is not configured.
476
     */
477 5
    public function getBaseUrl()
478
    {
479 5
        if ($this->_baseUrl === null) {
480 1
            $request = Yii::$app->getRequest();
481 1
            if ($request instanceof Request) {
482 1
                $this->_baseUrl = $request->getBaseUrl();
483 1
            } else {
484
                throw new InvalidConfigException('Please configure UrlManager::baseUrl correctly as you are running a console application.');
485
            }
486 1
        }
487
488 5
        return $this->_baseUrl;
489
    }
490
491
    /**
492
     * Sets the base URL that is used by [[createUrl()]] to prepend to created URLs.
493
     * This is mainly used when [[enablePrettyUrl]] is `true` and [[showScriptName]] is `false`.
494
     * @param string $value the base URL that is used by [[createUrl()]] to prepend to created URLs.
495
     */
496 13
    public function setBaseUrl($value)
497
    {
498 13
        $this->_baseUrl = $value === null ? null : rtrim($value, '/');
499 13
    }
500
501
    /**
502
     * Returns the entry script URL that is used by [[createUrl()]] to prepend to created URLs.
503
     * It defaults to [[Request::scriptUrl]].
504
     * This is mainly used when [[enablePrettyUrl]] is `false` or [[showScriptName]] is `true`.
505
     * @return string the entry script URL that is used by [[createUrl()]] to prepend to created URLs.
506
     * @throws InvalidConfigException if running in console application and [[scriptUrl]] is not configured.
507
     */
508 24
    public function getScriptUrl()
509
    {
510 24
        if ($this->_scriptUrl === null) {
511 7
            $request = Yii::$app->getRequest();
512 7
            if ($request instanceof Request) {
513 7
                $this->_scriptUrl = $request->getScriptUrl();
514 7
            } else {
515
                throw new InvalidConfigException('Please configure UrlManager::scriptUrl correctly as you are running a console application.');
516
            }
517 7
        }
518
519 24
        return $this->_scriptUrl;
520
    }
521
522
    /**
523
     * Sets the entry script URL that is used by [[createUrl()]] to prepend to created URLs.
524
     * This is mainly used when [[enablePrettyUrl]] is `false` or [[showScriptName]] is `true`.
525
     * @param string $value the entry script URL that is used by [[createUrl()]] to prepend to created URLs.
526
     */
527 21
    public function setScriptUrl($value)
528
    {
529 21
        $this->_scriptUrl = $value;
530 21
    }
531
532
    /**
533
     * Returns the host info that is used by [[createAbsoluteUrl()]] to prepend to created URLs.
534
     * @return string the host info (e.g. "http://www.example.com") that is used by [[createAbsoluteUrl()]] to prepend to created URLs.
535
     * @throws InvalidConfigException if running in console application and [[hostInfo]] is not configured.
536
     */
537 10
    public function getHostInfo()
538
    {
539 10
        if ($this->_hostInfo === null) {
540 4
            $request = Yii::$app->getRequest();
541 4
            if ($request instanceof \yii\web\Request) {
542 4
                $this->_hostInfo = $request->getHostInfo();
543 4
            } else {
544
                throw new InvalidConfigException('Please configure UrlManager::hostInfo correctly as you are running a console application.');
545
            }
546 4
        }
547
548 10
        return $this->_hostInfo;
549
    }
550
551
    /**
552
     * Sets the host info that is used by [[createAbsoluteUrl()]] to prepend to created URLs.
553
     * @param string $value the host info (e.g. "http://www.example.com") that is used by [[createAbsoluteUrl()]] to prepend to created URLs.
554
     */
555 9
    public function setHostInfo($value)
556
    {
557 9
        $this->_hostInfo = $value === null ? null : rtrim($value, '/');
558 9
    }
559
}
560