Загрузить изображение с iOS на PHP

Я пытаюсь загрузить изображение из своего приложения iOS на свой веб-сервер через PHP. Вот следующий код:

-(void)uploadImage {
    NSData *imageData = UIImageJPEGRepresentation(image, 0.8);   

    //1
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];

    //2
    NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];


    NSString *urlString = @"http://mywebserver.com/script.php";
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:urlString]];
    [request setHTTPMethod:@"POST"];
    NSString *boundary = @"---------------------------14737809831466499882746641449"
    ;
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
    [request addValue:contentType forHTTPHeaderField: @"Content-Type"];
    NSMutableData *body = [NSMutableData data];
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"Content-Disposition: form-data; name=\"userfile\"; filename=\"iosfile.jpg\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    [body appendData:[NSData dataWithData:imageData]];
    [body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [request setHTTPBody:body];

    //3
    self.uploadTask = [defaultSession uploadTaskWithRequest:request fromData:imageData];

    //4
    self.progressBarView.hidden = NO;
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];

    //5
    [uploadTask resume];
}

// update the progressbar
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.progressBarView setProgress:(double)totalBytesSent / (double)totalBytesExpectedToSend animated:YES];
    });
}

// when finished upload
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {

    dispatch_async(dispatch_get_main_queue(), ^{
        [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
        self.progressBarView.hidden = YES;
        [self.progressBarView setProgress:0.0];
    });

    if (!error) {
        // no error
        NSLog(@"no error");
    } else {
        NSLog(@"error");
        // error
    }

}

И следующий рабочий простой PHP-код:

<?php
$msg = " ".var_dump($_FILES)." ";
$new_image_name = $_FILES["userfile"]["name"];
move_uploaded_file($_FILES["userfile"]["tmp_name"], getcwd() . "/pictures/" . $new_image_name);
?>

Приложение на iOS, кажется, загружает фотографию, и индикатор выполнения работает, но файл на самом деле не загружается, когда я проверяю файлы сервера.

Когда я отправляю изображение со следующим кодом, он отлично работает (EDIT: но без индикатора выполнения):

NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];

И идея, где я ошибаюсь?


person Patrick L.    schedule 15.05.2014    source источник
comment
Есть ли причина, почему вы не используете код, который работает?   -  person 67cherries    schedule 15.05.2014
comment
@ 68cherries Это синхронно, не очень хорошая идея. Но sendAsynchronousRequest:queue:completionHandler: — это хорошая и простая замена метода синхронизации.   -  person zaph    schedule 15.05.2014
comment
@68cherries Я хотел бы отобразить индикатор выполнения, и, как я понимаю, единственный способ — использовать iOS7 NSURLSessionUploadTask   -  person Patrick L.    schedule 15.05.2014
comment
Если индикатор выполнения загружается, и вы не получаете никаких ошибок, я предполагаю, что что-то не так с кодом на стороне сервера. К сожалению, я ничего не знаю в php.   -  person 67cherries    schedule 15.05.2014
comment
@ 68cherries Вот почему я застрял, потому что не понимаю, почему это работает с NSURLConnection, а не с NSURLSessionUploadTask. Если он работает с первым, это означает, что код PHP в порядке, не так ли?   -  person Patrick L.    schedule 15.05.2014
comment
Я думаю, что мой NSMutableURLRequest *request плохо сконструирован для NSURLSessionUploadTask. Если кто-то может помочь, это будет оценено.   -  person Patrick L.    schedule 15.05.2014


Ответы (1)


Наконец, я использовал библиотеку AFNetworking, чтобы справиться с этим. Поскольку я не нашел четких способов сделать это в Интернете и в stackoverflow, вот мой ответ, чтобы легко публиковать изображения пользователя со своего устройства iOS на ваш сервер через PHP. Большая часть кода взята из этого сообщения stackoverflow.

-(void)uploadImage { 
    image = [self scaleImage:image toSize:CGSizeMake(800, 800)];
    NSData *imageData = UIImageJPEGRepresentation(image, 0.7);

    // 1. Create `AFHTTPRequestSerializer` which will create your request.
    AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializer serializer];

    NSDictionary *parameters = @{@"your_param": @"param_value"};

    NSError *__autoreleasing* error;
    // 2. Create an `NSMutableURLRequest`.
    NSMutableURLRequest *request = [serializer multipartFormRequestWithMethod:@"POST" URLString:@"http://www.yoururl.com/script.php" parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        [formData appendPartWithFileData:imageData
                                    name:@"userfile"
                                fileName:@"image.jpg"
                                mimeType:@"image/jpg"];
    } error:(NSError *__autoreleasing *)error];
    // 3. Create and use `AFHTTPRequestOperationManager` to create an `AFHTTPRequestOperation` from the `NSMutableURLRequest` that we just created.
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    AFHTTPRequestOperation *operation =
    [manager HTTPRequestOperationWithRequest:request
                                     success:^(AFHTTPRequestOperation *operation, id responseObject) {
                                         NSLog(@"Success %@", responseObject);
                                     } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                                         NSLog(@"Failure %@", error.description);
                                     }];

    // 4. Set the progress block of the operation.
    [operation setUploadProgressBlock:^(NSUInteger __unused bytesWritten,
                                        long long totalBytesWritten,
                                        long long totalBytesExpectedToWrite) {
        //NSLog(@"Wrote %lld/%lld", totalBytesWritten, totalBytesExpectedToWrite);
        [self.progressBarView setProgress:(double)totalBytesWritten / (double)totalBytesExpectedToWrite animated:YES];
    }];

    // 5. Begin!
    operation.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"application/json"];


    self.progressView.hidden = NO;
    [operation start];
}

Я думаю, это поможет новым xcoders.

Ваше здоровье.

person Patrick L.    schedule 15.05.2014
comment
Вы когда-нибудь узнавали, как это сделать с помощью NSURLSession? Я работаю над этим прямо сейчас, но у меня проблемы. - person marciokoko; 03.08.2014
comment
Вот мой пост, хотя некоторые SO'еры поторопились пометить его как дубликат! Заголовок stackoverflow.com/questions/25098056/ - person marciokoko; 03.08.2014
comment
@marciokoko Не мог понять, как это сделать с NSURLSession, но отлично работает с AFNetworking. Если вы сделаете это таким образом, вы получите более чистый код и сможете легче обрабатывать сетевые ошибки. - person Patrick L.; 05.08.2014