当前位置: 动力学知识库 > 问答 > 编程问答 >

ios - AFNetworking upload UIImage as NSData -> PHP Script move file

问题描述:

I know that this question was posted many times. I tried to get my code work, but can't find the problem. Please help me.

In my App the user takes a photo and this should be uploaded to a webserver.

here is my iOS Code:

NSData *data = UIImageJPEGRepresentation([UIImage imageNamed:@"oeffnungszeiten.jpg"], 1.0);

NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:BaseURLString parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {

[formData appendPartWithFileData:data name:@"uploadedfile" fileName:_imageString mimeType:@"image/jpeg"];

} error:nil];

AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];

manager.responseSerializer = [AFHTTPResponseSerializer serializer];

NSProgress *progress = nil;

NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:request progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {

if (error) {

NSLog(@"Error: %@", error);

} else {

NSLog(@"%@ %@", response, responseObject);

}

}];

[uploadTask resume];

and here is my PHP Code:

<?php

error_log("\n-->".$FILES["uploadedfile"]['name'], 3, "log.txt");

$target_path = "/";

$target_path = $target_path . basename( $_FILES['uploadedfile']['name']);

if (!$FILES["uploadedfile"]) {

error_log("\nleer", 3, "log.txt");

}

if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {

echo "The file ". basename( $_FILES['uploadedfile']['name']).

" has been uploaded";

error_log("The file ". basename( $_FILES['uploadedfile']['name']).

" has been uploaded", 3, "log.txt");

} else{

echo "There was an error uploading the file, please try again!";

error_log("There was an error uploading the file, please try again!", 3, "log.txt");

}

?>

Can you find my fault? No image send to server!

网友答案:

A couple of thoughts:

  1. Some servers do not handle chunked requests. (A Transfer-encoding of chunked is traditionally a way of streaming requests to a server where the Content-length is unknown in advance.) The way you create a chunked request in NSURLSession is to use a NSInputStream with the request rather than a NSData or file.

    Unfortunately, AFNetworking always uses NSInputStream technique (for multipart requests, at least), meaning that all requests are streamed to the server using a Transfer-encoding of chunked. You can, though, after making your request, create a NSData from the NSInputStream, eliminate the HTTPBodyStream from the request, and then use the upload task factory method that uses a NSData rather than a streamed request.

    NSMutableURLRequest *request = ... ; // create the request like you are now
    
    // create `NSData` from the `NSInputStream`
    
    NSMutableData *requestData = [NSMutableData data];
    u_int8_t buffer[1024];
    NSInteger length;
    
    [request.HTTPBodyStream open];
    
    do {
        length = [request.HTTPBodyStream read:buffer maxLength:sizeof(buffer)];
        if (length > 0)
            [requestData appendBytes:buffer length:length];
    } while (length > 0);
    
    [request.HTTPBodyStream close];
    
    // now that we have our `NSData`, we can remove `HTTPBodyStream` from request
    
    request.HTTPBodyStream = nil;
    request.HTTPBody = nil;
    
    // instead of uploadTaskWithStreamedRequest, actually specify the `NSData` for the body of the request
    
    NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithRequest:request fromData:requestData progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
        if (error) {
            NSLog(@"Error: %@", error);
        } else {
            NSLog(@"%@ %@", response, responseObject);
        }
    }];
    
    [uploadTask resume];
    

    This is admittedly a bit inefficient (you could reduce the memory footprint by streaming this to a file rather than a NSData and then using that in your upload task), but this is the only way I know of to force AFNetworking to not make a streamed, chunked request for multipart requests. Therefore, I'd suggest only going through this exercise if your server does not accept chunked requests.

  2. If your server issues an authentication challenge, there is a bug in AFNetworking that can cause problems for you. (If you're not receiving any authentication challenges, this bug will not manifest itself for you and you don't have to worry about this.)

    Looking at this in Charles, I notice that AFNetworking correctly specifies the boundary in the header of the request, but when the boundary is used in the body of the request that is reissued after the authentication challenge, the body part's boundary becomes nil. This is because of a bug in copyWithZone for AFHTTPBodyPart. I've issued a pull request that remedies this problem.

    If you'd like to fix this in your local copy by going to AFSerialization.h and replacing the copyWithZone of AFHTTPBodyPart:

    - (id)copyWithZone:(NSZone *)zone {
        AFHTTPBodyPart *bodyPart = [[[self class] allocWithZone:zone] init];
    
        bodyPart.stringEncoding = self.stringEncoding;
        bodyPart.headers = self.headers;
        bodyPart.bodyContentLength = self.bodyContentLength;
        bodyPart.body = self.body;
    
        return bodyPart;
    }
    

    with

    - (id)copyWithZone:(NSZone *)zone {
        AFHTTPBodyPart *bodyPart = [[[self class] allocWithZone:zone] init];
    
        bodyPart.stringEncoding = self.stringEncoding;
        bodyPart.headers = self.headers;
        bodyPart.bodyContentLength = self.bodyContentLength;
        bodyPart.body = self.body;
        bodyPart.boundary = self.boundary;
    
        return bodyPart;
    }
    

    I've simply added boundary to the list of properties that must be copied when the object is copied.

  3. Unrelated to your original question, you have a line that says:

    NSData *data = UIImageJPEGRepresentation([UIImage imageNamed:@"oeffnungszeiten.jpg"], 1.0);
    

    This process of round-tripping it through a UIImage will not return the same object as the original file. First, it could potentially be much larger than your original file given that you're using a quality factor of 1.0. You're also stripping any meta data (e.g. date it was shot, camera used, camera settings, etc.).

    If that's your intent, that's fine, but generally you would just send the original JPEG:

    NSURL *imageFileURL = [[NSBundle mainBundle] URLForResource:@"oeffnungszeiten" withExtension:@"jpg"];
    NSData *data = [NSData dataWithContentsOfURL:imageFileURL];
    
分享给朋友:
您可能感兴趣的文章:
随机阅读: