Reputation: 18729
I would like to send some URL encoded data from a Swift app to a PHP API where the data is decoded again.
While this works fine most of the time, I now became aware that PHP urldecode handles the + sign differently than the Swift addingPercentEncoding and decodes the + to a space.
How can this be avoided?
// Swift
let data = "some+test"
let encodedData = data.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) // some+test
sendToMyServer(encodedData)
// PHP
$encodedData = $receivedData; // some+text
$decodedData = urldecode($encodedData); // some text
It seems that Swift does not consider the + sign in any of its build in (inverted) char sets:
URLFragmentAllowedCharacterSet "#%<>[\]^`{|}
URLHostAllowedCharacterSet "#%/<>?@\^`{|}
URLPasswordAllowedCharacterSet "#%/:<>?@[\]^`{|}
URLPathAllowedCharacterSet "#%;<>?[\]^`{|}
URLQueryAllowedCharacterSet "#%<>[\]^`{|}
URLUserAllowedCharacterSet "#%/:<>?@[\]^`
Is there a reason why PHP handles the + sign in this way?
What is the "correct" way to solve this? I assume I could simple define a custom char set which includes the + sign, but I am not sure if this might lead to other unexpected side effects. Is this safe or are there other differences in PHP urldecode which needs to be considered?
Upvotes: 0
Views: 382
Reputation: 26026
For the reason:
Doc of CharacterSet.urlHostAllowed
:
Returns the character set for characters allowed in a host URL subcomponent.
If we then go to implicitly linked doc of URLComponents
This structure parses and constructs URLs according to RFC 3986. Its behavior differs subtly from that of the URL structure, which conforms to older RFCs. However, you can easily obtain a URL value based on the contents of a URLComponents value or vice versa.
The doc of PhP urldecode
says:
Plus symbols ('+') are decoded to a space character.
The urlencode
says:
This differs from the » RFC 3986 encoding (see rawurlencode()) in that for historical reasons, spaces are encoded as plus (+) signs.
So iOS uses the RFC 3986
and PhP doesn't.
Solution:
Use the same encoding/decoding, by changing it on iOS or in the server.
For the server changes:
To use the same as iOS on the server side, use rawurldecode
(or rawurlencode
if needed), as it says:
rawurldecode() does not decode plus symbols ('+') into spaces. urldecode() does.
and
rawurlencode — URL-encode according to RFC 3986
For the iOS changes:
See Sajjad's answer
Upvotes: 1