diff --git a/src/Symfony/Component/Routing/RouteCompiler.php b/src/Symfony/Component/Routing/RouteCompiler.php index f6637da666b8..1ce18ceb6607 100644 --- a/src/Symfony/Component/Routing/RouteCompiler.php +++ b/src/Symfony/Component/Routing/RouteCompiler.php @@ -28,12 +28,22 @@ class RouteCompiler implements RouteCompilerInterface */ const SEPARATORS = '/,;.:-_~+*=@|'; + /** + * The maximum supported length of a PCRE subpattern name + * http://pcre.org/current/doc/html/pcre2pattern.html#SEC16. + * + * @var int + * + * @internal + */ + const VARIABLE_MAXIMUM_LENGTH = 32; + /** * {@inheritdoc} * * @throws \LogicException If a variable is referenced more than once - * @throws \DomainException If a variable name is numeric because PHP raises an error for such - * subpatterns in PCRE and thus would break matching, e.g. "(?P<123>.+)". + * @throws \DomainException If a variable name starts with a digit or if it is too long to be successfully used as + * a PCRE subpattern. */ public static function compile(Route $route) { @@ -95,13 +105,19 @@ private static function compilePattern(Route $route, $pattern, $isHost) $precedingChar = strlen($precedingText) > 0 ? substr($precedingText, -1) : ''; $isSeparator = '' !== $precedingChar && false !== strpos(static::SEPARATORS, $precedingChar); - if (is_numeric($varName)) { - throw new \DomainException(sprintf('Variable name "%s" cannot be numeric in route pattern "%s". Please use a different name.', $varName, $pattern)); + // A PCRE subpattern name must start with a non-digit. Also a PHP variable cannot start with a digit so the + // variable would not be usable as a Controller action argument. + if (preg_match('/^\d/', $varName)) { + throw new \DomainException(sprintf('Variable name "%s" cannot start with a digit in route pattern "%s". Please use a different name.', $varName, $pattern)); } if (in_array($varName, $variables)) { throw new \LogicException(sprintf('Route pattern "%s" cannot reference variable name "%s" more than once.', $pattern, $varName)); } + if (strlen($varName) > self::VARIABLE_MAXIMUM_LENGTH) { + throw new \DomainException(sprintf('Variable name "%s" cannot be longer than %s characters in route pattern "%s". Please use a shorter name.', $varName, self::VARIABLE_MAXIMUM_LENGTH, $pattern)); + } + if ($isSeparator && strlen($precedingText) > 1) { $tokens[] = array('text', substr($precedingText, 0, -1)); } elseif (!$isSeparator && strlen($precedingText) > 0) { diff --git a/src/Symfony/Component/Routing/Tests/RouteCompilerTest.php b/src/Symfony/Component/Routing/Tests/RouteCompilerTest.php index b4b4f45a8379..f08b9688a921 100644 --- a/src/Symfony/Component/Routing/Tests/RouteCompilerTest.php +++ b/src/Symfony/Component/Routing/Tests/RouteCompilerTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Routing\Tests; use Symfony\Component\Routing\Route; +use Symfony\Component\Routing\RouteCompiler; class RouteCompilerTest extends \PHPUnit_Framework_TestCase { @@ -176,16 +177,16 @@ public function testRouteWithSameVariableTwice() } /** - * @dataProvider getNumericVariableNames + * @dataProvider getVariableNamesStartingWithADigit * @expectedException \DomainException */ - public function testRouteWithNumericVariableName($name) + public function testRouteWithVariableNameStartingWithADigit($name) { $route = new Route('/{'.$name.'}'); $route->compile(); } - public function getNumericVariableNames() + public function getVariableNamesStartingWithADigit() { return array( array('09'), @@ -264,4 +265,13 @@ public function provideCompileWithHostData() ), ); } + + /** + * @expectedException \DomainException + */ + public function testRouteWithTooLongVariableName() + { + $route = new Route(sprintf('/{%s}', str_repeat('a', RouteCompiler::VARIABLE_MAXIMUM_LENGTH + 1))); + $route->compile(); + } }