Subversion Repositories php-qbpwcf

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 liveuser 1
<?php
2
 
3
/*
4
 * This file is part of the Symfony package.
5
 *
6
 * (c) Fabien Potencier <fabien@symfony.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
 
12
namespace Symfony\Component\Routing\Matcher\Dumper;
13
 
14
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
15
use Symfony\Component\Routing\Exception\NoConfigurationException;
16
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
17
use Symfony\Component\Routing\Matcher\RedirectableUrlMatcherInterface;
18
use Symfony\Component\Routing\RequestContext;
19
 
20
/**
21
 * @author Nicolas Grekas <p@tchwork.com>
22
 *
23
 * @internal
24
 *
25
 * @property RequestContext $context
26
 */
27
trait CompiledUrlMatcherTrait
28
{
29
    private $matchHost = false;
30
    private $staticRoutes = [];
31
    private $regexpList = [];
32
    private $dynamicRoutes = [];
33
    private $checkCondition;
34
 
35
    public function match(string $pathinfo): array
36
    {
37
        $allow = $allowSchemes = [];
38
        if ($ret = $this->doMatch($pathinfo, $allow, $allowSchemes)) {
39
            return $ret;
40
        }
41
        if ($allow) {
42
            throw new MethodNotAllowedException(array_keys($allow));
43
        }
44
        if (!$this instanceof RedirectableUrlMatcherInterface) {
45
            throw new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo));
46
        }
47
        if (!\in_array($this->context->getMethod(), ['HEAD', 'GET'], true)) {
48
            // no-op
49
        } elseif ($allowSchemes) {
50
            redirect_scheme:
51
            $scheme = $this->context->getScheme();
52
            $this->context->setScheme(key($allowSchemes));
53
            try {
54
                if ($ret = $this->doMatch($pathinfo)) {
55
                    return $this->redirect($pathinfo, $ret['_route'], $this->context->getScheme()) + $ret;
56
                }
57
            } finally {
58
                $this->context->setScheme($scheme);
59
            }
60
        } elseif ('/' !== $trimmedPathinfo = rtrim($pathinfo, '/') ?: '/') {
61
            $pathinfo = $trimmedPathinfo === $pathinfo ? $pathinfo.'/' : $trimmedPathinfo;
62
            if ($ret = $this->doMatch($pathinfo, $allow, $allowSchemes)) {
63
                return $this->redirect($pathinfo, $ret['_route']) + $ret;
64
            }
65
            if ($allowSchemes) {
66
                goto redirect_scheme;
67
            }
68
        }
69
 
70
        throw new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo));
71
    }
72
 
73
    private function doMatch(string $pathinfo, array &$allow = [], array &$allowSchemes = []): array
74
    {
75
        $allow = $allowSchemes = [];
76
        $pathinfo = rawurldecode($pathinfo) ?: '/';
77
        $trimmedPathinfo = rtrim($pathinfo, '/') ?: '/';
78
        $context = $this->context;
79
        $requestMethod = $canonicalMethod = $context->getMethod();
80
 
81
        if ($this->matchHost) {
82
            $host = strtolower($context->getHost());
83
        }
84
 
85
        if ('HEAD' === $requestMethod) {
86
            $canonicalMethod = 'GET';
87
        }
88
        $supportsRedirections = 'GET' === $canonicalMethod && $this instanceof RedirectableUrlMatcherInterface;
89
 
90
        foreach ($this->staticRoutes[$trimmedPathinfo] ?? [] as list($ret, $requiredHost, $requiredMethods, $requiredSchemes, $hasTrailingSlash, , $condition)) {
91
            if ($condition && !($this->checkCondition)($condition, $context, 0 < $condition ? $request ?? $request = $this->request ?: $this->createRequest($pathinfo) : null)) {
92
                continue;
93
            }
94
 
95
            if ($requiredHost) {
96
                if ('{' !== $requiredHost[0] ? $requiredHost !== $host : !preg_match($requiredHost, $host, $hostMatches)) {
97
                    continue;
98
                }
99
                if ('{' === $requiredHost[0] && $hostMatches) {
100
                    $hostMatches['_route'] = $ret['_route'];
101
                    $ret = $this->mergeDefaults($hostMatches, $ret);
102
                }
103
            }
104
 
105
            if ('/' !== $pathinfo && $hasTrailingSlash === ($trimmedPathinfo === $pathinfo)) {
106
                if ($supportsRedirections && (!$requiredMethods || isset($requiredMethods['GET']))) {
107
                    return $allow = $allowSchemes = [];
108
                }
109
                continue;
110
            }
111
 
112
            $hasRequiredScheme = !$requiredSchemes || isset($requiredSchemes[$context->getScheme()]);
113
            if ($hasRequiredScheme && $requiredMethods && !isset($requiredMethods[$canonicalMethod]) && !isset($requiredMethods[$requestMethod])) {
114
                $allow += $requiredMethods;
115
                continue;
116
            }
117
 
118
            if (!$hasRequiredScheme) {
119
                $allowSchemes += $requiredSchemes;
120
                continue;
121
            }
122
 
123
            return $ret;
124
        }
125
 
126
        $matchedPathinfo = $this->matchHost ? $host.'.'.$pathinfo : $pathinfo;
127
 
128
        foreach ($this->regexpList as $offset => $regex) {
129
            while (preg_match($regex, $matchedPathinfo, $matches)) {
130
                foreach ($this->dynamicRoutes[$m = (int) $matches['MARK']] as list($ret, $vars, $requiredMethods, $requiredSchemes, $hasTrailingSlash, $hasTrailingVar, $condition)) {
131
                    if (null !== $condition) {
132
                        if (0 === $condition) { // marks the last route in the regexp
133
                            continue 3;
134
                        }
135
                        if (!($this->checkCondition)($condition, $context, 0 < $condition ? $request ?? $request = $this->request ?: $this->createRequest($pathinfo) : null)) {
136
                            continue;
137
                        }
138
                    }
139
 
140
                    $hasTrailingVar = $trimmedPathinfo !== $pathinfo && $hasTrailingVar;
141
 
142
                    if ($hasTrailingVar && ($hasTrailingSlash || (null === $n = $matches[\count($vars)] ?? null) || '/' !== ($n[-1] ?? '/')) && preg_match($regex, $this->matchHost ? $host.'.'.$trimmedPathinfo : $trimmedPathinfo, $n) && $m === (int) $n['MARK']) {
143
                        if ($hasTrailingSlash) {
144
                            $matches = $n;
145
                        } else {
146
                            $hasTrailingVar = false;
147
                        }
148
                    }
149
 
150
                    if ('/' !== $pathinfo && !$hasTrailingVar && $hasTrailingSlash === ($trimmedPathinfo === $pathinfo)) {
151
                        if ($supportsRedirections && (!$requiredMethods || isset($requiredMethods['GET']))) {
152
                            return $allow = $allowSchemes = [];
153
                        }
154
                        continue;
155
                    }
156
 
157
                    foreach ($vars as $i => $v) {
158
                        if (isset($matches[1 + $i])) {
159
                            $ret[$v] = $matches[1 + $i];
160
                        }
161
                    }
162
 
163
                    if ($requiredSchemes && !isset($requiredSchemes[$context->getScheme()])) {
164
                        $allowSchemes += $requiredSchemes;
165
                        continue;
166
                    }
167
 
168
                    if ($requiredMethods && !isset($requiredMethods[$canonicalMethod]) && !isset($requiredMethods[$requestMethod])) {
169
                        $allow += $requiredMethods;
170
                        continue;
171
                    }
172
 
173
                    return $ret;
174
                }
175
 
176
                $regex = substr_replace($regex, 'F', $m - $offset, 1 + \strlen($m));
177
                $offset += \strlen($m);
178
            }
179
        }
180
 
181
        if ('/' === $pathinfo && !$allow && !$allowSchemes) {
182
            throw new NoConfigurationException();
183
        }
184
 
185
        return [];
186
    }
187
}