0

I am recording audio (as .m4a) in my application. That works just fine. I can make that data and I send it to my PHP script and it gets uploaded. However, it's no longer a valid audio file - it cannot be played when I download from my public server. Here is code for when the recording is complete, the generation of the body with headers, and my PHP. I also supply the response from the server which shows some things I believe I need to fix but am unsure about.

func finishRecording(success: Bool)
{
    if success
    {
        if NSData(contentsOf: audioRecorder.url) != nil
        {
            let destUrl = URL(string: destinationURL)
            let request = NSMutableURLRequest(url: destUrl!)
            request.httpMethod = "POST"
            let param = ["firstName": "Eric", "lastName": "Dolecki", "userId": "5"]
            let boundary = "Boundary-\(NSUUID().uuidString)"
            request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

            do {
                let f = try FileHandle(forReadingFrom: audioRecorder.url)
                let data = f.readDataToEndOfFile()
                print(data) // i.e. 66505 bytes
                f.closeFile()

                // Lets send the file to the PHP script to save it.
                request.httpBody = createBodyWithParameters(parameters: param, filePathKey: "file", audioDataKey: data as NSData, boundary: boundary) as Data
                let task = URLSession.shared.dataTask(with: request as URLRequest)
                {
                    data, response, error in
                    if error != nil {
                        print("error=\(String(describing: error))")
                        return
                    }

                    print("Response = \(String(describing: response))")
                    let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
                    print("Response data = \(responseString!)")
                }
                task.resume()
            } catch {
               ...

Here is the body creation function:

func createBodyWithParameters(parameters: [String: String]?, filePathKey: String?,
                              audioDataKey: NSData, boundary: String) -> NSData {
    let body = NSMutableData();
    if parameters != nil {
        for (key, value) in parameters! {
            body.appendString(string: "--\(boundary)\r\n")
            body.appendString(string: "Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
            body.appendString(string: "\(value)\r\n")
        }
    }
    let filename = "recording.m4a"
    let mimetype = "audio/m4a"
    body.appendString(string: "--\(boundary)\r\n")
    body.appendString(string: "Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename)\"\r\n")
    body.appendString(string: "Content-Type: \(mimetype)\r\n\r\n")
    body.append(audioDataKey as Data)
    body.appendString(string: "\r\n")
    body.appendString(string: "--\(boundary)--\r\n")
    return body
    }
}

extension NSMutableData {
    func appendString(string: String) {
        let data = string.data(using: String.Encoding.utf8, allowLossyConversion: true)
        append(data!)
    }
}

Here is the PHP:

<?php
$firstName = $_POST["firstName"];
$lastName = $_POST["lastName"];
$userId = $_POST["userId"];

$target_dir = "assets";
$target_dir = $target_dir . "/" . basename($_FILES["file"]["name"]);

if (move_uploaded_file($_FILES["file"]["tmp_name"], $target_dir)) 
{
    echo "Status Okay: " . $firstName . ", " . $lastName . " : " . $userId . " " . $target_dir;

} else {
    echo "Error uploading";
}

?>

Server response:

Connection =     (
    "Keep-Alive"
);
"Content-Encoding" =     (
    gzip
);
"Content-Length" =     (
    50
);
"Content-Type" =     (
    "text/html"
);
Date =     (
    "Wed, 22 Aug 2018 13:29:04 GMT"
);
"Keep-Alive" =     (
    "timeout=5, max=100"
);
Server =     (
    "Apache/2.2.34"
);
Vary =     (
    "User-Agent,Accept-Encoding"
);
"X-Powered-By" =     (
    "PHP/5.3.29"
);

The response I get has a content type of text/html and content-encoding of gzip. Those can't be good. I think that needs to be addressed - instead of multipart/form-data, what should it be (if that is the solution)? Will the PHP overwrite a file that already exists?

Thanks for all your time and attention.

  • Are you able to play the file directly (i.e. download it, and play it with some media player)? Anyhoo, you need to set the proper headers in your PHP script. – Alen Androsevic Aug 22 '18 at 14:31
  • I cannot play the downloaded file. What do the headers need to be? – Radagast the Brown Aug 22 '18 at 14:56
  • See [this question](https://stackoverflow.com/q/49833586/2550501). You’ll have to change the content type to suit your file type though.. You could google the proper MIME-type. – Alen Androsevic Aug 22 '18 at 15:01
  • @gnCupo I don't think my upload of the file is correct. I think my swift code needs revision. I am downloading the uploaded file via ftp and it cannot be played. I just want to ensure the upload via the PHP produces a valid audio file. – Radagast the Brown Aug 22 '18 at 15:15
  • I solved this long ago. It had to do with the audio parameters which were wrong. So the file being sent after recording was corrupt and thus could not be played. – Radagast the Brown Oct 25 '18 at 00:21

0 Answers0