I am doing a post HTTP request in swift 4.2 and in one of my Strings I put in the parameters contain "&" but apparently the requests gets cut off after this symbol. I thought about replacing every "&" symbol with a unique placeholder and convert it back in PHP.
But is there are more elegant or easy way of doing this?
URL encode your data (and decode it when you need to use it), that will make the ampersand into %26 which will stop it cutting off in your GET request.
You could replace the "&" with "%26" and then it's have to work :)
All Precent-encoding characters:
https://en.wikipedia.org/wiki/Percent-encoding#Percent-encoding_reserved_characters
You should probably minimize how much manual percent escaping you do. You might, for example, use URLComponents to build your URL and percent escape it for you:
guard var components = URLComponents(string: "http://example.com") else { return }
components.queryItems = [URLQueryItem(name: "foo", value: "bar&baz")]
let url = components.url
That will result in:
http://example.com?foo=bar%26baz
The ampersand, as well as a few other characters, need to be encoded if they are within a query parameter otherwise they could be recognized as a delimiter of some sort.
You can encode a string for a query param in Swift like this:
let value = string.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
let urlString = "https://example.com/?query=\(value)"
On the other side, your server will receive the encode param value but will need to decode it.
PHP includes the urlencode() and urldecode() functions, and stift includes the .addingPercentEncoding function.
This means you can replace with the encoded version of the '&' symbol which is '%26', or you can use swift's function
Then when you recieve this value you can use urldecode( $escapedString ), or just replace '%26' with '&', or just pull the values stright from the request with $_GET.
Why do we not encode = and & in query strings? I am referencing RFC 3986 but cannot find where it says that we should not encode these characters. Using Guzzle, it doesn't seem they encode anything really.
Take for example the query string: key1='1'&key2='2', shouldn't this be encoded as key1%3D%271%27%26key2%3D%272%27? If I plug key1='1'&key2='2' into chrome as a query string (e.g. www.google.com?key1='1'&key2='2'), it appears as key1=%271%27&key2=%272%27, which does not match guzzle. Guzzle outputs key1='1'&key2='2'. Guzzle's encoding algorithm is below:
private static $charUnreserved = 'a-zA-Z0-9_\-\.~';
private static $charSubDelims = '!\$&\'\(\)\*\+,;=';
public function encode()
{
return preg_replace_callback(
'/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:#\/\?]++|%(?![A-Fa-f0-9]{2}))/',
function ($match) {
return urlencode($match[0]);
},
$str
);
}
= and & don't have any special meaning as part of URL syntax. As far as URL syntax is concerned, they're just ordinary characters.
However, when used in query strings, there's a convention implemented by most application frameworks to use them to delimit parameters and values. If you want to use these characters literally in a parameter name or value, you need to encode them. See escaping ampersand in url
I am using the following code to encode a URL for basic hiding of the URL
/lbs_map.php?msisdn=27827910118
This is what I do not want my clients to see. I have coded it the following way
<a href="lbs_map.php?msisdn=<?php echo base64_encode ("27".substr($rows['member_msisdn'],
1)); ?>
This is my output now:
/lbs_map.php?msisdn=Mjc4Mjc5MTAxMTk=
I am using this to try and decode the string:
<?php
$str = 'VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw==';
echo base64_decode($str);
?>
But it is not working at all to decode it and give me the required info i want. I need help on the decoding of the string
The encode string must work with the code string as the code string varies and is never the same
If you're passing base64 encoded data via the url, you need to urlencode() it first as = is a reserved character in urls.
You need to urlencode() the msisdn parameter.
Also keep in mind that base64 is not the way to go if you want to hide something from your users as it's not an encryption function and can be easily decoded.
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.
How can I test if a string is URL encoded?
Which of the following approaches is better?
Search the string for characters which would be encoded, which aren't, and if any exist then its not encoded, or
Use something like this which I've made:
function is_urlEncoded($string){
$test_string = $string;
while(urldecode($test_string) != $test_string){
$test_string = urldecode($test_string);
}
return (urlencode($test_string) == $string)?True:False;
}
$t = "Hello World > how are you?";
if(is_urlEncoded($sreq)){
print "Was Encoded.\n";
}else{
print "Not Encoded.\n";
print "Should be ".urlencode($sreq)."\n";
}
The above code works, but not in instances where the string has been doubly encoded, as in these examples:
$t = "Hello%2BWorld%2B%253E%2Bhow%2Bare%2Byou%253F";
$t = "Hello+World%2B%253E%2Bhow%2Bare%2Byou%253F";
i have one trick :
you can do this to prevent doubly encode.
Every time first decode then again encode;
$string = urldecode($string);
Then do again
$string = urlencode($string);
Performing this way we can avoid double encode :)
Here is something i just put together.
if ( urlencode(urldecode($data)) === $data){
echo 'string urlencoded';
} else {
echo 'string is NOT urlencoded';
}
You'll never know for sure if a string is URL-encoded or if it was supposed to have the sequence %2B in it. Instead, it probably depends on where the string came from, i.e. if it was hand-crafted or from some application.
Is it better to search the string for characters which would be encoded, which aren't, and if any exist then its not encoded.
I think this is a better approach, since it would take care of things that have been done programmatically (assuming the application would not have left a non-encoded character behind).
One thing that will be confusing here... Technically, the % "should be" encoded if it will be present in the final value, since it is a special character. You might have to combine your approaches to look for should-be-encoded characters as well as validating that the string decodes successfully if none are found.
I think there's no foolproof way to do it. For example, consider the following:
$t = "A+B";
Is that an URL encoded "A B" or does it need to be encoded to "A%2BB"?
well, the term "url encoded" is a bit vague, perhaps simple regex check will do the trick
$is_encoded = preg_match('~%[0-9A-F]{2}~i', $string);
What about:
if (urldecode(trim($url)) == trim($url)) { $url_form = 'decoded'; }
else { $url_form = 'encoded'; }
Will not work with double encoding but this is out of scope anyway I suppose?
There's no reliable way to do this, as there are strings which stay the same through the encoding process, i.e. is "abc" encoded or not? There's no clear answer. Also, as you've encountered, some characters have multiple encodings... But...
Your decode-check-encode-check scheme fails due to the fact that some characters may be encoded in more than one way. However, a slight modification to your function should be fairly reliable, just check if the decode modifies the string, if it does, it was encoded.
It won't be fool proof of course, as "10+20=30" will return true (+ gets converted to space), but we're actually just doing arithmetic. I suppose this is what you're scheme is attempting to counter, I'm sorry to say that I don't think there's a perfect solution.
HTH.
Edit:
As I entioned in my own comment (just reiterating here for clarity), a good compromise would probably be to check for invalid characters in your url (e.g. space), and if there are some it's not encoded. If there are none, try to decode and see if the string changes. This still won't handle the arithmetic above (which is impossible), but it'll hopefully be sufficient.
#user187291 code works and only fails when + is not encoded.
I know this is very old post. But this worked to me.
$is_encoded = preg_match('~%[0-9A-F]{2}~i', $string);
if($is_encoded) {
$string = urlencode(urldecode(str_replace(['+','='], ['%2B','%3D'], $string)));
} else {
$string = urlencode($string);
}
send a variable that flags the decode when you already getting data from an url.
?path=folder/new%20file.txt&decode=1
In my case I wanted to check if a complete URL is encoded, so I already knew that the URL must contain the string https://, and what I did was to check if the string had the encoded version of https:// in it (https%3A%2F%2F) and if it didn't, then I knew it was not encoded:
//make sure $completeUrl is encoded
if (strpos($completeUrl, urlencode('https://')) === false) {
// not encoded, need to encode it
$completeUrl = urlencode($completeUrl);
}
in theory this solution can be used with any string that has characters that gets encoded, as long as you know part of the string (https:// in this example) will always exists in what you are trying to check.
I am using the following test to see if strings have been urlencoded:
if(urlencode($str) != str_replace(['%','+'], ['%25','%2B'], $str))
If a string has already been urlencoded, the only characters that will changed by double encoding are % (which starts all encoded character strings) and + (which replaces spaces.) Change them back and you should have the original string.
Let me know if this works for you.
I found.
The url is For Exapmle: https://example.com/xD?foo=bar&uri=https%3A%2F%2Fexample.com%2FxD
You need Found $_GET['uri'] is encoded or not:
preg_match("/.*uri=(.*)&?.*/", $_SERVER['REQUEST_URI'], $r);
if (isset($_GET['uri']) && urldecode($r['1']) === $r['1']) {
// Code Here if url is not encoded
}
private static boolean isEncodedText(String val, String... encoding) throws UnsupportedEncodingException
{
String decodedText = URLDecoder.decode(val, TransformFetchConstants.DEFAULT_CHARSET);
if(encoding != null && encoding.length > 0){
decodedText = URLDecoder.decode(val, encoding[0]);
}
String encodedText = URLEncoder.encode(decodedText);
return encodedText.equalsIgnoreCase(val) || !decodedText.equalsIgnoreCase(val);
}