Yii2: Urlencoding in Url::toRoute and Url::to

Created on 31 May 2014  路  50Comments  路  Source: yiisoft/yii2

Url::tooRoute and Url::to returns a urlencoded result after passing a route which results in: /localhost/frontend/web/index.php?r=site%2Findex instead of /localhost/frontend/web/index.php?r=site/index.

Is this intended behavior? If so, how can one bypass it since the urlencoding seems to be hardcoded in the UrlManager Class at line 328?

docs

Most helpful comment

Just type test/me, test=me, test&me into google and then look into address bar of your browser to see which URLs are generated.

All 50 comments

why would you not encode the URL? not encoding may not produce valid URL.

Yes, it's intended.

Thank you for your replay, cebe. I need to generate valid urls in order to use it in form input elements like buttons and links. I know I could use the activeForm widget but I need to do it "manually". So assigning the result of Url::toRoute to an Html button will leave me withe the rather ugly link I have mentioned above...

So there is now way of converting a route like 'site/index' to a valid url without the / being converted to %2F ?

Encoded URL is also valid and will work just fine.

Yes, it is still working but it's not nice to the eye and maybe to search engines neither... Anyhow thanx for taking the time to answer, samdark.

Search engines are OK with it.

Hi, it first hurts my eyes too and then i realized it's just me and all users haven't even recognized, as they are looking (suprise) on the lements within the page and not the uri ...:)
Serious, under the technical aspect, I know you are right and as I'm not only a technician and sometimes beeing focused on the wrong spots... as I believe you it works... I focus more on the page content...

Yeah, it was hurting my eyes as well for quite some time.

But would it not make sense to optionally allow disabling encoding for cases where one could ensure that encoding is not needed -for the sake of stopping all the pain? :-)

@yiisoft/core-developers what do you think?

when using urlManager with pretty url feature you will not have encoded backslash. So this would be the option to choose when you want pretty looking urls.

This option works fine for me, thank you.

it's not work fine for me
in my case
Url::to(['repository/blob', 'username' => 'djfly', 'repository' => 'forum', 'branch' => 'master', 'filename' => 'mail/layouts/html.php']);

generate
http://127.0.0.1/gitday/web/djfly/forum/blob/master/mail%2Flayouts%2Fhtml.php

but i need this
http://127.0.0.1/gitday/web/djfly/forum/blob/master/mail/layouts/html.php

need option to set Urlencoding
@cebe

Option to turn on/off url encoding would be great.

biggest use case I see is using categories (or something else) with materialised path, at the moment it is possible to create url rules like:

'<lang:lt>/konstanta<path:(.*)>' => 'controller/action',
'<lang:en>/constant<path:(.*)>' => 'controller/action',

and they will work if you enter urls like:

lt/konstanta/tai/veiks
en/constant/this/will/work

but its impossible to create such url's in your application without making ugly hacks like:

$lang = \Yii::$app->language;

if ($lang == 'lt') {
    $url = $lang . '/konstanta' . $materialisedPath;
} else {
    $url = $lang . '/constant' . $materialisedPath;
}

echo Html::a('title', $url);

because Url::to(['controller/action', 'path' => '/this/will/fail/bad']); will fail.

it is a very big problem in multilingual apps :(

Would be nice if this worked, however the following returns a 404:

index.php?r=module%26method%3Dpayment%26module%3DAuthorizenet%26action%3Dedit

This returns the correct page:

index.php?r=module&method=payment&module=Authorizenet&action=edit

Where do I need to edit to switch off URL encoding?

+1 for an option to disable encoding, e.g. as an optional parameter in Url::to. Sometimes you need to create URL templates (which are not really valid URLs), like when defining sitelinks search box target URL, such as "https://query.example.com/search?q={search_term_string}",. You could of course create it manually, but using Url::to would be convenient. With encoding turned on there's no way to get curly braces.

With encoding turned on there's no way to get curly braces.

the safest way would be to str_replace() encoded url characters afterwards or just call urldecode() on it if you are sure that is fine for all included characters.

Encoding of URLs is ridiculous. I do not recall seeing any other website onllne that does it.

I think that the standard has been misinterpreted.

I do not see any reply to my post above, which shows that encoded URLs are not handled correctly by Yii itself.

They are handled correctly and according to spec. If you don't want encoded URLs, use URL manager to customize them.

Where is this automatic encoding behaviour documented? The echo examples under http://www.yiiframework.com/doc-2.0/guide-runtime-routing.html#creating-urls might be a good place.

// creates a URL to a route: /index.php?r=post/index
echo Url::to(['post/index']);

should _technically_ read:

// creates a URL to a route: /index.php?r=post%2Findex
echo Url::to(['post/index']);

can you please update the file and send a pull request?

Samdark they are NOT handled correctly, otherwise I would not get a 404 NOT FOUND error.

index.php?r=module%26method%3Dpayment%26module%3DAuthorizenet%26action%3Dedit

returns a 404 NOT FOUND

echo urldecode('index.php?r=module%26method%3Dpayment%26module%3DAuthorizenet%26action%3Dedit');

returns: index.php?r=module&method=payment&module=Authorizenet&action=edit

This URL works as expected.

You guys have got it all wrong. From the standard:

2.3. Unreserved Characters

Data characters that are allowed in a URI but do not have a reserved
purpose are called unreserved. These include upper and lower case
letters, decimal digits, and a limited set of punctuation marks and
symbols.

  unreserved  = alphanum | mark

  mark        = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"

Unreserved characters can be escaped without changing the semantics
of the URI, but this should not be done unless the URI is being used
in a context that does not allow the unescaped character to appear.

2.4. Escape Sequences

Data must be escaped if it does not have a representation using an
unreserved character; this includes data that does not correspond to
a printable character of the US-ASCII coded character set, or that
corresponds to any US-ASCII character that is disallowed, as
explained below.

Note the last part: " Data must be escaped if it does NOT have a representation using an
unreserved character" (my emphasis) - eg. a space.

You can find examples throughout the standards documents showing regular unencoded URLs.

These are fine in any URL:

2.2. Reserved Characters

Many URI include components consisting of or delimited by, certain
special characters. These characters are called "reserved", since
their usage within the URI component is limited to their reserved
purpose. If the data for a URI component would conflict with the
reserved purpose, then the conflicting data must be escaped before
forming the URI.

  reserved    = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
                "$" | ","

The "reserved" syntax class above refers to those characters that are
allowed within a URI, but which may not be allowed within a
particular component of the generic URI syntax; they are used as
delimiters of the components described in Section 3.

I could also ask, why then is "?" not encoded....? According to you, it should be "%3F".

@osCMattiFinn How did you create this url? Show code please.

index.php?r=module%26method%3Dpayment%26module%3DAuthorizenet%26action%3Dedit

kidol, the URL is created by Yii.

Yii encodes any URL if you use Html::a

This is beside the point - the URL is "correctly" encoded, however Yii is unable to interpret it and throws a 404 NOT FOUND.

echo \yii\helpers\Html::a("test", ['site/index', 'a' => 1, 'b' => 2]);

<a href="/index.php?r=site%2Findex&amp;a=1&amp;b=2">test</a>

This is correct encoding. In your case everything after ?r= is urlencoded, which is not correct, because it maps everything to the r param. How to reproduce this?

No, it is correct. Use urlencode() on your URL written without encoding.

Why in the World would you encode characters which the standard says are reserved and perfectly good as they are?...... and at the same time not encode others?

We encode "&" as "&amp;" within HTML, but not the actual URL - browsers correctly interpret "&amp;" within HTML as "&" if you look at your address bar. This character is reserved and does not need encoding.

Forward slashes are reserved and do not need to be encoded.

With urlencode you encode the individual query values (like the value 'site/index'), not the whole url (which happend in your case for some reason).

? is encoded if it's a part of the parameter value same as / or &. If it's not part of parameter value, it's not encoded.

Samdark - You are NOT following the standard. Reserved characters do not need to be nor should they be encoded. Show me just one non-Yii website where the URLs are encoded, other than characters which should be encoded.

Here you go: https://github.com/yiisoft/yii2/issues?q=is%3Aissue

Anyway you fail to see that your whole url (inclusive &) is urlencoded, which is obviously wrong (Yii can not parse it). You don't post your url creation code, so no one can help I guess.

<a href="/index.php?r=site%2Findex&amp;a=1&amp;b=2">test</a>

I've seen something similar here: http://github.com/yiisoft/yii2/issues/9816#issuecomment-148725384

Well problem here is that everything, the whole url is urlencoded. So maybe he does something wrong like:

echo \yii\helpers\Html::a("test", ['site/index?a=1&b=2']);

But who knows without code.

You prove nothing Samdark by pasting links which CORRECTLY have spaces encoded. Show me some with forward slashes and = encoded and ampersands encoded.......please take the time to actually read the Specification, not just take some fool's opinion on it.

See my comments above. These are forward slashes encoded, not spaces.

And to be complete, here are = and & encoded by Google:

Just type test/me, test=me, test&me into google and then look into address bar of your browser to see which URLs are generated.

For anyone looking for a solution there is an encodeParams property of UrlRule.

The solution is to wrap your URL inside rawurldecode.

http://php.net/manual/en/function.rawurldecode.php

E.g:

$url = Url::to(['post/view', 'slug' => $model->slug]);

echo rawurldecode($url);

I still think there should be an option within Url::to() to control this, however.

Hello dear Yii contributors,

im beginner and try to upgrade to yii2

in yii1 i was able to use the url path like below:

<controller:\w+>/<action:\w+>/service/<service:\d+>/*' => '<controller>/<action>
the star(*) that ending the url as you know was meant to end whole params with a slash and not
?id=23?
as sad in yii1 documentation :

If the GET parameters passed to createUrl are more than those required by a rule, the additional parameters will appear in the query string. For example, if we call $this->createUrl('post/read',array('id'=>100,'year'=>2008)), we would obtain /index.php/post/100?year=2008. In order to make these additional parameters appear in the path info part, we should append /* to the rule. Therefore, with the rule post/

now with yii2 i don't figure out how to handle this,
thanks for helping.

@MuhammedSami it's better to ask at forum: https://forum.yiiframework.com/

I want to chime in to say that URI encoding makes sense by default. By default, this is probably just going to get echo'd somewhere in a URI setting, and so the encoding makes sense.

However, there are cases for wanting it to not encode, such as using it as a cache key, or logging the URI, or I'm sure other cases. Maybe there can be an option to encode or not directly at the usage site? For these cases, it's not "this UrlRule should not encode params", it's that this usage should not encode params.

One of use cases for not encoded URL is JavaScript variables.
For example, I have a JavaScript table that populates columns based on their configuration from JSON on client's side.
I would like to use Url::to(['/some/controller/action', 'id' => '${data.id}']) to have dynamic links in the resulting table. Right now only thing I can do is Url::to(['/some/controller/action']) . '/${data.id}'.
However, depending on URL rules, each new parameter can create a very different URL (/some/action?id=1 or /some/action/1 or /some/controller/1), which is hard to manage when they have to be appended manually.

@eggnukes please open a new issue for this.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Ragazzo picture Ragazzo  路  44Comments

AstRonin picture AstRonin  路  49Comments

sepidemahmoodi picture sepidemahmoodi  路  104Comments

gpoehl picture gpoehl  路  47Comments

dhiman252 picture dhiman252  路  44Comments