How to encode URL parameters?
Asked Answered
U

4

177

I am trying to pass parameters to a URL which looks like this:

http://www.foobar.com/foo?imageurl=

And I want to pass the parameters such as an image URL which is generated itself by another API, and the link for the image turns out as:

http://www.image.com/?username=unknown&password=unknown

However, when I try to use the URL:

http://www.foobar.com/foo?imageurl=http://www.image.com/?username=unknown&password=unknown

It doesn't work.

I have also tried using encodeURI() and encodeURIComponent() on the imageURL, and that too doesn't work.

Unsphere answered 15/11, 2011 at 10:48 Comment(5)
What language is generating the URL? JavaScript?Vigilance
Note that you should not put passwords in urls, not even when using https, as every router between client and server will see the whole url.Dimorph
Does this answer your question? How to create query parameters in Javascript?Portage
@Dimorph That doesn't seem to be true: https://mcmap.net/q/24468/-are-https-urls-encryptedCaprifoliaceous
@Caprifoliaceous GET path and params are encrypted for HTTPS, but not HTTP (which, ok, no-one should be using, but still...). However, much more seriously, server logs and any analytics tools will see the GET params, so you'll log plaintext passwords in your apache logs, and in your Google Analytics. They're also sent through the referrer header, if that's enabled. See security.stackexchange.com/questions/233795/…Ergot
W
221

With PHP

echo urlencode("http://www.image.com/?username=unknown&password=unknown");

Result

http%3A%2F%2Fwww.image.com%2F%3Fusername%3Dunknown%26password%3Dunknown

With Javascript:

var myUrl = "http://www.image.com/?username=unknown&password=unknown";
var encodedURL= "http://www.foobar.com/foo?imageurl=" + encodeURIComponent(myUrl);

DEMO: http://jsfiddle.net/Lpv53/

Woadwaxen answered 15/11, 2011 at 10:53 Comment(1)
This question is not about PHP, but about Javascript.Modulator
G
65

Using new ES6 Object.entries(), it makes for a fun little nested map/join:

const encodeGetParams = p => 
  Object.entries(p).map(kv => kv.map(encodeURIComponent).join("=")).join("&");

const params = {
  user: "María Rodríguez",
  awesome: true,
  awesomeness: 64,
  "ZOMG+&=*(": "*^%*GMOZ"
};

console.log("https://example.com/endpoint?" + encodeGetParams(params))
Grownup answered 11/5, 2018 at 9:1 Comment(1)
This works very well in my case I added a call to decodeURIComponent inside the map function to make sure entries already encoded dont get messiForcemeat
K
34

With URLSearchParams:

const params = new URLSearchParams()
params.set('imageurl', 'http://www.image.com/?username=unknown&password=unknown')
return `http://www.foobar.com/foo?${params.toString()}`
Kenay answered 26/8, 2020 at 13:37 Comment(6)
Will this work in all browsers and browser versions?Meader
@Meader : while it's a standard, some <1%-browsers have not implemented it: caniuse.com/urlsearchparamsKenay
Why not use the entirety of the URL API and start with const url = new URL("http://www.foobar.com/foo");? Also, in most circumstances you want set, not append: url.set("imageurl", "http://www.image.com/?username=unknown&password=unknown"); return url;.Plutocrat
@SebastianSimon: good point about set vs append, thanks. Using URL might distract from the main point, since setting the params does not seem to be elegant. Or did I overlook something?Kenay
@Kenay Depends on the use case; using URL itself was just a general suggestion. I prefer to have my URLs always validated by the URL API, even if they’re static, so it might be a bit of an overkill; it’s just preference.Plutocrat
Or simply: http://foobar.com/foo?${new URLSearchParams({ imageurl: '...' }).toString()}Wellfixed
O
10

Just try encodeURI() and encodeURIComponent() yourself...

console.log(encodeURIComponent('@#$%^&*'));

Input: @#$%^&*. Output: %40%23%24%25%5E%26*. So, wait, what happened to *? Why wasn't this converted? TLDR: You actually want fixedEncodeURIComponent() and fixedEncodeURI(). Long-story...

You should not be using encodeURIComponent() or encodeURI(). You should use fixedEncodeURIComponent() and fixedEncodeURI(), according to the MDN Documentation.

Regarding encodeURI()...

If one wishes to follow the more recent RFC3986 for URLs, which makes square brackets reserved (for IPv6) and thus not encoded when forming something which could be part of a URL (such as a host), the following code snippet may help:

function fixedEncodeURI(str) { return encodeURI(str).replace(/%5B/g, '[').replace(/%5D/g, ']'); }

Regarding encodeURIComponent()...

To be more stringent in adhering to RFC 3986 (which reserves !, ', (, ), and *), even though these characters have no formalized URI delimiting uses, the following can be safely used:

function fixedEncodeURIComponent(str) { return encodeURIComponent(str).replace(/[!'()*]/g, function(c) { return '%' + c.charCodeAt(0).toString(16); }); }

So, what is the difference? fixedEncodeURI() and fixedEncodeURIComponent() convert the same set of values, but fixedEncodeURIComponent() also converts this set: +@?=:*#;,$&. This set is used in GET parameters (&, +, etc.), anchor tags (#), wildcard tags (*), email/username parts (@), etc..

For example -- If you use encodeURI(), [email protected]/?email=me@home will not properly send the second @ to the server, except for your browser handling the compatibility (as Chrome naturally does often).

Olmstead answered 18/6, 2020 at 21:1 Comment(2)
What do you mean by "except for your browser handling the compatibility"?Stairway
@Stephan: For example, if site.com?formula=a+b=c works in producing formula=>a+b=c, that violates the spec, but if it works, it's because Chrome/etc. can detect the spec failure of the URL, etc., and so on, w/ [email protected][email protected].Olmstead

© 2022 - 2024 — McMap. All rights reserved.