Whenever I attempt to post something to my PHP Server, I receive the following message. It seems as if the code is connecting to the server, but no data is returned, and the pos
"name=%@&email=%@&phash=%@" is not a proper url-encoded string. Each key-value pair has to be separated by an '&' character, and each key from its value by an '=' character. Keys and values are both escaped by replacing spaces with the '+' character and then encoded by stringByAddingPercentEscapesUsingEncoding
.
See application/x-www-form-urlencoded.
You can find a recipe how to do this in this blog post.
As @elk said, you should replace spaces with +
. But you should percent-encode reserved characters (as defined in RFC2396).
Unfortunately, the standard stringByAddingPercentEscapesUsingEncoding
does not percent escape all of the reserved characters. For example, if the name was "Bill & Melinda Gates" or "Bill + Melinda Gates", stringByAddingPercentEscapesUsingEncoding
would not percent escape the &
or the +
(and thus the +
would have been interpreted as a space, and the &
would have been interpreted as delimiting the next POST
parameter).
Instead, use CFURLCreateStringByAddingPercentEscapes, supplying the necessary reserved characters in the legalURLCharactersToBeEscaped
parameter and then replace the spaces with +
. For example, you might define a NSString
category:
@implementation NSString (PercentEscape)
- (NSString *)stringForPostParameterValue:(NSStringEncoding)encoding
{
NSString *string = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)self,
(CFStringRef)@" ",
(CFStringRef)@";/?:@&=+$,",
CFStringConvertNSStringEncodingToEncoding(encoding)));
return [string stringByReplacingOccurrencesOfString:@" " withString:@"+"];
}
@end
Note, I was primarily concerned with the &
and +
, characters, but RFC2396 (which supersedes RFC1738) listed those additional characters as being reserved, so it's probably prudent to include all of those reserved characters in the legalURLCharactersToBeEscaped
.
Pulling this together, I might have code that posts the request as:
NSDictionary *params = @{@"name" : _nameField.text ?: @"",
@"email": _emailField.text ?: @"",
@"phash": [NSString stringWithFormat:@"%d",phashnum]};
NSURL *url = [NSURL URLWithString:kBaseURLString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:@"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:[self httpBodyForParamsDictionary:params]];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error)
NSLog(@"sendAsynchronousRequest error = %@", error);
if (data) {
// do whatever you want with the data
}
}];
Using a utility method:
- (NSData *)httpBodyForParamsDictionary:(NSDictionary *)paramDictionary
{
NSMutableArray *paramArray = [NSMutableArray array];
[paramDictionary enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
NSString *param = [NSString stringWithFormat:@"%@=%@", key, [obj stringForPostParameterValue:NSUTF8StringEncoding]];
[paramArray addObject:param];
}];
NSString *string = [paramArray componentsJoinedByString:@"&"];
return [string dataUsingEncoding:NSUTF8StringEncoding];
}