Я делаю приложение в Swift, которое записывает некоторый звук, а затем отправляет эту запись на мой PHP-сервер.
Приложение записывает аудио клип в порядке (его можно воспроизводить без проблем). Когда я println
записанный аудиоклип, он показывает нагрузки и нагрузки байтовых данных (то же самое, когда я помещаю звук в обертку NSData
). Все это говорит мне, что звук в приложении хорош.
Файл PHP, захватывающий запись на моем сервере, также отлично работает и без ошибок.
Но где-то вдоль линии записанный аудиоклип теряется.
Быстрый код, который загружает запись:
// 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
ничего не получает.
Я отправляю запись неправильно, или я неправильно поймаю запись? Или оба?
Заранее спасибо.
Ваш PHP-код в основном прекрасен. Часть $_FILES
в порядке, но php://input
недоступен с enctype="multipart/form-data"
.
Проблема заключается в том, как вы генерируете HTTP-запрос в вашем Swift-коде. Главным образом заголовки HTTP. При создании заголовков для многочастных данных шаблон таков (если мы выбрали 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 или Charles
Я просто проверил ваш код и сравнил HTTP-трафик с тем, что произошло, когда я сделал запрос с завитком
curl -X POST http://localhost/\~cjwirth/catch.php -F "file=@Untitled.m4a"