将音频从SWIFT应用程序发送到PHP服务器,在音频丢失的某个地方[英] Sending audio from a Swift App to PHP Server, and somewhere the audio is lost

本文是小编为大家收集整理的关于将音频从SWIFT应用程序发送到PHP服务器,在音频丢失的某个地方的处理方法,想解了将音频从SWIFT应用程序发送到PHP服务器,在音频丢失的某个地方的问题怎么解决?将音频从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根本没有收到任何东西.

我正在发送录音错误,或者正在捕获错误吗?或两者?

提前感谢.

推荐答案

您的PHP代码大多是正常的. $_FILES部分是可以的,但 php://input不适用于enctype="multipart/form-data".

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

    我们选择的边界:"aaaaa"
  • 内容类型="multipart/form-data;边界= 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"

其他推荐答案

这是swift 4〜5代码. 在ViewController上创建新的按钮(在代码中的ButtonLabel),并将按钮操作链接到@Ibaction和@iboutlet [按住重新介绍和释放以上载音频文件]

import UIKit
import AVFoundation

class ViewController2: UIViewController, AVAudioRecorderDelegate{
    
    var recordingSession: AVAudioSession!
    var audioRecorder: AVAudioRecorder!
    var audioPlayer: AVAudioPlayer!
    var numberOfRecords = 0
    

    @IBOutlet weak var buttonLabel: UIButton!
    let E_401 = "E_401"
    let DATABASE_PATH = "http://<IP_address_of_PHP_server>/YourPrjectName/"
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Set the recognizer to recognize the button action
        let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(record))
        longPressRecognizer.minimumPressDuration = 0
        buttonLabel.addGestureRecognizer(longPressRecognizer)
        
        // Setting up session
        recordingSession = AVAudioSession.sharedInstance()
        
        
        // Get permission from user to use mic
        AVAudioSession.sharedInstance().requestRecordPermission{ (hasPermission) in
            if hasPermission
            {print ("ACCEPTED")}
        }
    }
    
    
    @IBAction func record(_ gestureRecognizer: UILongPressGestureRecognizer) {
        
        // Check if we have an active recorder
        if (gestureRecognizer.state == .began) && (audioRecorder == nil) {
            // Increase +1 total number of recordings for every new recording made
            
            self.numberOfRecords += 1
            
            // Setting filename and settings
            let filename = getDirectory().appendingPathComponent("\(numberOfRecords).m4a")
            let settings = [
                AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
                AVSampleRateKey: 12000,
                AVNumberOfChannelsKey: 1,
                AVEncoderAudioQualityKey: AVAudioQuality.medium.rawValue
            ]
            
            do
            {
                // Start audio recording
                buttonLabel.setTitle("Recording...", for: .normal)
                audioRecorder = try AVAudioRecorder(url: filename, settings: settings)
                audioRecorder.delegate = self
                audioRecorder.record()
            }
            catch
            {
                // Catch for errors
                displayAlert(title: "Oops!", message: "Recording failed")
                
            }
            
        } else if gestureRecognizer.state == .ended && (audioRecorder != nil)
            
        {
            // Stopping audio recording
            buttonLabel.setTitle("Start Recording", for: .normal)
            audioRecorder.stop()
            audioRecorder = nil
            
            
            
            do {
                let filename = getDirectory().appendingPathComponent("\(numberOfRecords).m4a")
                let recording: NSData = try NSData(contentsOf: filename)
                self.uploadFile(fileData: recording as Data, fileName: "\(numberOfRecords).m4a"){
                    (fileURL, e) in
                    if e == nil {
                        print("FILE URL: " + fileURL!)
                    }
                }
                
            } catch {
                print("Unexpected <<<<<<<<<<<<<<>>>>>>>>>>>>>> error: \(error)")
            }

        }
    }
    
    // Function that gets path to directory
    func getDirectory () -> URL
    {
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        let documentDirectory = paths[0]
        
        return documentDirectory
    }
    
    // Function that displays an alert
    func displayAlert(title:String, message:String)
    {
        let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "dismiss", style: .default, handler: nil))
        present(alert, animated: true, completion: nil)
    }
    
    
    func uploadFile(fileData:Data, fileName:String , completion: @escaping (_ fileURL:String?, _ error:String?) -> Void) {
        let recId = "\(numberOfRecords)"
        print("FILENAME: \(fileName)")
        let request = NSMutableURLRequest()

        let boundary = "--------14737809831466499882746641449----"
        let beginningBoundary = "--\(boundary)"
        let endingBoundary = "--\(boundary)--"
        let contentType = "multipart/form-data;boundary=\(boundary)"
        
        
        
        request.url = URL(string: DATABASE_PATH + "catch.php")
//        catch.php is php script on server
        request.httpShouldHandleCookies = false
        request.timeoutInterval = 60
        request.httpMethod = "POST"
        request.setValue(contentType, forHTTPHeaderField: "Content-Type")
        let body = NSMutableData()
        body.append("--\(boundary)\r\n".data(using: String.Encoding.utf8)!)
        body.append("Content-Disposition: form-data; name=\"fileName\"\r\n\r\n".data(using: String.Encoding.utf8)!)
        body.append("\(fileName)\r\n".data(using: String.Encoding.utf8)!)
        body.append("--\(boundary)\r\n".data(using: String.Encoding.utf8)!)
        body.append("Content-Disposition: form-data; name=\"file\"; filename=\"file\"\r\n".data(using: String.Encoding.utf8)!)
        
        body.append(("\(beginningBoundary)\r\n" as NSString).data(using: String.Encoding.utf8.rawValue)!)
        body.append(("Content-Type: application/octet-stream\r\n\r\n" as NSString).data(using: String.Encoding.utf8.rawValue)!)

        body.append(fileData)
        body.append("\r\n".data(using: String.Encoding.utf8)!)
        
        
        body.append("--\(boundary)--\r\n".data(using: String.Encoding.utf8)!)
        request.addValue(contentType, forHTTPHeaderField: "Content-Type")
//        request.addValue(recId, forHTTPHeaderField: "REC-ID")
        request.httpBody = body as Data
        
        
        let session = URLSession.shared
        let task = session.dataTask(with: request as URLRequest) { (data, response, error) in
            guard let _:Data = data as Data?, let _:URLResponse = response, error == nil else {
                DispatchQueue.main.async { completion(nil, error!.localizedDescription) }
                return
            }
            if let response = String(data: data!, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue)) {
                print("XSUploadFile -> RESPONSE: " + self.DATABASE_PATH + response)
                DispatchQueue.main.async { completion(self.DATABASE_PATH + response, nil) }
                
                // NO response
            } else { DispatchQueue.main.async { completion(nil, self.E_401) } }// ./ If response
        }; task.resume()
    }
}

本文地址:https://www.itbaoku.cn/post/924416.html