1

It seems that this question has been asked before, but no answers were very helpful to me. I have an app where I created my own ImagePicker to select more than one image from the user's Camera Roll. I now need to upload these images to a PHP script. Everything is working when I need to upload only a single image. The thing is, I have no idea how to change my code to upload multiple images.

Code to begin post (Only most important code related to upload)

let param = ["request":"uploadImagesAndParams", "someParam": self.txtSomeTextField.text!]

        let boundary = generateBoundaryString()

        request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

        //Here I am just selecting the first image in my UIImage array (selectedImages). I need to be able to select all of them and upload it.
        let imageData = UIImageJPEGRepresentation((selectedImages?[0])!, 1)

        if(imageData == nil)  { return; }

        request.httpBody = createBodyWithParameters(parameters: param,
                                                    filePathKey: "image",
                                                    imageDataKey: imageData! as NSData,
                                                    boundary: boundary) as Data

Code to upload

//Upload Function
    func createBodyWithParameters(parameters: [String: String]?, filePathKey: String?, imageDataKey: 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 = "user-profile.jpg"
        let mimetype = "image/jpg"

        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(imageDataKey as Data)
        body.appendString(string: "\r\n")



        body.appendString(string: "--\(boundary)--\r\n")

        return body
    }



    func generateBoundaryString() -> String {
        return "Boundary-\(NSUUID().uuidString)"
    }
halfer
  • 19,824
  • 17
  • 99
  • 186
Christopher Smit
  • 953
  • 11
  • 27
  • 1
    Check this question and the answer https://stackoverflow.com/questions/43972651/multiple-file-upload-with-array-of-parameters-using-alamofire/43972778#43972778. It should give you the general idea of how to achieve this. – Max Pevsner Jul 11 '17 at 14:25
  • That question is using Alamofire. – Christopher Smit Jul 11 '17 at 14:26
  • The answer focuses on `Operation` rather than on `Alamofire`. You can use this concept. The rest is implementation details. – Max Pevsner Jul 11 '17 at 14:29

2 Answers2

0

Here is the snippet for upload multiple image uploading with Alamofire

Suppose you are having Array of images which you want to upload to the service

for aIndex in 0..<imgArray.count{
   if let imageData = UIImageJPEGRepresentation(imgArray[aIndex], 0.5) {
        multipartFormData.append(imageData, withName: "Image\(aIndex).jpg")
        }
   }

Hope this will help you

Maulik Pandya
  • 2,200
  • 17
  • 26
0

I figured out the way to do it without operations. Below method will upload multiple images to PHP server. Hope this helps someone else.

Import the following

import MobileCoreServices

Add the following

var selectedImages: [UIImage]?
var params: NSMutableDictionary = NSMutableDictionary()

Function that makes the request

    function upload() {
            // Retrieve server URL
            let serverUrl = dbConn.OnlineDBConnectionString()

            // Define server side script URL
            let scriptUrl = serverUrl + "evalue8_api.php"

            let myUrl = NSURL(string: scriptUrl);

            let request = NSMutableURLRequest(url:myUrl! as URL);
            request.httpMethod = "POST";

            //Note the [] after image
             params = ["someVariable": self.txtMytextfield.text!, "image[]": selectedImages!]

            let boundary = generateBoundaryString()

            request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

            request.httpBody = createBodyWithParameters(parameters: params, boundary: boundary) as Data

            _ = URLSession.shared.dataTask(with: request as URLRequest) {
                data, response, error in

                if error != nil {
                    print("Error=\(error!)")
                    return
                }

                do {
                    let parsedData = try JSONSerialization.jsonObject(with: data!, options: []) as! NSDictionary

                    //print(parsedData)
                    let success = parsedData["response"] as! Bool

                    DispatchQueue.main.async {
                        if (success) {
                            //Do something
                        }
                    }
                } catch {
                    print(error.localizedDescription)
                }
            }.resume()
        }

Other needed functions

//Upload Function
    func createBodyWithParameters(parameters: NSMutableDictionary?, boundary: String) -> NSData {
        let body = NSMutableData()

        if parameters != nil {
            for (key, value) in parameters! {

                if(value is String || value is NSString){
                    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")
                }
                else if(value is [UIImage]){
                    var i = 0;
                    for image in value as! [UIImage]{
                        let filename = "image\(i).jpg"
                        let data = UIImageJPEGRepresentation(image,1);
                        let mimetype = mimeTypeForPath(path: filename)

                        body.appendString(string: "--\(boundary)\r\n")
                        body.appendString(string: "Content-Disposition: form-data; name=\"\(key)\"; filename=\"\(filename)\"\r\n")
                        body.appendString(string: "Content-Type: \(mimetype)\r\n\r\n")
                        body.append(data!)
                        body.appendString(string: "\r\n")
                        i += 1;
                    }
                    print(i)
                }
            }
        }
        body.appendString(string: "--\(boundary)--\r\n")
        return body
    }

    func mimeTypeForPath(path: String) -> String {
        let pathUrl = NSURL(string: path)

        let pathExtension = pathUrl!.pathExtension
        var stringMimeType = "application/octet-stream"
        if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension! as CFString, nil)?.takeRetainedValue() {
            if let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() {
                stringMimeType = mimetype as NSString as String
            }
        }
        return stringMimeType;
    }

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

Extention needed

    extension NSMutableData {

    func appendString(string: String) {
        let data = string.data(using: String.Encoding.utf8, allowLossyConversion: true)
        append(data!)
    }
}
Christopher Smit
  • 953
  • 11
  • 27