Я делаю приложение в 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
ничего не получает вообще.
Я неправильно отправляю запись или записываю неправильно? Или оба?
Заранее спасибо.
Ваш 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 или же Чарльз
Я просто проверил ваш код и сравнил трафик HTTP с тем, что произошло, когда я сделал запрос с помощью curl
curl -X POST http://localhost/\~cjwirth/catch.php -F "[email protected]"
Других решений пока нет …