ASIHTTPRequest – Uploading Photos

Recently I used ASIHTTPRequest to upload images and other data from an iPhone application to a web server. I search around and looked at all the different options and this was best and easiest to use. It’s open source and comes with lots of good examples. I was particularly impressed with the network queue.

The one thing I did not find, was sample code for was posting an image to a server. Here is some sample code:

// Initilize Queue
[networkQueue setUploadProgressDelegate:statusProgressView];
[networkQueue setRequestDidFinishSelector:@selector(imageRequestDidFinish:)];
[networkQueue setQueueDidFinishSelector:@selector(imageQueueDidFinish:)];
[networkQueue setRequestDidFailSelector:@selector(requestDidFail:)];
[networkQueue setShowAccurateProgress:true];
[networkQueue setDelegate:self];

// Initilize Variables
NSURL *url;
ASIFormDataRequest * request;

// Add Image
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
     NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dataPath = [documentsDirectory
     stringByAppendingPathComponent:@"myImage.jpg"];

// Get Image
NSData *imageData = [[[NSData alloc]
     initWithContentsOfFile:dataPath] autorelease];

// Return if there is no image
if(imageData != nil){
	url = [NSURL URLWithString:@"http://myserver/upload.php"];
	request = [[[ASIFormDataRequest alloc] initWithURL:url] autorelease];
	[request setPostValue:@"myImageName" forKey:@"name"];
	[request setData:imageData forKey:@"file"];
	[request setDidFailSelector:@selector(requestWentWrong:)];
	[request setTimeOutSeconds:500];
	[networkQueue addOperation:request];
	queueCount++;
}
[networkQueue go];

Note: It’s not necessary to use a queue here because I’m only uploading 1 thing. But in my application I’m uploading many things and a queue was helpful. It also runs in the asynchronously in the background, which prevents the UI from getting locked up.

Note 2: When sending large files you should use “setFile” instead of “setData”. Files are then read from disk instead of memory. Here is an updated example. Thanks again to Ben Copsey for this library and his useful comments below.

NSString *imagePath = [documentsDirectory
     stringByAppendingPathComponent:@"myImage.jpg"];
url = [NSURL URLWithString:@"http://myserver/upload.php"];
ASIFormDataRequest *request =
    [[[ASIFormDataRequest alloc] initWithURL:url] autorelease];
[request setPostValue:@"myImageName" forKey:@"name"];
[request setFile:imagePath forKey:@"photo"];

More info on streaming here: http://allseeing-i.com/ASIHTTPRequest/How-to-use#streaming

Tags: , , ,
If you like this post and would like to receive updates from this blog, please subscribe our feed. Subscribe via RSS

16 Responses to “ASIHTTPRequest – Uploading Photos”

  1. Ben Copsey Says:

    Hi Doug

    I’m glad you find ASIHTTPRequest useful!

    It’s actually preferable to use a queue even if you only have one request, simply because it’s the easiest way to perform a request in the background. You can create synchronous requests without a queue, but you’ll lock the user interface until the request is complete, unless you want to create and manage threads for the requests yourself.

    Ben

  2. Ben Copsey Says:

    Also, if you are uploading several photos at once, use setFile:forKey: rather than setData:forKey:. This way, ASIFormDataRequest will know you’re sending a fair bit of data, and it will stream the request data from a temporary file on disk, which means you don’t need to keep lots of image data in memory.

    (See here for more info: http://allseeing-i.com/ASIHTTPRequest/How-to-use#streaming)

    Ben

  3. Bill Brookfield Says:

    Great Example, but your refer to upload.php. Where is the source for upload.php. I have tried several examples of php script, but none work. can you send me or post the PHP script you used in you example.

    Thanks

    Bill B

  4. Frank Says:

    Hey Doug & Ben,

    I had a quick question. I am using the first ASI queue code to attempt to upload a photo from the iPhone to a PHP based script.

    For some reason, all of the $_POST variables are coming in fine, but the $_FILE server variable is coming up blank. There is no record of the images being sent. I’m not sure if there is a problem or if I am just trying to access the information incorrectly on the server side.

    Any assistance would be greatly appreciated!!

    -Frank

  5. Colin Says:

    Hey Doug,
    What does the PHP end look like to receive the data? I’ve been having a hard time determining why my file uploads won’t work, if it’s because the way I’m sending it or the way it’s being received..

  6. Spark Says:

    Hi Doug and Ben,

    Great stuff, I am wondering if it is actually possible to use ASIHTTPRequest to post data from iphone to the Google App Engine’s datastore , and more specifically the google file service https://gae-file-service.appspot.com/

    Thanks

    Spark

  7. doug Says:

    Yeah. Here’s some sample python Google App Engine code with get’s the post data named file.

    if (‘file’ in self.request.POST and
    self.request.POST.get(‘file’, None) is not None and
    self.request.POST.get(‘file’, None).filename):

    file_data = self.request.POST.get(‘file’).file.read()

    image_length = len(file_data)

    if image_length > config.max_size:
    self.response.out.write(“IMAGE_TOO_LARGE”)
    return
    else:
    file_content_type = self.request.POST.get(‘file’).type
    file_name = self.request.POST.get(‘file’).filename

    try:
    my_model.image = db.Blob(file_data)
    my_model.imageName = file_name
    my_model.imageType = file_content_type
    my_model.imageLength = image_length
    my_model.put()

    except Exception, e:
    logging.exception(e)
    error = ‘Image error processing’
    self.response.out.write(‘ERROR_PROCESSING_IMAGE’)
    return

    logging.info(‘File name : %s’ % file_name)
    logging.info(‘Type : %s’ % file_content_type)
    logging.info(‘Length : %s’ % image_length)
    self.response.out.write(‘SUCCESS’)

    class MyModel(db.Model):
    image = db.BlobProperty()
    imageName = db.StringProperty()
    imageType = db.StringProperty()
    imageLength = db.IntegerProperty()

  8. Romulo Says:

    if I select an image from the Photo Library, how should I be able to use the setFile ?

  9. Frankie Says:

    How would integrate this using imagePickerController?
    would have a code sample?

  10. doug Says:

    Hi Frankie,
    There is lots of sample code out there for using the imagePicker. Basically you use some code, like I list below to save the image to the iPhone documents directory. Then you can point at this image later to upload it somewhere…

    - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo
    {
    NSLog(@”image width: %f image height: %f”, [image size].width, [image size].height);
    NSData * imageData = UIImagePNGRepresentation(image);
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:@"myfilename.jpg"];
    [imageData writeToFile:dataPath atomically:YES];
    [self dismissModalViewControllerAnimated:YES];
    }

  11. Forrest Says:

    How about uploading images to S3 ?

    And if I just want to create another Http Server in iPhone or Mac, are there any samples we can refer to first ?

    Thanks

  12. doug Says:

    I’m sorry, but I have no experience with Amazon S3.

  13. Forrest Says:

    Thanks ! I found that ASIHttpRequest provides some helps for S3. I will check them out.

    Another question about back end server. If I just want to write some server using cocoa to do similar thing like “php” did, to receive file from your uploading, is that easy to do ? Sorry I have really no experience on back end service etc.

  14. doug Says:

    I’ve never tried that before. What you’d need to do, is write an HTTP Server in cocoa. Here is a simple example:
    http://cocoawithlove.com/2009/07/simple-extensible-http-server-in-cocoa.html

  15. Bruno Fuster Says:

    Forrest, ASIHTTPRequest has built-in support for S3.

    http://brunofuster.wordpress.com/2010/11/03/uploading-an-image-from-iphone-with-uiimagepicker-and-asihttprequests3/

  16. bob Says:

    [[[NSData alloc] initWithContentsOfFile:dataPath] autorelease] can be written as [NSData dataWithContentsOfFile:dataPath]

Leave a Reply