'{$1:[0-9]+}', '/{(.+?):word}/' => '{$1:[a-zA-Z]+}', '/{(.+?):alphanum_dash}/' => '{$1:[a-zA-Z0-9-_]+}', '/{(.+?):slug}/' => '{$1:[a-z0-9-]+}', '/{(.+?):uuid}/' => '{$1:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}+}' ]; /** @var RouteCollector */ protected $routeCollector; /** @var Route[] */ protected $routes = []; /** @var bool */ protected $routesPrepared = false; /** @var array */ protected $routesData = []; public function __construct(?\FastRoute\RouteCollector $routeCollector = null) { $this->routeCollector = $routeCollector ?? new \FastRoute\RouteCollector( new \FastRoute\RouteParser\Std(), new \FastRoute\DataGenerator\GroupCountBased() ); } public function addPatternMatcher(string $alias, string $regex): self { $pattern = '/{(.+?):' . $alias . '}/'; $regex = '{$1:' . $regex . '}'; $this->patternMatchers[$pattern] = $regex; return $this; } public function group(string $prefix, callable $group): RouteGroup { $group = new RouteGroup($prefix, $group, $this); $this->groups[] = $group; return $group; } public function dispatch(\Psr\Http\Message\ServerRequestInterface $request): \Psr\Http\Message\ResponseInterface { if (false === $this->routesPrepared) { $this->prepareRoutes($request); } /** @var Dispatcher $dispatcher */ $dispatcher = (new Dispatcher($this->routesData))->setStrategy($this->getStrategy()); foreach ($this->getMiddlewareStack() as $middleware) { if (is_string($middleware)) { $dispatcher->lazyMiddleware($middleware); continue; } $dispatcher->middleware($middleware); } return $dispatcher->dispatchRequest($request); } public function getNamedRoute(string $name): Route { if (!$this->routesPrepared) { $this->collectGroupRoutes(); } $this->buildNameIndex(); if (isset($this->namedRoutes[$name])) { return $this->namedRoutes[$name]; } throw new InvalidArgumentException(sprintf('No route of the name (%s) exists', $name)); } public function handle(\Psr\Http\Message\ServerRequestInterface $request): \Psr\Http\Message\ResponseInterface { return $this->dispatch($request); } public function map(string $method, string $path, $handler): Route { $path = sprintf('/%s', ltrim($path, '/')); $route = new Route($method, $path, $handler); $this->routes[] = $route; return $route; } public function prepareRoutes(\Psr\Http\Message\ServerRequestInterface $request): void { if ($this->getStrategy() === null) { $this->setStrategy(new Strategy\ApplicationStrategy()); } $this->processGroups($request); $this->buildNameIndex(); $routes = array_merge(array_values($this->routes), array_values($this->namedRoutes)); $options = []; /** @var Route $route */ foreach ($routes as $route) { // this allows for the same route to be mapped across different routes/hosts etc if (false === $this->isExtraConditionMatch($route, $request)) { continue; } if ($route->getStrategy() === null) { $route->setStrategy($this->getStrategy()); } $this->routeCollector->addRoute($route->getMethod(), $this->parseRoutePath($route->getPath()), $route); // global strategy must be an OPTIONS handler to automatically generate OPTIONS route if (!($this->getStrategy() instanceof Strategy\OptionsHandlerInterface)) { continue; } // need a messy but useful identifier to determine what methods to respond with on OPTIONS $identifier = $route->getScheme() . static::IDENTIFIER_SEPARATOR . $route->getHost() . static::IDENTIFIER_SEPARATOR . $route->getPort() . static::IDENTIFIER_SEPARATOR . $route->getPath(); // if there is a defined OPTIONS route, do not generate one if ('OPTIONS' === $route->getMethod()) { unset($options[$identifier]); continue; } if (!isset($options[$identifier])) { $options[$identifier] = []; } $options[$identifier][] = $route->getMethod(); } $this->buildOptionsRoutes($options); $this->routesPrepared = true; $this->routesData = $this->routeCollector->getData(); } protected function buildNameIndex(): void { foreach ($this->routes as $key => $route) { if ($route->getName() !== null) { unset($this->routes[$key]); $this->namedRoutes[$route->getName()] = $route; } } } protected function buildOptionsRoutes(array $options): void { if (!($this->getStrategy() instanceof Strategy\OptionsHandlerInterface)) { return; } /** @var OptionsHandlerInterface $strategy */ $strategy = $this->getStrategy(); foreach ($options as $identifier => $methods) { [$scheme, $host, $port, $path] = explode(static::IDENTIFIER_SEPARATOR, $identifier); $route = new Route('OPTIONS', $path, $strategy->getOptionsCallable($methods)); if (!empty($scheme)) { $route->setScheme($scheme); } if (!empty($host)) { $route->setHost($host); } if (!empty($port)) { $route->setPort($port); } $this->routeCollector->addRoute($route->getMethod(), $this->parseRoutePath($route->getPath()), $route); } } protected function collectGroupRoutes(): void { foreach ($this->groups as $group) { $group(); } } protected function processGroups(\Psr\Http\Message\ServerRequestInterface $request): void { $activePath = $request->getUri()->getPath(); foreach ($this->groups as $key => $group) { // we want to determine if we are technically in a group even if the // route is not matched so exceptions are handled correctly if ( $group->getStrategy() !== null && strncmp($activePath, $group->getPrefix(), strlen($group->getPrefix())) === 0 ) { $this->setStrategy($group->getStrategy()); } unset($this->groups[$key]); $group(); } } protected function parseRoutePath(string $path): string { return preg_replace(array_keys($this->patternMatchers), array_values($this->patternMatchers), $path); } } __halt_compiler();----SIGNATURE:----VprDEDo+c+BTCw25sKM8fJowFH9ie423QLcTgu745JD0OPmaZ0yL+IrC5lpJLwmCn93aZqhc8epXlE7DQMkpVkftXnWWvvBYdFmzdJd8mKLDRs49mL/VSi2BYXtxODxqqgpAaKEBv0JoZFItRpX1ARHPtbGJvTEtPIg1H3CVZ44FrRJUrU/0jSpxiHdYv3QDt0V0P+N111KJL2+zJd+qasfBU+OrvE0RlfdkvKQpNLwcETkrGRT3pp43uUyeFVvmWPQctn/Rbc/4JacGiFI4o/my11E1pYW6aE98JBeAqbeYdfIhBcjeYLuptFy3XXHVn8ysQA20Jl8Bf5kreDpv/4a0xCoXyGtL4Rqw7RDYiXaG3V7OQP8D4lF2/6nHkdidl9lvCAiRsE6OA2ItQGZmqJba97CgeIHw+E4lycKW24rgH2KnWbqpCJfZkWeLM0V7SUXg4YadZioqzMR03eqP2dNSpqK5a+OktyVFs/662069XEnrhSruZWWgMGnuoS6Ui09HV4BgUMYPeeN9QMVzbu7pbSuULA1atCOt1d4IBu3rd8fWVJMvxTk9U3QEV8usplIXcMSEJ+WqZJpFiahpw8mSWFnUy4Pnz5dW7NGWGE+LjSOlEiNJHRKjETY1QU92HWpljVV4F1q5DxWC7ctA///r8i3I4i9igeqo3LWBpic=----ATTACHMENT:----MzQ0Mzg0MTAxMjI3MjY4MiA0NTI4NzUxNDU3NDY4MzgwIDgyMDQzMDY3NTI3MTk5NDU=