php - 将音频从 Swift 应用程序发送到 PHP 服务器,但音频在某处丢失

标签 php ios audio swift

我正在用 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()

catch.php 文件中用于接收录音的 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 is not available with enctype="multipart/form-data".

问题在于您如何在 Swift 代码中生成 HTTP 请求。主要是 HTTP header 。 为多部分数据创建 header 时,模式是这样的(如果我们选择 AAAAA 作为我们的边界):

  • 我们选择的边界:“AAAAA”
  • 内容类型 = "multipart/form-data;boundary=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因为它很简单,但你也可以使用 BurpSuiteCharles

我刚刚运行了你的代码,并将 HTTP 流量与我使用 curl 发出请求时发生的情况进行了比较

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

关于php - 将音频从 Swift 应用程序发送到 PHP 服务器,但音频在某处丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27863211/

相关文章:

c# - 碰撞中的Unity2D AudioSource

php - 如何为php项目设置端口?

php - 使用 php 删除除前 20 行以外的所有行

php - 使用 DataTable 显示数据库中的 50 行,并能够搜索整个数据库

ios - DispatchQueue.main.async 不会崩溃但 DispatchQueue.main.sync 会崩溃?

ios - UIBarButton 不执行操作

javascript - MediaElements.js YouTube 音频自动播放

Python:发出哔哔声

javascript - 形成 PreventDefault 然后再次激活不起作用

iOS - 如果模型 View 正在呈现,如何不呈现?