GET forms are the easiest to do. You just tack on your variables to the end of the URL, like this:
http://www.nowhere.com/sendFormHere.php?key1=val1&key2=val2
Then you could use your standard NSURLDownload to fetch the file.
A POST form is pretty much the same thing, except you need to specify that you are sending a POST, and you need to stick your variables into the http body instead of tacking them onto the end of the URL.
Here's how to setup the URL request for a POST:
NSString *post = @"key1=val1&key2=val2";
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:@"http://www.nowhere.com/sendFormHere.php"]];
[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:postData];
And you can use this to setup your NSURLDownload. Pretty simple huh?
There is one last thing we need to tackle before you can start using this in your finished product. You need to make sure that the strings you use are properly encoded to go into your string. For example, imagine that one of your keys is called "name" and it's value is "Bob & Cindy". You can't have spaces like that in your URL (or inside the post string), so you'd have to escape the spaces like this "Bob%20&%20Cindy". But that's not all...
You would also need to encode the '&' symbol, because it has special meaning. (To seperate one key,value pair from another). And you'd also need to encode any '?' symbols, and any '=' symbols, and so on. But we don't want to have to write a custom method to do all this. Not when apple has already provided such a huge API for use to use. So what can we use to do this for use in 1 or 2 lines of code?
At first glance it looks like NSString's stringByAddingPercentEscapesUsingEncoding: method might work. But if you try it with the "Bob & Cindy" string above you'll find that it only encodes the spaces, and leaves the '&' symbol. But we see from the method's documentation that it uses Core Foundations CFURLCreateStringByAddingPercentEscapes method to do it's dirty work. And we can use this to do ours as well. Here is a method to do what we want:
- (NSString *)urlEncodeValue:(NSString *)str
{
NSString *result = (NSString *) CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)str, NULL, CFSTR("?=&+"), kCFStringEncodingUTF8);
return [result autorelease];
}
So to use the method you would write something like this:
NSString *post = [NSString stringWithFormat:@"key1=%@&key2=%@",
[self urlEncodeValue:val1]
[self urlEncodeValue:val2]];
31 comments:
A simple and excellent guide. I was about to write a post on the exact same thing, but it looks like you beat me to it!
I'm glad you included information on how to encode strings for GET and POST as omitting this can cause frustrating errors if you don't know what's going on.
Very good post. I found a 6-page article split in 3 parts on mactech.com about the same subject but this says exactly the same things in 1/6th the length ... and much simpler too.
Thanks for the tips :-)
Nice...although it seems like urlEncodeValue: should really be a category method on NSString...like stringByAddingQueryPercentEscapes. (Or leave in the encoding parameter... stringByAddingQueryPercentEscapesUsingEncoding:)
Or pick a nicer, less corresponding name.
Thanks that really helps. I am developing an iPhone app and I couldn't find anything on useful on HTTP POST with Objective-C and COCOA. Thanks again. Andrew Paul Simmons
Thanks a lot for the post info, it was just what I needed for my iPhone app.
Excellent, just what I was looking for. Thanks!
Typos:
"and it's value" --> "and its value"
"do it's dirty work" --> "do its dirty work"
Thanks a lot! Just needed for my iPhone app.
Ugh. I know I had this working but now I've been fighting with it all day and it is broken. Could I send you what I have? I am sure it is just something totally basic that I am missing.
Thank you! Just what I'm looking for!
You rock man, after 3 years...
Many thanx for the post.
Thanx for this!
more then 3 years later and it still helped me out a great deal...
This works perfectly.
Thank you so much!
Simple and great post.. thanks!
Thanks Alot Really was Helpful :D
Incredibly helpful. Apple should have a reference to this in the developer docs. Would save a lot of time for a lot of people.
Your URL encoding is wrong. You're not supposed to encode the "&" and "=" characters. Only the keys and values should be encoded.
Thanks a lot!
@ Dave, I am having trouble getting this working and wondered if it's for the reason you state (i.e. the & and = should not be encoded). But that begs the question how do I append them to the data if these characters are not encoded?
I have the key and argument "posts[quote]=somequote" as my key and argument. So how do make a data obj from this without encoding the whole lot or splitting it and appending [posts[quote] datausingencoding... and then dataByAppending: @"=" ?!?
I am confused how this would work or is that perfectly OK? Sorry I am a bit of a newbie :-) cheers
Thank you for this!!! I've been looking for this for some time.
People are rarely as straight forward in their explanations as you are.
Excellent guide. Thanks a lot!
Thank you for the tip!
Good to see that you encoded it, too bad there isn't already a decent selector that I know of for creating http request arguments. I had to write a bit more code to completed your selector, as follows:
- (NSString *)httpArgumentsFromDictionary:(NSDictionary *)dict {
NSString *argumentList = [[NSString new] autorelease];
for (NSString *aKey in dict) {
NSString *rawValue = [dict valueForKey:aKey];
NSString *encodedvalue = [self urlEncodeValue:rawValue];
NSString *kvPair;
if([argumentList length]==0) {
kvPair = @"%@?%@=%@";
} else {
kvPair = @"%@&%@=%@";
}
argumentList = [NSString stringWithFormat:kvPair,argumentList,aKey,encodedvalue];
}
return argumentList;
}
an example of using the selector i wrote is as follows:
NSString *hogTestScript = @"hogTest.php";
NSArray *keys = [NSArray arrayWithObjects:@"fileName",@"bytesBeforeSleep",@"sleepSeconds",˙nil];
NSArray *values = [NSArray arrayWithObjects:mp4FileName,@"2048",@"5",nil];
NSDictionary *requestArgumentsDictionary = [NSDictionary dictionaryWithObjects:values forKeys:keys];
NSString *reqArguments = [self.utils httpArgumentsFromDictionary:requestArgumentsDictionary];
NSString *sourceURL = [NSString stringWithFormat:@"%@%@%@",webDocumentBase,hogTestScript,reqArguments];
What I do is I create a dictionary of keys and values to use in my http request then I run my selector on it to return a string which I concatenate onto my php script web address.
I hope you find it useful!
For anyone else who runs into this, the original code + encoding is just fine! You encode & = INSIDE the values, which is exactly what the code is doing.
key1=val1&key2=value2&key3=val3
Here, key1,val1,key2,val2,key3,val3 should have & or =encoded, otherwise their = & will get confused with the above string that separates the keys and values. Makes sense?
But the problem with the code is that you need to tack on
[[NSURLDownload alloc] initWithRequest:request delegate:self];
to the end, otherwise it doesn't actually do anything. :P
Also configure a delegate as here: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLDownload.html
Many thanks..
I want to post the values and open the url (for proxy pay). Is it possible?
Jabz padoor
A few years late but it has to be said...
Trevor you are wrong about the typos.
just wanted to say thanks - a real time-saver.
Trevor is correct about the typos. "it's" == "it is"
So the uses don't make any sense:
"...and it is value is..."
"...do it is dirty work..."
http://garyes.stormloader.com/its.html
Oh, brother. Is this an English class now? I don't think the post is any less understandable with the typos. I suppose us coders are trained to be syntax junkies!
For what it's worth, possessive personal pronouns, serving as either noun-equivalents or adjective-equivalents, do not use an apostrophe, even when they end in s. The complete list of those ending in the letter s or the corresponding sound /s/ or /z/ but not taking an apostrophe is ours, yours, his, hers, its, theirs, and whose. That's a sneaky one, isn't it?
But we digress... ;)
Thanks for the excellent post. Very helpful indeed.
It's not working for me.
I've copied your Objective-C code but in PHP I'm not getting any _POST variable at all, I'm dumping, all _POST, _SERVER, _GET, _ENV, and so on variables to a file but no data at all is posted.
And the _ENV variable says that it's a GET request.
Any ideas what it can be?
Post a Comment