ios — отправка аудио из приложения Swift на сервер PHP, и где-то звук теряется

Я делаю приложение в Swift, которое записывает звук, а затем отправляет эту запись на мой сервер PHP.

Приложение прекрасно записывает аудиоклип (его можно воспроизвести без проблем). Когда я println записанный аудиоклип показывает загрузки и загрузки байтовых данных (то же самое, когда я помещаю аудио в NSData обертка). Все это говорит мне о том, что звук в приложении нормальный.

Файл PHP, перехватывающий запись на моем сервере, также работает нормально и без ошибок.

Но где-то вдоль линии записанный аудиоклип теряется.

Swift-код, который загружает запись:

// The variable "recordedFileURL" is defined earlier in the code like this:

currentFilename = "xxxx.m4a"let dirPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let docsDir: AnyObject=dirPaths[0]
recordedFilePath = docsDir.stringByAppendingPathComponent(self.currentFilename)
recordedFileURL = NSURL(fileURLWithPath: self.recordedFilePath)

// "currentFilename", "recordedFilePath" and "recordedFileURL" are all global variables

// This recording stored at "recordedFileURL" can be played back fine.

let sendToPath = "http://......../catch.php"let sendToURL = NSURL(string: sendToPath)
let recording: NSData? = NSData(contentsOfURL: recordedFileURL)
let boundary = "--------14737809831466499882746641449----"let contentType = "multipart/form-data;boundary=\(boundary)"
var request = NSMutableURLRequest()
request.URL = sendToURL
request.HTTPMethod = "POST"request.addValue(contentType, forHTTPHeaderField: "Content-Type")
request.addValue(recId, forHTTPHeaderField: "REC-ID") // recId is defined elsewhere

var body = NSMutableData()
var header = "Content-Disposition: form-data; name=\"\(currentFilename)\"; filename=\"\(recordedFilePath)\"\r\n"
body.appendData(("\r\n-\(boundary)\r\n" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData((header as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData(("Content-Type: application/octet-stream\r\n\r\n" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)

body.appendData(recording!) // adding the recording here

body.appendData(("\r\n-\(boundary)\r\n" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)

request.HTTPBody = body

var session = NSURLSession.sharedSession()
var task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in

println("upload complete")
let dataStr = NSString(data: data, encoding: NSUTF8StringEncoding)
println(dataStr)

})

task.resume()

PHP-код в файле catch.php который должен получить запись:

$contents = file_get_contents('php://input');
$files = $_FILES;

echo "Caught the following:/r/n";
echo "Contents:" . var_export($contents) . "/r/n";
echo "Files:" . var_export($files) . "/r/n";

И всякий раз, когда я запускаю все это, я получаю следующий вывод из catch.php:

Caught the following:
Contents:''
Files:array (
)

Так catch.php ничего не получает вообще.

Я неправильно отправляю запись или записываю неправильно? Или оба?

Заранее спасибо.

3

Решение

Ваш PHP-код в основном в порядке. $_FILES часть в порядке, но php://input недоступно с enctype="multipart/form-data",

Проблема в том, как вы генерируете HTTP-запрос в своем коде Swift. Главным образом заголовки HTTP.
При создании заголовков для составных данных шаблон выглядит следующим образом (если мы выберем AAAAA в качестве нашей границы):

  • Выбранная нами граница: «ААААА»
  • Тип содержимого = «multipart / form-data; border = AAAAA»
  • Начальная граница = —AAAAA
  • Конечная граница = —AAAAA—

Итак, исправив ваш код немного:

// This was your main problem
let boundary = "--------14737809831466499882746641449----"let beginningBoundary = "--\(boundary)"let endingBoundary = "--\(boundary)--"let contentType = "multipart/form-data;boundary=\(boundary)"
// recordedFilePath is Optional, so the resulting string will end up being 'Optional("/path/to/file/filename.m4a")', which is wrong.
// We could just use currentFilename if we wanted
let filename = recordedFilePath ?? currentFilename
var header = "Content-Disposition: form-data; name=\"\(currentFilename)\"; filename=\"\(recordedFilePath!)\"\r\n"
var body = NSMutableData()
body.appendData(("\(beginningBoundary)\r\n" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData((header as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData(("Content-Type: application/octet-stream\r\n\r\n" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)
body.appendData(recording!) // adding the recording here
body.appendData(("\r\n\(endingBoundary)\r\n" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!)

var request = NSMutableURLRequest()
request.URL = sendToURL
request.HTTPMethod = "POST"request.addValue(contentType, forHTTPHeaderField: "Content-Type")
request.addValue(recId, forHTTPHeaderField: "REC-ID") // recId is defined elsewhere
request.HTTPBody = body

В случае, если вы снова столкнетесь с подобными вещами, при отладке сетевого кода, подобного этому, я хотел бы использовать инструменты, которые позволяют мне проверять передаваемые данные сети HTTP. Мне лично нравится HTTPScoop потому что это просто, но вы также можете использовать BurpSuite или же Чарльз

Я просто проверил ваш код и сравнил трафик HTTP с тем, что произошло, когда я сделал запрос с помощью curl

curl -X POST http://localhost/\~cjwirth/catch.php -F "file=@Untitled.m4a"
3

Другие решения

Других решений пока нет …