<?php
\\FastRoute\RouteParser\Std;
class Std implements RouteParser
{
const VARIABLE_REGEX = <<<'REGEX'
\{
\s* ([a-zA-Z_][a-zA-Z0-9_-]*) \s*
(?:
: \s* ([^{}]*(?:\{(?-1)\}[^{}]*)*)
)?
\}
REGEX;
const DEFAULT_DISPATCH_REGEX = '[^/]+';
public function parse($route)
{
$routeWithoutClosingOptionals = rtrim($route, ']');
$numOptionals = strlen($route) - strlen($routeWithoutClosingOptionals);
// Split on [ while skipping placeholders
$segments = preg_split('~' . self::VARIABLE_REGEX . '(*SKIP)(*F) | \[~x', $routeWithoutClosingOptionals);
if ($numOptionals !== count($segments) - 1) { // If there are any ] in the middle of the route, throw a more specific error message
if (preg_match('~' . self::VARIABLE_REGEX . '(*SKIP)(*F) | \]~x', $routeWithoutClosingOptionals)) { throw new BadRouteException('Optional segments can only occur at the end of a route');
}
throw new BadRouteException("Number of opening '[' and closing ']' does not match");
}
$currentRoute = '';
$routeDatas = [];
foreach ($segments as $n => $segment) {
if ($segment === '' && $n !== 0) {
throw new BadRouteException('Empty optional part');
}
$currentRoute .= $segment;
$routeDatas[] = $this->parsePlaceholders($currentRoute);
}
return $routeDatas;
}
}
PD9waHAKXFxGYXN0Um91dGVcUm91dGVQYXJzZXJcU3RkOwoKY2xhc3MgU3RkIGltcGxlbWVudHMgUm91dGVQYXJzZXIKewogICAgY29uc3QgVkFSSUFCTEVfUkVHRVggPSA8PDwnUkVHRVgnClx7CiAgICBccyogKFthLXpBLVpfXVthLXpBLVowLTlfLV0qKSBccyoKICAgICg/OgogICAgICAgIDogXHMqIChbXnt9XSooPzpceyg/LTEpXH1bXnt9XSopKikKICAgICk/Clx9ClJFR0VYOwogICAgY29uc3QgREVGQVVMVF9ESVNQQVRDSF9SRUdFWCA9ICdbXi9dKyc7CgogICAgcHVibGljIGZ1bmN0aW9uIHBhcnNlKCRyb3V0ZSkKICAgIHsKICAgICAgICAkcm91dGVXaXRob3V0Q2xvc2luZ09wdGlvbmFscyA9IHJ0cmltKCRyb3V0ZSwgJ10nKTsKICAgICAKICAgICAgICAkbnVtT3B0aW9uYWxzID0gc3RybGVuKCRyb3V0ZSkgLSBzdHJsZW4oJHJvdXRlV2l0aG91dENsb3NpbmdPcHRpb25hbHMpOwogICAKICAgICAgICAvLyBTcGxpdCBvbiBbIHdoaWxlIHNraXBwaW5nIHBsYWNlaG9sZGVycwogICAgICAgICRzZWdtZW50cyA9IHByZWdfc3BsaXQoJ34nIC4gc2VsZjo6VkFSSUFCTEVfUkVHRVggLiAnKCpTS0lQKSgqRikgfCBcW354JywgJHJvdXRlV2l0aG91dENsb3NpbmdPcHRpb25hbHMpOwogICAgIAogICAgICAgIGlmICgkbnVtT3B0aW9uYWxzICE9PSBjb3VudCgkc2VnbWVudHMpIC0gMSkgewogICAgICAgICAgICAvLyBJZiB0aGVyZSBhcmUgYW55IF0gaW4gdGhlIG1pZGRsZSBvZiB0aGUgcm91dGUsIHRocm93IGEgbW9yZSBzcGVjaWZpYyBlcnJvciBtZXNzYWdlCiAgICAgICAgICAgIGlmIChwcmVnX21hdGNoKCd+JyAuIHNlbGY6OlZBUklBQkxFX1JFR0VYIC4gJygqU0tJUCkoKkYpIHwgXF1+eCcsICRyb3V0ZVdpdGhvdXRDbG9zaW5nT3B0aW9uYWxzKSkgewogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEJhZFJvdXRlRXhjZXB0aW9uKCdPcHRpb25hbCBzZWdtZW50cyBjYW4gb25seSBvY2N1ciBhdCB0aGUgZW5kIG9mIGEgcm91dGUnKTsKICAgICAgICAgICAgfQogICAgICAgICAgICB0aHJvdyBuZXcgQmFkUm91dGVFeGNlcHRpb24oIk51bWJlciBvZiBvcGVuaW5nICdbJyBhbmQgY2xvc2luZyAnXScgZG9lcyBub3QgbWF0Y2giKTsKICAgICAgICB9CgogICAgICAgICRjdXJyZW50Um91dGUgPSAnJzsKICAgICAgICAkcm91dGVEYXRhcyA9IFtdOwogICAgICAgIGZvcmVhY2ggKCRzZWdtZW50cyBhcyAkbiA9PiAkc2VnbWVudCkgewoKICAgICAgICAgICAgaWYgKCRzZWdtZW50ID09PSAnJyAmJiAkbiAhPT0gMCkgewogICAgICAgICAgICAgICAgdGhyb3cgbmV3IEJhZFJvdXRlRXhjZXB0aW9uKCdFbXB0eSBvcHRpb25hbCBwYXJ0Jyk7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgICRjdXJyZW50Um91dGUgLj0gJHNlZ21lbnQ7CiAgICAgICAgICAgICRyb3V0ZURhdGFzW10gPSAkdGhpcy0+cGFyc2VQbGFjZWhvbGRlcnMoJGN1cnJlbnRSb3V0ZSk7CiAgICAgICAgCiAgICAgICAgfQoKICAgICAgICByZXR1cm4gJHJvdXRlRGF0YXM7CiAgICB9Cn0=