All dispatcher strategies checked preg_match() results with `!== 1`, which conflates a genuine no-match (0) with a PCRE engine failure (false), e.g. PREG_BACKTRACK_LIMIT_ERROR from a catastrophically backtracking route pattern. Because dynamic routes for the same method are combined into shared regex chunks, one such route could make the preg_match() call for the whole chunk fail, silently turning an unrelated, cheap route in that chunk into a spurious NOT_FOUND. Add a shared matchRoute() helper on RegexBasedAbstract that calls preg_match() and throws a RuntimeException (including preg_last_error_msg()) when it returns false, while preserving the existing 0/1 no-match/match behavior. Update GroupCountBased, GroupPosBased, CharCountBased and MarkBased to use it. Fixes #167
40 lines
954 B
PHP
40 lines
954 B
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace FastRoute\Dispatcher;
|
|
|
|
use FastRoute\Dispatcher\Result\Matched;
|
|
|
|
use function count;
|
|
|
|
/** @final */
|
|
class GroupCountBased extends RegexBasedAbstract
|
|
{
|
|
/** @inheritDoc */
|
|
protected function dispatchVariableRoute(array $routeData, string $uri): ?Matched
|
|
{
|
|
foreach ($routeData as $data) {
|
|
if ($this->matchRoute($data['regex'], $uri, $matches) !== 1) {
|
|
continue;
|
|
}
|
|
|
|
[$handler, $varNames, $extraParameters] = $data['routeMap'][count($matches)];
|
|
|
|
$vars = [];
|
|
$i = 0;
|
|
foreach ($varNames as $varName) {
|
|
$vars[$varName] = $matches[++$i];
|
|
}
|
|
|
|
$result = new Matched();
|
|
$result->handler = $handler;
|
|
$result->variables = $vars;
|
|
$result->extraParameters = $extraParameters;
|
|
|
|
return $result;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|