NSURLSessionUploadTask не передает файл в php-скрипт

EDIT: Хорошо, я просто установил заголовок типа контента для multipart / form-data без разницы. Мой первоначальный вопрос ниже:


Это мой первый вопрос о переполнении стека, я надеюсь, что все правильно.

Я изучаю Objective-C, недавно завершив онлайн-версию курса Стэнфорда. Я ничего не знаю о php и html. Сценарий php и используемый мной html в основном копируются с учебника. Obj-C имеет больше смысла для меня.

Проблема:

У меня есть php-скрипт. Он загружает файл изображения. Он корректно работает при вызове из html-файла в той же папке на сервере. Я пытаюсь заставить тот же скрипт работать, когда он вызывается из моего obj-c. Кажется, что он запускается, он возвращает 200, obj-c вызывает php, но в онлайновой папке не появляется файл.

Похоже, об этом в Интернете очень мало, поскольку он был введен только в ios7. Никаких примеров, которые я нашел, касаются загрузки файлов, все они имеют дело с загрузкой и просто говорят, что загрузка похожа. То, что я сделал, похоже, удовлетворяет любым учебникам, которые я нашел.

Я знаю, что:

  • php работает, и файл загружается, когда он вызывается из html-файла на сервере
  • obj-c определенно вызывает скрипт php (я написал несколько протоколов (используя file_put_contents) в php, который подтверждает, что скрипт вызывается при запуске obj-c)
  • obj-c почти определенно загружает файл изображения (если я использую метод делегата в obj-c, он показывает ход загрузки)
  • но php-скрипт не получает файл (журнал, который я написал в php, показывает, что $ _FILES не имеет значения при вызове из obj-c. При вызове из html он работает так, как ожидалось)
  • Я только что редактировал php, чтобы записывать заголовки, которые он получает, и он получает Content-Length файла изображения.

Что может быть важно :

  • Я не добавляю заголовки html, никаких учебных пособий, которые, как я видел, не имеют, я должен (с NSURLSessionUploadTask), я предполагаю, что NSURLSessionUploadTask сортирует это для вас? Или это моя проблема?
  • [описание ответа] возвращает 200, quote: {URL: (URL-адрес скрипта PHP)} {код состояния: 200, заголовки {Connection = "Keep-Alive"; «Content-Type» = «text / html»; Date = "Thu, 16 Jan 2014 19:58:10 GMT"; «Keep-Alive» = «timeout = 5, max = 100»; Server = Apache; «Transfer-Encoding» = Identity; }}
  • html указывает enctype = "multipart / form-data", возможно, это должно быть сработано в моем obj-c где-нибудь?
  • Пока что я только запускаю его с симулятора
  • любая помощь будет очень оценена! благодаря 🙂
  • редактирую, я только что отредактировал приведенный ниже код, чтобы показать [request setHTTPMethod: @ "POST"] вместо [request setHTTPMethod: @ "PUSH"], который я изначально имел, но он не меняет.

Вот цель C

- (void) uploadFile: (NSURL*) localURL toRemoteURL: (NSURL*) phpScriptURL { NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration]; NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]]; NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:phpScriptURL]; [request setHTTPMethod:@"POST"]; NSURLSessionUploadTask* uploadTask = [defaultSession uploadTaskWithRequest:request fromFile:localURL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){ if (error == nil) { NSLog(@"NSURLresponse =%@", [response description]); // do something !!! } else { //handle error } [defaultSession invalidateAndCancel]; }]; self.imageView.image = [UIImage imageWithContentsOfFile:localURL.path]; //to confirm localURL is correct [uploadTask resume]; } 

и вот PHP-скрипт, который находится на сервере

 <?php $file = 'log.txt'; $current = file_get_contents($file); $current .= $_FILES["file"]["name"]." is being uploaded. "; //should write the name of the file to log.txt file_put_contents($file, $current); ini_set('display_errors',1); error_reporting(E_ALL); $allowedExts = array("gif", "jpeg", "jpg", "png"); $temp = explode(".", $_FILES["file"]["name"]); $extension = end($temp); if ((($_FILES["file"]["type"] == "image/gif") || ($_FILES["file"]["type"] == "image/jpeg") || ($_FILES["file"]["type"] == "image/jpg") || ($_FILES["file"]["type"] == "image/pjpeg") || ($_FILES["file"]["type"] == "image/x-png") || ($_FILES["file"]["type"] == "image/png")) //&& ($_FILES["file"]["size"] < 100000) //commented out for error checking && in_array($extension, $allowedExts)) { if ($_FILES["file"]["error"] > 0) { echo "Return Code: " . $_FILES["file"]["error"] . "<br>"; } else { echo "Upload: " . $_FILES["file"]["name"] . "<br>"; echo "Type: " . $_FILES["file"]["type"] . "<br>"; echo "Size: " . ($_FILES["file"]["size"] / 1024) . " kB<br>"; echo "Temp file: " . $_FILES["file"]["tmp_name"] . "<br>"; if (file_exists("upload/" . $_FILES["file"]["name"])) { echo $_FILES["file"]["name"] . " already exists. "; } else { if (move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"])) { echo "Stored in: " . "upload/" . $_FILES["file"]["name"]; } else { echo "Error saving to: " . "upload/" . $_FILES["file"]["name"]; } } } } else { echo "Invalid file"; } ?> 

и вот html-файл, который работает как ожидается при вызове того же скрипта

 <html> <body> <form action="ios_upload.php" method="post" enctype="multipart/form-data"> <label for="file">Filename:</label> <input type="file" name="file" id="file"><br> <input type="submit" name="submit" value="Submit"> </form> </body> 

Я просто ответил на этот же вопрос: https://stackoverflow.com/a/28269901/4518324

В принципе, файл загружается на сервер в тело запроса как двоичный.

Чтобы сохранить этот файл в PHP, вы можете просто получить тело запроса и сохранить его в файле.

Ваш код должен выглядеть примерно так:

Код Objective-C:

 - (void) uploadFile: (NSURL*) localURL toRemoteURL: (NSURL*) phpScriptURL { // Create the Request NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:phpScriptURL]; [request setHTTPMethod:@"POST"]; // Configure the NSURL Session NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.upload"]; [sessionConfig setHTTPMaximumConnectionsPerHost: 1]; NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:nil]; NSURLSessionUploadTask* uploadTask = [defaultSession uploadTaskWithRequest:request fromFile:localURL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){ if (error == nil) { NSLog(@"NSURLresponse =%@", [response description]); // do something !!! } else { //handle error } [defaultSession invalidateAndCancel]; }]; self.imageView.image = [UIImage imageWithContentsOfFile:localURL.path]; //to confirm localURL is correct [uploadTask resume]; } 

Код PHP:

 <?php // Get the Request body $request_body = @file_get_contents('php://input'); // Get some information on the file $file_info = new finfo(FILEINFO_MIME); // Extract the mime type $mime_type = $file_info->buffer($request_body); // Logic to deal with the type returned switch($mime_type) { case "image/gif; charset=binary": // Create filepath $file = "upload/image.gif"; // Write the request body to file file_put_contents($file, $request_body); break; case "image/png; charset=binary": // Create filepath $file = "upload/image.png"; // Write the request body to file file_put_contents($file, $request_body); break; default: // Handle wrong file type here echo $mime_type; } ?> 

Я написал пример кода для записи звука и загрузки его на сервер здесь: https://github.com/gingofthesouth/Audio-Recording-Playback-and-Upload

Он показывает код с сохранением на устройстве iOS, загрузку и сохранение на сервер.

Надеюсь, это поможет.