-
-
Notifications
You must be signed in to change notification settings - Fork 6.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Redirect 301 for unresolved url matching with suffix #10733
Redirect 301 for unresolved url matching with suffix #10733
Conversation
@@ -7,6 +7,7 @@ Yii Framework 2 Change Log | |||
- Bug #6363, #8301, #8582, #9566: Fixed data methods and PJAX issues when used together (derekisbusy) | |||
- Bug #6876: Fixed RBAC migration MSSQL cascade problem (thejahweh) | |||
- Bug #7627: Fixed `yii\widgets\ActiveField` to handle inputs validation with changed ID properly (dynasource, cebe) | |||
- Bug #7670: Fixed `yii\web\Request`: forces redirect when unresolved url matches an url with suffix (dynasource) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should work the other way around as well i.e. if suffix isn't defined than check if there's /
in the path. If it's there, remove it and try again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there are 2 problems with this other way around:
-
The current UrlManager + UrlRules (2.0.6) accept infinit '/' suffixes in the url (try it yourself with a route like /index.php/test/route//////). This means that a suffix like '/' is always accepted in the URL, despite a suffix not being set (perhabs this is another issue for the tracker)
-
Taken this into account this means that, if you still want to check the other way around, you have to check on a '/' suffix for every request that is correctly parsed (because an given urls with '////' are always parsed correctly). This goes at cost of performance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- rtrim
/
. - URLs with
////
parsed correctly? What do you mean? It gives 404 if suffix isn't/
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dived into it.
I started with a fresh new Advanced project with the following setting:
'urlManager'=>[
'class'=>'yii\web\UrlManager',
'enablePrettyUrl' => true,
]
Both following urls render correctly:
- http://localhost/dmn/yii-application/frontend/web/index.php/site/about
- http://localhost/dmn/yii-application/frontend/web/index.php/site/about/////
Seems like unwanted behavior.
if ($result !== false) { | ||
list ($route, $params) = $result; | ||
if ($this->_queryParams === null) { | ||
list ($route, $params) = $result; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Redundant spaces at the end of the line
Solution does not seem right to me. There must be a simplier way to achieve the goal. |
with the current state of the UrlManager + UrlRules + Request, this is a simple way of achieving this goal. When you desire a cleaner and even more simple way, than more refactoring and cleanups have to be done in the those 3 classes. I would say, this is something for later releases. |
- cleanup to PSR - cleanup spaces - create PHP doc return tag Response - move Request out of resolveRequest() to $this format
dc31f30
to
9357dac
Compare
Nothing is so permanent as a temporary solution. |
nothing is so permanent as a perminant 301 redirect ;) |
@klimov-paul do you have an idea for better approach to the problem? |
Just to throw it out there, we have things setup like below. This way, the default is no trailing slash but it is optional. <?php
namespace yii\helpers;
use Yii;
use yii\helpers\BaseUrl;
class Url extends BaseUrl {
public static function to($url = '', $scheme = false)
{
if (is_array($url)) {
if (!isset($url['tbs']) && $url[0] !== 'home/index') {
$url['tbs'] = '';
}
return static::toRoute($url, $scheme);
} and at the end of urls.php: $newUrls = [];
foreach ($urls as $url => $route) {
if ($url !== '/') {
$url .= '<tbs:\/?>';
}
$newUrls[$url] = $route;
}
return $newUrls; |
@df2, this patch is about automatic redirection |
This is hard to tell for sure. But at first glance just analyzing of |
Correct but we need to get the suffix we're checking for from somewhere. It could be defined either in UrlManager or in UrlRule. |
We may advance can be following: return [(string) $route, [], $urlSuffix]; This will not cause a BC break. |
Inside public function resolve()
{
$result = Yii::$app->getUrlManager()->parseRequest($this);
if ($result !== false) {
list ($route, $params, $urlSuffix) = $result;
if (isset($urlSuffix)) {
// check and redirect if necessary
}
//...
} |
well, it looks like your excluding the (rare) usecase of #9207 (comment) Based on your example:
If you do this, than someone cannot have both Urls as UrlRules:
Because pageX is matched first, pageY is ignored |
Why? Url suffix is used for URL rule parsing already. Does not it? [
'site/contact',
[],
'/'
] And everything will be fine. Parsing [
'site/contact',
[],
''
] Also should be fine. Then we compare returned 3rd parameter with the request URI, checking if it is present or not. |
the issue is about hard & softmatching and the correct order which means, first hard matching, then softmatching. If you are doing a redirect, than it means, the URL is not right by hard matching, but with softmatching on a suffix, it should be executed. If you are using the current implementation of UrlManager::parseRequest, you are looping on the UrlRules. You are returning [(string) $route, [], $urlSuffix] if a match of the UrlRule has been found. With your example, this means a softmatching on suffix is done in an early stage in the UrlRule itself, otherwise it could never return the array with the correct suffix. This also means that a hard match on a following UrlRule is ignored. |
Are you sure about that? If suffix is missmatch the Rule will return The goal is enforce some trainling suffix ("/") in case NO suffix is explicitly macthed by The only problem I can see if you want enforce some suffix like "/", but still keep a route without any suffix. For this use case some magic value should be reserved like |
I have no garantee my idea will work. But at least it worth trying. |
true. Your solution is cleaner & faster. If you get it more robust, fixing the problem you mentioned, I would prefer yours. It requires more refactoring though, which would make this PR bigger. I tried to keep my PR a small as possible. |
See #10745 |
fixes #7670