The following redirect url becomes with http%3A%2F%2F instead of http://. How can I avoid this?
Thanks in advance.
$params = array(
'client_id' => $client_id,
'redirect_uri' => site_url('welcome/google_connect_redirect/'),
'state' => $_SESSION['state'],
'approval_prompt' => 'force',
'scope' => 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email',
'response_type' => 'code'
);
$url = "https://accounts.google.com/o/oauth2/auth?".http_build_query($params);
// send to google
redirect($url);
URL becomes like this.
https://accounts.google.com/o/oauth2/auth?client_id=871111192098.apps.
googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%3A8888%2Fmyappname
%2Findex.php%2Fwelcome%2Fgoogle_connect_redirect&state=f0babsomeletterscb5b48753358c
3b9&approval_prompt=force&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2F
userinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&
response_type=code
When you put strings with special characters into URL, they will be encoded, you can use urldecode
The point of http_build_query() is that it urlencode()s each of the array's values for you before joining them in a querystring format. This is the preferred behavior.
The query string is encoded because there are some special characters that have special meaning in a URL.
From Wikipedia:
Some characters cannot be part of a URL (for example, the space) and
some other characters have a special meaning in a URL: for example,
the character # can be used to further specify a subsection (or
fragment) of a document; the character = is used to separate a name
from a value. A query string may need to be converted to satisfy these
constraints. This can be done using a schema known as URL encoding.
It's actually desired behavior and proper way to do it.
Look at manual and description of function http_build_query
Generates a URL-encoded query string from the associative (or indexed) array provided.
So basically what it does it goes through whole array and urlencode it (that's why you see these characters) and joins it with &. If you want to avoid it then don't use http_build_query() but I really don't recommend it.
Related
This question is about the proper use of rawurlencode, http_build_query & htmlspecialchars.
Until now my standard way of creating HTML link in vanilla PHP was this:
$qs = [
'foo' => 'foo~bar',
'bar' => 'bar foo',
];
echo 'Link';
Recently I have learned that this is not 100% correct. Here are few issues:
http_build_query uses by default PHP_QUERY_RFC1738 instead of PHP_QUERY_RFC3986. RFC3986 is the standard and superseded RFC1738 which in PHP is only kept for legacy use.
While the "special" HTML characters in the key and value part will be encoded to the percent-encoded representation, the argument separator will be an ampersand. In most sane situations this would not be a problem, but sometimes your key name might be quot; and then your link will become invalid:
$qs = [
'a' => 'a',
'quot;' => 'bar',
];
echo 'Link';
The code above will generate this link: ?a=a"%3B=bar!
IMO this implies that the function http_build_query needs to be called context-aware with the 3-rd argument & when in HTML, and with just & when in header('Location: ...');. Another option would be to pass it through htmlspecialchars before displaying in HTML.
PHP manual for urlencode (which should be deprecated long time ago IMO) suggests to encode only the value part of query string and then pass the whole query string through htmlentities before displaying in HTML. This looks very incorrect to me; the key part could still contain forbidden URL characters.
$query_string = 'foo=' . urlencode($foo) . '&bar=' . urlencode($bar);
echo '<a href="mycgi?' . htmlentities($query_string) . '">';
My conclusion is to do something along this lines:
$qs = [
'a' => 'a',
'quot;' => 'bar foo',
];
echo 'Link';
What is the recommended way to create HTML links in PHP? Is there an easier way than what I came up with? Have I missed any crucial points?
How to dynamically build HTML links with query string?
If you need to create query string to be used in HTML link (e.g. Link) then you should use http_build_query.
This function accepts 4 parameters, with the first one being an array/object of query data. For the most part the other 3 parameters are irrelevant.
$qs = [
'a' => 'a',
'quot;' => 'bar foo',
];
echo 'Link';
However, you should still pass the output of the function through htmlspecialchars to encode the & correctly. "A good framework will do this automatically, like Laravel's {{ }}"
echo 'Link';
Alternatively you can pass the third argument to http_build_query as '&', leaving the second one null. This will use & instead of & which is what htmlspecialchars would do.
About spaces.
For use in form data (i.e. query strings) the space should be encoded as + and in any other place it should be encoded as %20 e.g. new%20page.php?my+field=my+val. This is to ensure backwards comparability with all browsers. You can use the newer RFC3986 which will encode the spaces as %20 and it will work in all common browsers as well as be up to date with modern standards.
echo 'Link';
rawurlencode vs urlencode
For any part of URL before ? you should use rawurlencode. For example:
$subdir = rawurlencode('blue+light blue');
echo 'rawurlencode';
If in the above example you used urlencode the link would be broken. urlencode has very limited use and should be avoided.
Do not pass whole URL through rawurlencode. Separators / and other special characters in URL should not be encoded if they are to fulfil their function.
Footnote
There is no general agreement on the best practices for using http_build_query, other than the fact it should be passed through htmlspecialchars just like any other output in HTML context.
Laravel uses http_build_query($array, null, '&', PHP_QUERY_RFC3986)
CodeIgniter uses http_build_query($query)
Symfony uses http_build_query($extra, '', '&', PHP_QUERY_RFC3986)
Slim uses http_build_query($queryParams)
CakePHP uses http_build_query($query)
Twig uses http_build_query($url, '', '&', PHP_QUERY_RFC3986)
I am trying to send a GET message that contains strings with ampersands and can't figure how to escape the ampersand in the URL.
Example:
http://www.example.com?candy_name=M&M
result => candy_name = M
I also tried:
http://www.example.com?candy_name=M\&M
result => candy_name = M\\
I am using URLs manually, so I just need the correct characters.
I can't use any libraries. How can it be done?
They need to be percent-encoded:
> encodeURIComponent('&')
"%26"
So in your case, the URL would look like:
http://www.mysite.com?candy_name=M%26M
This does not only apply to the ampersand in URLs, but to all reserved characters. Some of which include:
# $ & + , / : ; = ? # [ ]
The idea is the same as encoding an &in an HTML document, but the context has changed to be within the URI, in addition to being within the HTML document. So, the percent-encoding prevents issues with parsing inside of both contexts.
The place where this comes in handy a lot is when you need to put a URL inside of another URL. For example, if you want to post a status on Twitter:
http://www.twitter.com/intent/tweet?status=What%27s%20up%2C%20StackOverflow%3F(http%3A%2F%2Fwww.stackoverflow.com)
There's lots of reserved characters in my Tweet, namely ?'():/, so I encoded the whole value of the status URL parameter. This also is helpful when using mailto: links that have a message body or subject, because you need to encode the body and subject parameters to keep line breaks, ampersands, etc. intact.
When a character from the reserved set (a "reserved character") has
special meaning (a "reserved purpose") in a certain context, and a URI
scheme says that it is necessary to use that character for some other
purpose, then the character must be percent-encoded. Percent-encoding
a reserved character involves converting the character to its
corresponding byte value in ASCII and then representing that value as
a pair of hexadecimal digits. The digits, preceded by a percent sign
("%") which is used as an escape character, are then used in the URI
in place of the reserved character. (For a non-ASCII character, it is
typically converted to its byte sequence in UTF-8, and then each byte
value is represented as above.) The reserved character "/", for
example, if used in the "path" component of a URI, has the special
meaning of being a delimiter between path segments. If, according to a
given URI scheme, "/" needs to be in a path segment, then the three
characters "%2F" or "%2f" must be used in the segment instead of a raw
"/".
http://en.wikipedia.org/wiki/Percent-encoding#Percent-encoding_reserved_characters
Try using http://www.example.org?candy_name=M%26M.
See also this reference and some more information on Wikipedia.
I would like to add a minor comment to Blender's solution.
You can do the following:
var link = 'http://example.com?candy_name=' + encodeURIComponent('M&M');
That outputs:
http://example.com?candy_name=M%26M
The great thing about this it does not only work for &, but for any especial character.
For instance:
var link = 'http://example.com?candy_name=' + encodeURIComponent('M&M?><')
Outputs:
"http://example.com?candy_name=M%26M%3F%3E%3C"
You can use the % character to 'escape' characters that aren't allowed in URLs. See RFC 1738.
A table of ASCII values is given on the Wikipedia page.
You can see & is 26 in hexadecimal - so you need M%26M.
This may help if someone want it in PHP
$variable ="candy_name=M&M";
$variable = str_replace("&", "%26", $variable);
If you can't use any libraries to encode the value,
http://www.urlencoder.org/ or http://www.urlencode-urldecode.com/ or ...
Just enter your value "M&M", not the full URL ;-)
You can rather pass your arguments using this encodeURIComponent function so you don't have to worry about passing any special characters.
data: "param1=getAccNos¶m2="+encodeURIComponent('Dolce & Gabbana') OR
var someValue = 'Dolce & Gabbana';
data : "param1=getAccNos¶m2="+encodeURIComponent(someValue)
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
I'm using codeigniter (newbie at codeigniter).
I have a function getproducts($p1, $p2, $p3) in a controller.
When I call getproducts/0/0/ from my jquery-script (ajax) it works, but I want to call URL like this:
getproducts/0/0/{"0":"13","1":"24"}
it doesn't work. (I get into to google-search-results instead of staying at my local webserver)
I basically want to pass an array to a function in the url somehow when using codeigniter. How should I solve that? Please help :-)
I think you should at least adjust the Codeigniter's config about allowed characters in the URL to include curly braces, comma and double quotes :
$config['permitted_uri_chars'] = ',{}"a-z 0-9~%.:_()#\-';
The reason why you end up on Google might however be something else (does not seem to be Codeigniter related)
Your browser don't think that that is a URL and navigates to google (thinking that you are searching something), I Think.
The main parts of URLs
A full BNF description of the URL syntax is given in Section 5.
In general, URLs are written as follows:
<scheme>:<scheme-specific-part>
A URL contains the name of the scheme being used () followed
by a colon and then a string (the ) whose
interpretation depends on the scheme.
Scheme names consist of a sequence of characters. The lower case
letters "a"--"z", digits, and the characters plus ("+"), period
("."), and hyphen ("-") are allowed. For resiliency, programs
interpreting URLs should treat upper case letters as equivalent to
lower case in scheme names (e.g., allow "HTTP" as well as "http").
Thus, only alphanumerics, the special characters "$-_.+!*'(),", and
reserved characters used for their reserved purposes may be used
unencoded within a URL.
schemepart = *xchar | ip-schemepart
See http://www.faqs.org/rfcs/rfc1738.html please.
{"0":"13","1":"24"} should be url encoded.
http://php.net/manual/en/function.urlencode.php
I think a better answer for this question would be to use the inbuilt uri to associative array handler. see http://www.codeigniter.com/user_guide/libraries/uri.html?highlight=uri
this stops all that nasty mucking about with config permitted uri characters.
your uri would be: getproducts/p1/0/p2/0/p3/0/p5/13/p6/1/p6/24
and the handler would be something like:
function get_product()
{
$object = $this->uri->uri_to_assoc(4);
}
You need to use URI class's
$this->uri->assoc_to_uri()
Manual wrote,
Takes an associative array as input and generates a URI string from it.
The array keys will be included in the string. Example:
$array = array('product' => 'shoes', 'size' => 'large', 'color' => 'red');
$str = $this->uri->assoc_to_uri($array);
// Produces: product/shoes/size/large/color/red
In my code, I create a link like this:
$link = 'http://www.mydomain.com/'.urlencode($str).'/1';
I use url-rewriting and the rule in my htaccess file looks like this:
rewriteRule ^(.+)/(.*)$ index.php?var1=$1&var2=$2 [NC,L]
This code is working fine for almost every strings. But sometimes, the string to encode contains "&". The urlencode function encodes it corectly, but when I read the $_GET array in php, it looks like this (with $str = 'substring1&substring2'):
'var1' => 'substring1' (without "&")
'substring2' => '' (without "&")
'var2' => 1
I really need the "&" in my var. Is there a way to encode that character to make it works?
Also, I really don't know why, but sometimes I get a forbidden http error with some strings passed as var1. Apparently, they have nothing special, for exemple, "Décarie Square" makes that error. Other strings with spaces and "é" are working fine.
Apache's mod_rewrite automatically decodes urlencoded strings when it does regex matching. But it only does this once, so you should be if you urlencode your string twice. This will re-escape all of those `%' characters.
try
$link = 'http://www.mydomain.com/'.urlencode(urlencode($str)).'/1';
or stop relying on rewrite rules and use a framework that handles URL routing properly.
Oh, and there should also be htmlentities() somewhere in there.
Apache will automatically translate (decode) the path. You must use a different encoding or even double encoding. Base 64 will work.
your $str isn't setup with key=val pairs
Try $str = 'var1=substr1&var2=substr2';
Two options:
Urlencode the string before urlencoding the query.
Replace all non alphanumerical chars with a dash or underscore
As for the forbidden error are you using http auth basic or digest?
Update may mistake try using htmlentities or htmlspecialchars instead of urlencode
I used the solution accepted for this question for encrypting by id for example in /index.php?id=3 . The problem is I cannot send the encrypted value as an url, example /index.php?id=dsf13f3343f23/23=. Because sometimes it will have weird characters in the url e.g. notice the = sign in the end
The weird characters in the values passed in the URL should be escaped, using urlencode().
For example, the following portion of code :
echo urlencode('dsf13f3343f23/23=');
would give you :
dsf13f3343f23%2F23%3D
Which works fine, as an URL parameter.
And if you want to build aquery string with several parameters, take a look at the http_build_query() function.
For example :
echo http_build_query(array(
'id' => 'dsf13f3343f23/23=',
'a' => 'plop',
'b' => '$^#test',
));
will give you :
id=dsf13f3343f23%2F23%3D&a=plop&b=%24%5E%40test
This function deals with escaping and concatenating the parameters itself ;-)
Use PHP's urlencode() function to encode the value before you put it into a URL.
string urlencode ( string $str )
This function is convenient when
encoding a string to be used in a
query part of a URL, as a convenient
way to pass variables to the next
page.
This function converts "weird" characters, such as =, into a format safe to put into a URL. You can use it like this:
Header('Location: /index.php?id=' . urlencode($id))
If you use Base64 to encode the binary value for the URL, there is also a variant with URL and filename safe alphabet.
You can use the strtr function to translate one from alphabet to the other:
$base64url = strtr($base64, '+/', '-_');
$base64 = strtr($base64url, '-_', '+/');
So you can use these functions to encode and decode base64url:
function base64url_encode($str) {
return strtr(base64_encode($str), '+/', '-_'));
}
function base64url_decode($base64url) {
return base64_decode(strtr($base64url, '-_', '+/'));
}
See also my answer on What is a good way to produce an short alphanumeric string from a long md5 hash?
There is no use in encrypting parameters.
Send it as is:
/index.php?id=3
nothing wrong with it.