mirror of
https://github.com/yiisoft/yii2.git
synced 2025-11-17 23:09:10 +08:00
Merge pull request #10064 from SilverFire/9999-url-validator
Fixed `yii\web\UrlRule` to allow route parameter names with `-`, `_`, `.` characters
This commit is contained in:
@@ -30,6 +30,7 @@ Yii Framework 2 Change Log
|
|||||||
- Bug #9915: `yii\helpers\ArrayHelper::getValue()` was erroring instead of returning `null` for non-existing object properties (totaldev, samdark)
|
- Bug #9915: `yii\helpers\ArrayHelper::getValue()` was erroring instead of returning `null` for non-existing object properties (totaldev, samdark)
|
||||||
- Bug #9924: Fixed `yii.js` handleAction corrupted parameter values containing quote (") character (silverfire)
|
- Bug #9924: Fixed `yii.js` handleAction corrupted parameter values containing quote (") character (silverfire)
|
||||||
- Bug #9984: Fixed wrong captcha color in case Imagick is used (DrDeath72)
|
- Bug #9984: Fixed wrong captcha color in case Imagick is used (DrDeath72)
|
||||||
|
- Bug #9999: Fixed `yii\web\UrlRule` to allow route parameter names with `-`, `_`, `.`characters (silverfire)
|
||||||
- Bug #10029: Fixed MaskedInput not working with PJAX (martrix78, samdark)
|
- Bug #10029: Fixed MaskedInput not working with PJAX (martrix78, samdark)
|
||||||
- Bug: Fixed generation of canonical URLs for `ViewAction` pages (samdark)
|
- Bug: Fixed generation of canonical URLs for `ViewAction` pages (samdark)
|
||||||
- Enh #3506: Added `\yii\validators\IpValidator` to perform validation of IP addresses and subnets (SilverFire, samdark)
|
- Enh #3506: Added `\yii\validators\IpValidator` to perform validation of IP addresses and subnets (SilverFire, samdark)
|
||||||
|
|||||||
@@ -104,6 +104,18 @@ class UrlRule extends Object implements UrlRuleInterface
|
|||||||
* @var array list of parameters used in the route.
|
* @var array list of parameters used in the route.
|
||||||
*/
|
*/
|
||||||
private $_routeParams = [];
|
private $_routeParams = [];
|
||||||
|
/**
|
||||||
|
* @var array list of placeholders for matching parameters names. Used in [[parseRequest()]], [[createUrl()]]
|
||||||
|
* On the rule initialization, the [[pattern]] parameters names will be replaced with placeholders.
|
||||||
|
* This array contains relations between the original parameters names and their placeholders.
|
||||||
|
* key - placeholder
|
||||||
|
* value - original name
|
||||||
|
*
|
||||||
|
* @see parseRequest()
|
||||||
|
* @see createUrl()
|
||||||
|
* @since 2.0.7
|
||||||
|
*/
|
||||||
|
private $_placeholders = [];
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -151,7 +163,7 @@ class UrlRule extends Object implements UrlRuleInterface
|
|||||||
$this->pattern = '/' . $this->pattern . '/';
|
$this->pattern = '/' . $this->pattern . '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strpos($this->route, '<') !== false && preg_match_all('/<(\w+)>/', $this->route, $matches)) {
|
if (strpos($this->route, '<') !== false && preg_match_all('/<([\w._-]+)>/', $this->route, $matches)) {
|
||||||
foreach ($matches[1] as $name) {
|
foreach ($matches[1] as $name) {
|
||||||
$this->_routeParams[$name] = "<$name>";
|
$this->_routeParams[$name] = "<$name>";
|
||||||
}
|
}
|
||||||
@@ -166,31 +178,34 @@ class UrlRule extends Object implements UrlRuleInterface
|
|||||||
'(' => '\\(',
|
'(' => '\\(',
|
||||||
')' => '\\)',
|
')' => '\\)',
|
||||||
];
|
];
|
||||||
|
|
||||||
$tr2 = [];
|
$tr2 = [];
|
||||||
if (preg_match_all('/<(\w+):?([^>]+)?>/', $this->pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
|
if (preg_match_all('/<([\w._-]+):?([^>]+)?>/', $this->pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
|
||||||
foreach ($matches as $match) {
|
foreach ($matches as $match) {
|
||||||
$name = $match[1][0];
|
$name = $match[1][0];
|
||||||
$pattern = isset($match[2][0]) ? $match[2][0] : '[^\/]+';
|
$pattern = isset($match[2][0]) ? $match[2][0] : '[^\/]+';
|
||||||
|
$placeholder = 'a' . hash('crc32b', $name); // placeholder must begin with a letter
|
||||||
|
$this->_placeholders[$placeholder] = $name;
|
||||||
if (array_key_exists($name, $this->defaults)) {
|
if (array_key_exists($name, $this->defaults)) {
|
||||||
$length = strlen($match[0][0]);
|
$length = strlen($match[0][0]);
|
||||||
$offset = $match[0][1];
|
$offset = $match[0][1];
|
||||||
if ($offset > 1 && $this->pattern[$offset - 1] === '/' && (!isset($this->pattern[$offset + $length]) || $this->pattern[$offset + $length] === '/')) {
|
if ($offset > 1 && $this->pattern[$offset - 1] === '/' && (!isset($this->pattern[$offset + $length]) || $this->pattern[$offset + $length] === '/')) {
|
||||||
$tr["/<$name>"] = "(/(?P<$name>$pattern))?";
|
$tr["/<$name>"] = "(/(?P<$placeholder>$pattern))?";
|
||||||
} else {
|
} else {
|
||||||
$tr["<$name>"] = "(?P<$name>$pattern)?";
|
$tr["<$name>"] = "(?P<$placeholder>$pattern)?";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$tr["<$name>"] = "(?P<$name>$pattern)";
|
$tr["<$name>"] = "(?P<$placeholder>$pattern)";
|
||||||
}
|
}
|
||||||
if (isset($this->_routeParams[$name])) {
|
if (isset($this->_routeParams[$name])) {
|
||||||
$tr2["<$name>"] = "(?P<$name>$pattern)";
|
$tr2["<$name>"] = "(?P<$placeholder>$pattern)";
|
||||||
} else {
|
} else {
|
||||||
$this->_paramRules[$name] = $pattern === '[^\/]+' ? '' : "#^$pattern$#u";
|
$this->_paramRules[$name] = $pattern === '[^\/]+' ? '' : "#^$pattern$#u";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->_template = preg_replace('/<(\w+):?([^>]+)?>/', '<$1>', $this->pattern);
|
$this->_template = preg_replace('/<([\w._-]+):?([^>]+)?>/', '<$1>', $this->pattern);
|
||||||
$this->pattern = '#^' . trim(strtr($this->_template, $tr), '/') . '$#u';
|
$this->pattern = '#^' . trim(strtr($this->_template, $tr), '/') . '$#u';
|
||||||
|
|
||||||
if (!empty($this->_routeParams)) {
|
if (!empty($this->_routeParams)) {
|
||||||
@@ -216,7 +231,7 @@ class UrlRule extends Object implements UrlRuleInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
$pathInfo = $request->getPathInfo();
|
$pathInfo = $request->getPathInfo();
|
||||||
$suffix = (string) ($this->suffix === null ? $manager->suffix : $this->suffix);
|
$suffix = (string)($this->suffix === null ? $manager->suffix : $this->suffix);
|
||||||
if ($suffix !== '' && $pathInfo !== '') {
|
if ($suffix !== '' && $pathInfo !== '') {
|
||||||
$n = strlen($suffix);
|
$n = strlen($suffix);
|
||||||
if (substr_compare($pathInfo, $suffix, -$n, $n) === 0) {
|
if (substr_compare($pathInfo, $suffix, -$n, $n) === 0) {
|
||||||
@@ -237,6 +252,8 @@ class UrlRule extends Object implements UrlRuleInterface
|
|||||||
if (!preg_match($this->pattern, $pathInfo, $matches)) {
|
if (!preg_match($this->pattern, $pathInfo, $matches)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
$matches = $this->substitutePlaceholderNames($matches);
|
||||||
|
|
||||||
foreach ($this->defaults as $name => $value) {
|
foreach ($this->defaults as $name => $value) {
|
||||||
if (!isset($matches[$name]) || $matches[$name] === '') {
|
if (!isset($matches[$name]) || $matches[$name] === '') {
|
||||||
$matches[$name] = $value;
|
$matches[$name] = $value;
|
||||||
@@ -281,6 +298,7 @@ class UrlRule extends Object implements UrlRuleInterface
|
|||||||
// match the route part first
|
// match the route part first
|
||||||
if ($route !== $this->route) {
|
if ($route !== $this->route) {
|
||||||
if ($this->_routeRule !== null && preg_match($this->_routeRule, $route, $matches)) {
|
if ($this->_routeRule !== null && preg_match($this->_routeRule, $route, $matches)) {
|
||||||
|
$matches = $this->substitutePlaceholderNames($matches);
|
||||||
foreach ($this->_routeParams as $name => $token) {
|
foreach ($this->_routeParams as $name => $token) {
|
||||||
if (isset($this->defaults[$name]) && strcmp($this->defaults[$name], $matches[$name]) === 0) {
|
if (isset($this->defaults[$name]) && strcmp($this->defaults[$name], $matches[$name]) === 0) {
|
||||||
$tr[$token] = '';
|
$tr[$token] = '';
|
||||||
@@ -352,4 +370,34 @@ class UrlRule extends Object implements UrlRuleInterface
|
|||||||
{
|
{
|
||||||
return $this->_paramRules;
|
return $this->_paramRules;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Iterates over [[_placeholders]] and checks whether each placeholder exists as a key in $matches array.
|
||||||
|
* When found - replaces this placeholder key with a appropriate name of matching parameter.
|
||||||
|
* Used in [[parseRequest()]], [[createUrl()]].
|
||||||
|
*
|
||||||
|
* @param array $matches result of `preg_match()` call
|
||||||
|
* @return array input array with replaced placeholder keys
|
||||||
|
* @see _placeholders
|
||||||
|
* @since 2.0.7
|
||||||
|
*/
|
||||||
|
private function substitutePlaceholderNames (array $matches) {
|
||||||
|
foreach ($this->_placeholders as $placeholder => $name) {
|
||||||
|
if (isset($matches[$placeholder])) {
|
||||||
|
$matches[$name] = $matches[$placeholder];
|
||||||
|
unset($matches[$placeholder]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns list of placeholders and original names for matching parameters.
|
||||||
|
* @return array
|
||||||
|
* @since 2.0.7
|
||||||
|
* @see _placeholders
|
||||||
|
*/
|
||||||
|
protected function getPlaceholders() {
|
||||||
|
return $this->_placeholders;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user