Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Upload Pdf, Docx and image file to server using Swift 4

I am new to swift, I have been trying to upload pdf, docx and image file from local storage of a Iphone. I have written a code but it doesn't work and I keep getting Status Code: 415 from the response. Here is my code:

func uploadfileToServer(completed: @escaping () -> ()){

    let theTitle = labelTitle.text


    guard let url = URL(string: "http://www.--------.com/assignment/post") else {return}
    var request = URLRequest.init(url: url)
    request.httpMethod = "POST"

    request.addValue("cf7ab8c9d4efae82b575eabd6bec76cbb86c6108391e036387f3dd5356a582171519367747000", forHTTPHeaderField: "api_key")




    let boundary = generateBoundaryString()


    // Set Content-Type in HTTP header.
    let boundaryConstant = boundary // This should be auto-generated.
    let contentType = "multipart/form-data; boundary=" + boundaryConstant

    let directory = NSTemporaryDirectory()
    let fileName = NSUUID().uuidString

    // This returns a URL? even though it is an NSURL class method
    let fullURL = NSURL.fileURL(withPathComponents: [directory, fileName])



    let fileNamee = fullURL?.path
    let mimeType = "text/csv"
    let fieldName = "uploadFile"

    request.setValue(contentType, forHTTPHeaderField: "Content-Type")



    var dataString = "--\(boundaryConstant)\r\n"


    dataString += "\r\n"
    dataString += "--\(boundaryConstant)--\r\n"

    var theBody = Data()



    let sectionID : String?
    sectionID = nil
    let str = "user_id=\(savedsesuid!)" + "&school_id=" + SCHOOL_ID + "&class_id=" + classID + "&section_id=\(sectionID)" + "&subject_id=\(id)"



    if let b = str.data(using: .utf8) {
        theBody.append(b)
    }

    let str1 = "&atitle=" + theTitle! + "&class_id=" + classID

    if let c = str1.data(using: .utf8){
        theBody.append(c)
    }


    let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
    var filePath = documentDirectory.appendingFormat("/")
    filePath     = filePath.appendingFormat("/Users/prashanna/Desktop/ebusiness_topic_1_handout.pdf")
    let pdfData  = NSData(contentsOfFile: filePath)

    let file = "&afile=" + "\(pdfData)"

    if let d = file.data(using: .utf8){
        theBody.append(d)
    }

    print(theBody)



    request.httpBody = theBody

    URLSession.shared.dataTask(with: request) { (data, response, error) in
        print(response)
        if let httpResponse = response as? HTTPURLResponse {
            let statuscode = httpResponse.statusCode
            if statuscode == 401{
                self.displayMessage(userMessage: "Sending Failed")


            }else if statuscode == 200{
                if error == nil{
                    do{
                        self.displayMessage(userMessage: "File Successfully Uploaded!")
                        DispatchQueue.main.async {
                            completed()

                        }

                    }

                }
            }
        }
    }.resume()



}

func generateBoundaryString() -> String {
    return "Boundary-\(NSUUID().uuidString)"
}

Some solutions tell me to convert the file into Data and then send it to server while some say to directly add the file path to your body. Need Help!

like image 823
TheSwiftGuy77 Avatar asked Apr 09 '18 10:04

TheSwiftGuy77


2 Answers

One fundamental mistake is that you are using dataTask instead of an uploadTask on your URLSession instance, e.g. uploadTask(with:from:completionHandler:)

Construction of Body Data

Here's a generic example from my own code (as requested in the comments below) of how body data might be constructed:

// imagesURLS is an optional array of URLs, i.e. imageURLS:[URL]?

if let imgURLs = imagesURLS {
    for f in imgURLs {
        let filename = f.lastPathComponent  
        let splitName = filename.split(separator: ".")
        let name = String(describing: splitName.first)
        let filetype = String(describing: splitName.last)

        let imgBoundary = "\r\n--\(boundary)\r\nContent-Type: image/\(filetype)\r\nContent-Disposition: form-data; filename=\(filename); name=\(name)\r\n\r\n"

        if let d = imgBoundary.data(using: .utf8) {
            bodyData.append(d)
        }

        do {
            let imgData = try Data(contentsOf:f, options:[])
            bodyData.append(imgData)
        }
        catch {
            // can't load image data
        }

        }
    }
    let closingBoundary = "\r\n--\(boundary)--"
    if let d = closingBoundary.data(using: .utf8) {
            bodyData.append(d)
    }

The loop means that every item of data (in this case an image) is preceded by a boundary string and after the very last item of data the closing boundary string is added (i.e. the one ending in a double hyphen).

like image 53
sketchyTech Avatar answered Sep 28 '22 02:09

sketchyTech


This works for me, in Swift4:

func uploadFiles(_ urlPath: [URL]){

if let url = URL(string: "YourURL"){
var request = URLRequest(url: url)
let boundary:String = "Boundary-\(UUID().uuidString)"

request.httpMethod = "POST"
request.timeoutInterval = 10
request.allHTTPHeaderFields = ["Content-Type": "multipart/form-data; boundary=----\(boundary)"]

    for path in urlPath{
        do{
            var data2: Data = Data()
            var data: Data = Data()
            data2 = try NSData.init(contentsOf: URL.init(fileURLWithPath: path.absoluteString, isDirectory: true)) as Data
            /* Use this if you have to send a JSON too.
             let dic:[String:Any] = [
             "Key":Value,
             "Key":Value
            ]


            for (key,value) in dic{
                data.append("------\(boundary)\r\n")
                data.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
                data.append("\(value)\r\n")
            }
              */
            data.append("------\(boundary)\r\n")
            //Here you have to change the Content-Type
            data.append("Content-Disposition: form-data; name=\"file\"; filename=\"YourFileName\"\r\n")
            data.append("Content-Type: application/YourType\r\n\r\n")
            data.append(data2)
            data.append("\r\n")
            data.append("------\(boundary)--")

            request.httpBody = data
        }catch let e{
            //Your errors
        }
        DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated).sync {
            let session = URLSession.shared
            let task = session.dataTask(with: request, completionHandler: { (dataS, aResponse, error) in
                if let erros = error{
                    //Your errors
                }else{
                    do{
                        let responseObj = try JSONSerialization.jsonObject(with: dataS!, options: JSONSerialization.ReadingOptions(rawValue:0)) as! [String:Any]

                    }catch let e{

                    }
                }
            }).resume()
        }
    }
}
}

extension Data{
mutating func append(_ string: String, using encoding: String.Encoding = .utf8) {
    if let data = string.data(using: encoding) {
        append(data)
    }
}
}
like image 40
Genaro Arvizu Avatar answered Sep 28 '22 00:09

Genaro Arvizu