s4lfish
s4lfish

Reputation: 633

Multipart/Formdata image upload, get the file

in my app i want to upload an image chosen via UIImagePickerController to a database which only accepts JPEG images. I've browsed many questions in here, and in other forums but i still didn't get it to work. I hope you can check my code, if there is a mistake which i can't see. This is the complete method for uploading, with an image description, an image title, and the geodata for this image:

- (void) uploadPic{
    NSArray  *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *destinationFilePath = [[NSString alloc] initWithFormat: @"%@/%@.jpeg", documentsDirectory, self.chosenImage.imgTitle];
    NSURL *fileURL = [[NSURL alloc]initWithString:destinationFilePath];
    NSLog(@"will upload file: %@", destinationFilePath);

    NSData *imageURLdata = [[NSData alloc]initWithContentsOfURL:fileURL];   (*1) 
    NSData *imageData = UIImageJPEGRepresentation(self.chosenImage, 90);    (*2) 
    //Here i tried 2 ways of getting the data for uploading, but both don't work.

    // create the URL
    NSURL *postURL = [NSURL URLWithString:@"http://*********/PictureUpload"];

    // create the connection
    NSMutableURLRequest *postRequest = [NSMutableURLRequest requestWithURL:postURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];

    // change type to POST (default is GET)
    [postRequest setHTTPMethod:@"POST"];

    // just some random text that will never occur in the body
    NSString *stringBoundary = @"0xKhTmLbOuNdArY---This_Is_ThE_BoUnDaRyy---pqo";

    // header value, user session ID added
    NSString *headerBoundary = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",
                                sessionID];

    // set header
    [postRequest addValue:headerBoundary forHTTPHeaderField:@"Content-Type"];
    // create data
    NSMutableData *postBody = [NSMutableData data];

    // title part
    [postBody appendData:[[NSString stringWithFormat:@"--%@\r\n", stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"title\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[self.chosenImage.imgTitle dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];

    // desc part
    [postBody appendData:[[NSString stringWithFormat:@"--%@\r\n", stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"desc\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[self.chosenImage.imgDescription dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];


    // latitude part
    [postBody appendData:[[NSString stringWithFormat:@"--%@\r\n", stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"latitude\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[self.chosenImage.latitude dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];

    // longitude part
    [postBody appendData:[[NSString stringWithFormat:@"--%@\r\n", stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"longitude\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[self.chosenImage.longitude dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];

    // media part
    [postBody appendData:[[NSString stringWithFormat:@"--%@\r\n", stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"file\"; filename=\"%@.jpeg\"\r\n", self.chosenImage.imgTitle ] dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[@"Content-Type: image/jpeg\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    [postBody appendData:[NSData dataWithData:imageURLdata]];
    [postBody appendData:[@"Content-Transfer-Encoding: binary\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];

    // final boundary
    [postBody appendData:[[NSString stringWithFormat:@"--%@--\r\n", stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
    NSString *s = [[NSString alloc] initWithData:postBody encoding:NSASCIIStringEncoding];
    NSLog(@"%@", s);

    // add body to post
    [postRequest setHTTPBody:postBody];

    // pointers to some necessary objects
    NSURLResponse* response;
    NSError* error;

    // synchronous filling of data from HTTP POST response
    NSData *responseData = [NSURLConnection sendSynchronousRequest:postRequest returningResponse:&response error:&error];

    if (error)
    {
        NSLog(@"Error: %@", [error localizedDescription]);
    }

    // convert data into string
    NSString *responseString = [[NSString alloc] initWithBytes:[responseData bytes]
                                                        length:[responseData length]
                                                      encoding:NSUTF8StringEncoding];

    // see if we get a welcome result
    NSLog(@"%@", responseString);
    [self responseHandler:responseString];

}

The GEOimage chosenImage is created via the CGImageRef after an UIImage is chosen in the ImagePickerController. Method nr. *1 to get the NSData for upload is not the best, because here the image is chosen from the document directory, and here every EXIF information about the image is deleted. With both methods i get the response from the database that the image filetype is not supported (JPEG expected). I thought with method nr. *2 i'm sending an JPEG image, but perhaps i have a mistake in the whole multipart/formdata process.

I tried to get the URL to the original file on the filesystem, but this is quite difficult for me. I only got the assets-url from the image.

Thanks in advance

S4lfish

Upvotes: 2

Views: 8339

Answers (2)

Ashish
Ashish

Reputation: 11

// Try this ---->>>

   NSMutableDictionary *post_dic=[[NSMutableDictionary
   alloc]initWithCapacity:20]; [post_dic setObject:firstName_txtFld.text
   forKey:@"firstname"]; [post_dic setObject:lastName_txtFld.text
   forKey:@"lastname"]; [post_dic setObject:email_txtFld.text
   forKey:@"email"]; [post_dic setObject:password_txtFld.text
   forKey:@"password"]; [post_dic setObject:country_txtFld.text
   forKey:@"address"]; [post_dic setObject:state_txtFld.text
   forKey:@"state"]; [post_dic setObject:city_txtFld.text
   forKey:@"city"]; [post_dic setObject:zip_txtFld.text forKey:@"zip"];
   [post_dic setObject:phoneNumber_txtFld.text forKey:@"phonenumber"];   
   NSURL *url = [NSURL URLWithString:@"Enter your url"];
   NSMutableURLRequest *urlRequest = [NSMutableURLRequest
   requestWithURL:url]; [urlRequest setHTTPMethod:@"POST"]; [urlRequest
   setHTTPBody:[urlString dataUsingEncoding:NSUTF8StringEncoding]];
            NSString *boundary = @"--------------------------14737809831466499882746641449"; NSString
   *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
   [urlRequest addValue:contentType
   forHTTPHeaderField: @"Content-Type"];
          NSMutableData *postbody = [NSMutableData data];
          for (NSString *param in post_dic) {
        [postbody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary]
  dataUsingEncoding:NSUTF8StringEncoding]];
        [postbody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data;
   name=\"%@\"\r\n\r\n", param]
   dataUsingEncoding:NSUTF8StringEncoding]];
        [postbody appendData:[[NSString stringWithFormat:@"%@\r\n", [post_dic objectForKey:param]]
   dataUsingEncoding:NSUTF8StringEncoding]];
            }
       [postbody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary]
   dataUsingEncoding:NSUTF8StringEncoding]];
       [postbody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data;
   name=\"filedata\";
   filename=\"%@.jpg\"\r\n",@"text"]
   dataUsingEncoding:NSUTF8StringEncoding]];
       [postbody appendData:[@"Content-Type: application/octet-stream\r\n\r\n"
   dataUsingEncoding:NSUTF8StringEncoding]];
       //NSLog(@" image -->%@",imageData);
       [postbody appendData:[NSData dataWithData:imageData]];
       [postbody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary]
   dataUsingEncoding:NSUTF8StringEncoding]];
        [urlRequest setHTTPBody:postbody]; [urlRequest setURL:url]; 
        NSURLConnection *connection=[[NSURLConnection alloc] initWithRequest:urlRequest  delegate:self]; 
[connection start];

Upvotes: 0

David Smith
David Smith

Reputation: 910

You've probably solved it on your own by now, but I think I see your problem.

NSString *stringBoundary = @"0xKhTmLbOuNdArY---This_Is_ThE_BoUnDaRyy---pqo";

// header value, user session ID added
NSString *headerBoundary = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",
                            sessionID];

When you're defining the boundary inside the MIME header, you're using your sessionID as the boundary. Then, down below, you're using your stringBoundary variable to create the actual boundaries.

[postBody appendData:[[NSString stringWithFormat:@"--%@\r\n", stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];

It might also be a good idea to provide the Content-Length of each MIME block to help the processing code, but I don't think that's at issue here.

Upvotes: 2

Related Questions