0

I’ve been working on an App where you can take a picture and then it is send to a server via PHP (POST). Everything works fine, I get the picture. But now I was thinking that it would be better if you can show the name of the user that took the picture. The problem is, I don’t know how to send parameters from this Function to the PHP $_POST. I tried using request.httpBody but when I run the PHP file it says there is no value in the variable. My code looks like the following:

func subirFotoRequest(){
let url = URL(string: "http://192.168.0.155/BolsaTrabajo/imagen.php")

let request = NSMutableURLRequest(url: url!)
request.httpMethod = "POST"

let postString = "username\(userName)&userlastname\(lastName)"
//Where userName and lastName are global variables declared before//

let request.httpBody = postString.data(using: String.Encoding.utf8)

let boundary = generateBoundaryString()

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

if (imageView.image == nil)
{
    return
}

let image_data = UIImagePNGRepresentation(imageView.image!)

if(image_data == nil)
{
    return
}

let body = NSMutableData()
indicadorActividad.startAnimating()

let fname = "test.png"
let mimetype = "image/png"


body.append("--\(boundary)\r\n".data(using: String.Encoding.utf8)!)
body.append("Content-Disposition:form-data; name=\"test\"\r\n\r\n".data(using: String.Encoding.utf8)!)
body.append("hi\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=\"\(fname)\"\r\n".data(using: String.Encoding.utf8)!)
body.append("Content-Type: \(mimetype)\r\n\r\n".data(using: String.Encoding.utf8)!)
body.append(image_data!)
body.append("\r\n".data(using: String.Encoding.utf8)!)

body.append("--\(boundary)--\r\n".data(using: String.Encoding.utf8)!)

request.httpBody = body as Data
let session = URLSession.shared

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

    guard let _:Data = data, let _:URLResponse = response  , error == nil else {
        print("error")
        return
    }

    let dataString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)

    print(dataString)
    //self.indicadorActividad.stopAnimating()



    do {
    DispatchQueue.main.async(execute: {
        self.indicadorActividad.stopAnimating()

        self.imageView.image = nil;
        });
    }
    catch{
        //Errores
    }


   }
   task.resume()       
  }    

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

2 Answers 2

1

Update

example to put userID:

body.append("--\(boundary)\r\n".data(using: String.Encoding.utf8)!)
body.append("Content-Disposition:form-data; name=\"userID\"\r\n\r\n".data(using: String.Encoding.utf8)!)
body.append("{value of userID}\r\n".data(using: String.Encoding.utf8)!)

Origin

Your code use form-data to post value.

body.append("--\(boundary)\r\n".data(using: String.Encoding.utf8)!)
body.append("Content-Disposition:form-data; name=\"test\"\r\n\r\n".data(using: String.Encoding.utf8)!)
body.append("hi\r\n".data(using: String.Encoding.utf8)!)

Above code generate post value hi for key test. Just put your username... like this.

Sign up to request clarification or add additional context in comments.

5 Comments

Hi Codus, first of all thank you for taking your time for answering. Could you please explain me this a bit further?(Hi as key for test) For example, if I want to add another parameter, should I put another line like "Hi" and just replace it with, let's say, userID?
As you see the code above, --\(boundary)\r\nContent-Disposition:form-data; name=\"test\"\r\n\r\nhi\r\n put the parameter exactly. I can get value(hi) of $_POST["test"] .
Oh I see, so if I want to call a $_Post['ID'] the code would look like... --(boundary)\r\nContent-Disposition:form-data; name=\"Id\"\r\n\r\nId\r\n correct?
Thanks for the Code-Update, I'm starting to see it clearly now
Yes, note the case difference ID and Id :)
1

NSMutableURLRequest (or URLRequest) cannot have multiple httpBodys. (And HTTP protocol cannot send multiple bodies in a single request.)

So, remove these lines:

    let postString = "username\(userName)&userlastname\(lastName)"
    //Where userName and lastName are global variables declared before//

    let request.httpBody = postString.data(using: String.Encoding.utf8)

(The latter line must be causing compile-time error, but that's another thing.)

And replace the lines assigning httpBody later:

    //### Use `Data` rather than `NSMutableData` in Swift.
    var body = Data()
    indicadorActividad.startAnimating()

    let fname = "test.png"
    let mimetype = "image/png"

    body.append("--\(boundary)\r\n".data(using: .utf8)!)
    body.append("Content-Disposition:form-data; name=\"username\"\r\n\r\n".data(using: .utf8)!)
    //### Assuming `userName` and `lastName` are non-Optional.
    body.append("\(userName)\r\n".data(using: .utf8)!)

    body.append("--\(boundary)\r\n".data(using: .utf8)!)
    body.append("Content-Disposition:form-data; name=\"userlastname\"\r\n\r\n".data(using: .utf8)!)
    body.append("\(lastName)\r\n".data(using: .utf8)!)

    body.append("--\(boundary)\r\n".data(using: .utf8)!)
    body.append("Content-Disposition:form-data; name=\"file\"; filename=\"\(fname)\"\r\n".data(using: .utf8)!)
    body.append("Content-Type: \(mimetype)\r\n\r\n".data(using: .utf8)!)
    body.append(image_data)
    body.append("\r\n".data(using: .utf8)!)

    body.append("--\(boundary)--\r\n".data(using: .utf8)!)

    //### No need to cast, when you use `Data`.
    request.httpBody = body

When you want to send text parameters in addition to image, you add other part s in multipart like "test" in your code. (Oh, it's already shown in Codus' answer.)


This is not mandatory to make your code work, but your code made more Swift-ish would be:

func subirFotoRequest() {
    //### If you eventually need forced-upwrapping, do it as soon as possible!
    let url = URL(string: "http://192.168.0.155/BolsaTrabajo/imagen.php")!

    //### Use `URLRequest` rather than `NSMutableURLRequest` in Swift.
    //### Please do not miss, it's `var` not `let`.
    var request = URLRequest(url: url)
    request.httpMethod = "POST"

    let boundary = generateBoundaryString()

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

    //### Consider using `guard` for early-return pattern.
    guard let image = imageView.image else {
        //### Silently ignoring unusual case may not be good for debugging.
        print("imageView.image == nil")
        return
    }

    //### (same as above)
    guard let image_data = UIImagePNGRepresentation(image) else {
        print("UIImagePNGRepresentation returned nil")
        return
    }

    //### Use `Data` rather than `NSMutableData` in Swift.
    var body = Data()
    indicadorActividad.startAnimating()

    let fname = "test.png"
    let mimetype = "image/png"

    body.append("--\(boundary)\r\n".data(using: .utf8)!)
    body.append("Content-Disposition:form-data; name=\"username\"\r\n\r\n".data(using: .utf8)!)
    //### Assuming `userName` and `lastName` are non-Optional.
    body.append("\(userName)\r\n".data(using: .utf8)!)

    body.append("--\(boundary)\r\n".data(using: .utf8)!)
    body.append("Content-Disposition:form-data; name=\"userlastname\"\r\n\r\n".data(using: .utf8)!)
    body.append("\(lastName)\r\n".data(using: .utf8)!)

    body.append("--\(boundary)\r\n".data(using: .utf8)!)
    body.append("Content-Disposition:form-data; name=\"file\"; filename=\"\(fname)\"\r\n".data(using: .utf8)!)
    body.append("Content-Type: \(mimetype)\r\n\r\n".data(using: .utf8)!)
    body.append(image_data)
    body.append("\r\n".data(using: .utf8)!)

    body.append("--\(boundary)--\r\n".data(using: .utf8)!)

    //### No need to cast, when you use `Data`.
    request.httpBody = body

    //### No need to cast, when you use `URLRequest`.
    let task = URLSession.shared.dataTask(with: request) {
        (data, response, error) in

        guard let data = data, response != nil, error == nil else {
            print("error")
            return
        }

        //### Use `String` rather than `NSString` in Swift.
        let dataString = String(data: data, encoding: .utf8)

        //### Supplying default value prevents output "Optional(...)".
        print(dataString ?? "Undecodable result")

        //### No code throws here.
        DispatchQueue.main.async {
            self.indicadorActividad.stopAnimating()

            self.imageView.image = nil
        }
    }
    task.resume()
}

1 Comment

Thanks for making more "Swifty" my code, I will edit it, make some changes and add more in the "multipart" area like you and Codus said

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.