Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Uploading Image NSData via POST and NSURLSession

I'm trying to upload a single UIImage to a server, and everything seems to be okay except that the image is never uploaded.

This is the code I'm using to upload the image in iOS:

const NSString *boundaryConstant = @"----------V2ymHFg03ehbqgZCaKO6jy";
const NSString *fileParamConstant = @"photo";

NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:@"POST"];

NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundaryConstant];
[request setValue:contentType forHTTPHeaderField:@"Content-Type"];

NSMutableData *body = [NSMutableData data];

ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library assetForURL:info[UIImagePickerControllerReferenceURL] resultBlock:^(ALAsset *asset) {
    ALAssetRepresentation *representation = [asset defaultRepresentation];

    // get byte size of image
    long long size = [representation size];
    unsigned char *bytes = malloc(size);

    // read image data into bytes array
    [representation getBytes:bytes fromOffset:0 length:size error:nil];

    NSData *imageData = [NSData dataWithBytesNoCopy:bytes length:size freeWhenDone:YES];

    if (imageData) {
        [body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundaryConstant] dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", fileParamConstant, filename] dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n",[SWNetworkController contentTypeForImageData:imageData]] dataUsingEncoding:NSUTF8StringEncoding]];
        [body appendData:imageData];
        [body appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    }

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

    NSString *postLength = [NSString stringWithFormat:@"%zu", [body length]];
    [request setValue:postLength forHTTPHeaderField:@"Content-Length"];

    [request setHTTPBody:body];

    NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:imageData completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        NSLog(@"STRING %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
        NSLog(@"%@", response);
        NSLog(@"%@", error);
    }];
    [uploadTask resume];
} failureBlock:^(NSError *error) {
    NSLog(@"Image error:\n%@",error);
}];

The server responds with a 200 OK status and no error, except the image is not received and nothing is returned from the server (this is expected if no image is uploaded).

Here is the server-side code:

<?
    $allowedExts = array("gif", "jpeg", "jpg", "png");
    $temp = explode(".", $_FILES["photo"]["name"]);
    $extension = end($temp);

    error_log(print_r($_FILES, true));

    if ((($_FILES["photo"]["type"] == "image/gif")
    || ($_FILES["photo"]["type"] == "image/jpeg")
    || ($_FILES["photo"]["type"] == "image/jpg")
    || ($_FILES["photo"]["type"] == "image/pjpeg")
    || ($_FILES["photo"]["type"] == "image/x-png")
    || ($_FILES["photo"]["type"] == "image/png"))
    && ($_FILES["photo"]["size"] < 20000000)
    && in_array($extension, $allowedExts)) {
      if ($_FILES["photo"]["error"] == 0) {
        $filename = sha1($_FILES['photo']['name'] . uniqid("",true));
            if (move_uploaded_file($_FILES['photo']['tmp_name'], 'pic/' . $filename . "." . $extension)) {
                // do stuff with the saved image here
            }
        }
    }
?>

A normal request (via the web interface) logs the following:

Array
(
    [photo] => Array
    (
        [name] => BoPzSyRIgAAe1h6.jpg-large.jpeg
        [type] => image/jpeg
        [tmp_name] => /var/tmp/phpjScXQB
        [error] => 0
        [size] => 67900
    )

)

Meanwhile, the request sent from iOS looks as follows:

Array
(
)

For the life of me, I can't figure out what's going wrong... Any ideas?

Thanks

like image 601
jaggedcow Avatar asked May 27 '14 00:05

jaggedcow


1 Answers

The problem was in NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:imageData completionHandler:...]

NSURLSessionUploadTask ignores the request body provided and adds the fromData: parameter as the request body. However, I was just providing the image data and not the properly formatted request body...

The fixed code is then NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:body completionHandler:...]

I'll leave my answer up in case anyone else stumbles across this problem again.

like image 153
jaggedcow Avatar answered Nov 15 '22 14:11

jaggedcow