【问题标题】:AFNetworking upload UIImage as NSData -> PHP Script move fileAFNetworking 将 UIImage 上传为 NSData -> PHP 脚本移动文件
【发布时间】:2014-04-20 19:29:37
【问题描述】:

我知道这个问题被发布了很多次。我试图让我的代码工作,但找不到问题。请帮我。 在我的应用程序中,用户拍照并应将其上传到网络服务器。

这是我的 iOS 代码:

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];

这是我的 PHP 代码:

<?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");
}
?>

你能找出我的错吗?没有图像发送到服务器!

【问题讨论】:

  • 当你运行它时,究竟会发生什么?你得到什么回应?有任何错误信息吗?
  • 我明白了:&lt;NSHTTPURLResponse: 0x10adaef80&gt; { URL: http://www....URLTOMYSCRIPT... } { status code: 200, headers { Connection = close; "Content-Length" = 0; "Content-Type" = "text/html"; Date = "Sat, 15 Mar 2014 11:47:38 GMT"; Server = Apache; } } &lt;&gt; and $FILES["uploadedfile"]['name'] 是空的。

标签: php ios upload afnetworking-2


【解决方案1】:

一些想法:

  1. 有些服务器不处理chunked 请求。 (chunkedTransfer-encoding 传统上是一种将请求流式传输到服务器的方式,其中Content-length 事先未知。)在NSURLSession 中创建chunked 请求的方式是使用NSInputStream使用请求而不是 NSData 或文件。

    不幸的是,AFNetworking 总是使用NSInputStream 技术(至少对于多部分请求),这意味着所有请求都使用Transfer-encodingchunked 流式传输到服务器。但是,您可以在发出请求后,从NSInputStream 创建一个NSData,从请求中删除HTTPBodyStream,然后使用使用NSData 而不是流式请求的上传任务工厂方法。

    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];
    

    诚然,这有点低效(您可以通过将其流式传输到文件而不是 NSData 然后在您的上传任务中使用它来减少内存占用),但这是我所知道的强制 AFNetworking 的唯一方法不要对多部分请求进行流式chunked 请求。因此,我建议仅在您的服务器不接受 chunked 请求时进行此练习。

  2. 如果您的服务器发出身份验证质询,则 AFNetworking 中存在可能给您带来问题的错误。 (如果您没有收到任何身份验证质询,则此错误不会为您显现,您不必担心。)

    Charles 中看到这个,我注意到AFNetworking 正确指定了请求标头中的边界,但是当在身份验证质询后重新发出的请求的主体中使用边界时,主体部分的边界变为nil。这是因为copyWithZone 中针对AFHTTPBodyPart 的错误。我已经发布了一个 pull request 来解决这个问题。

    如果您想在本地副本中解决此问题,请转到 AFSerialization.h 并替换 AFHTTPBodyPartcopyWithZone

    - (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;
    }
    

    - (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;
    }
    

    我只是将boundary 添加到复制对象时必须复制的属性列表中。

  3. 与您的原始问题无关,您有一行说:

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

    这个通过UIImage 往返的过程不会返回与原始文件相同的对象。首先,考虑到您使用的品质因数为1.0,它可能比您的原始文件大得多。您还将剥离任何元数据(例如拍摄日期、使用的相机、相机设置等)。

    如果这是您的意图,那很好,但通常您只需发送原始 JPEG:

    NSURL *imageFileURL = [[NSBundle mainBundle] URLForResource:@"oeffnungszeiten" withExtension:@"jpg"];
    NSData *data = [NSData dataWithContentsOfURL:imageFileURL];
    

【讨论】:

  • 嗨,罗伯。首先,我要感谢您的时间和详细的答复。好的。这是第 1 点和第 3 点的组合。身份验证没有问题。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-04
  • 1970-01-01
  • 2011-09-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多