2

I have an app that uploads some data to a MySQL database via some PHP web services I wrote. I have got the text data to upload successfully, but I am struggling trying to get an image to upload. Basically, the user takes a photo using their iPhone camera, I convert it to a UIImage and now want to upload it.

I have looked at the following sources for help but they haven't seemed to work for me: How to Upload text, pdf, doc, zip file via PHP file upload to MySQL
https://www.youtube.com/watch?v=HqxeyS961Uk (The code in here wouldn't compile for me and I copied it letter for letter)
How to post a picture from iPhone app (in Swift) to MySQL database?
Saving image on db mysql through swift
Swift - uploading base64 encoded image to php and displaying the image
Getting a UIImage from MySQL using PHP and jSON

I want to upload the image and text together in the same query if possible, as they relate to one another and my MySQL table assigns an auto number for new rows.

Edit Thanks to the answers below. I am a little unsure as to how to implement the changes you guys suggested. My Swift code at the moment to upload text data is:

let url:NSURL = NSURL(string: "http://www.website.com.au/savenewexpense.php")!
        let request:NSMutableURLRequest = NSMutableURLRequest(URL: url)
        request.HTTPMethod = "POST"
        var dataDictionary:[String:AnyObject] = ["Date" : strDate, "Staff" : strStaff, "Amount" : dblAmount, "Category" : strCategory]
        var data:NSData = NSJSONSerialization.dataWithJSONObject(dataDictionary, options: nil, error: nil)!
        request.HTTPBody = data

        request.addValue("application/json", forHTTPHeaderField: "Content-Type")

        let task:NSURLSessionDataTask = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: { (data:NSData!, response:NSURLResponse!, error:NSError!) -> Void in

            let response:[String:String] = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! [String:String]
            if let result = response["result"] {
                if result == "success" {
                    NSLog("Text Data saved successfully")
                    if self.SendImageToServer() == true {
                        NSLog("Image Data saved successfully")
                        self.SaveSuccessful()
                    } else {
                        NSLog("Image Data failed to save")
                        self.DataFail()
                    }
                } else {
                    NSLog("Error saving data")
                    self.DataFail()
                }
            } else {
                NSLog("No response")
                self.NoResponse()
            }

        })

        task.resume()
    }

and my PHP code is:

    // Create connection
$conn = new mysqli($servername, $username, $password, $dbname);

// Check connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

$json = file_get_contents('php://input');
$data = json_decode($json, true);

$stmt = $conn->prepare("INSERT INTO tblExpenses (Date, Staff, Amount, Category) VALUES (?, ?, ?, ?)");
$txtDate = $data['Date'];
$txtStaff = $data['Staff'];
$txtAmount = $data['Amount'];
$txtCategory = $data['Category'];
$stmt->bind_param("ssds", $txtDate, $txtStaff, $txtAmount, $txtCategory);
$stmt->execute();
echo '{"result" : "success"}';


$stmt->close();
$conn->close();

How should I implement the image into this?

Thanks

Community
  • 1
  • 1
Matt Kelly
  • 1,451
  • 2
  • 13
  • 30
  • You cannot just put binary data in JSON like that. Two basic approaches: `multipart/form-data` request (the Swift code is http://stackoverflow.com/a/26163136/1271826 and the PHP code then accesses the upload via `$_FILES` or base64-encoding in (converting the binary data into text form) and then using JSON or `application/x-www-form-urlencoded` to send it (but then you'd have to receive it and convert the base64 back to binary form; plus the transmission is 33% larger than it needs to be). – Rob May 11 '15 at 03:05
  • @Rob what do you mean transmission is 33% larger than it needs to be? what is making it larger? How would you reduce it? – the_pantless_coder Jul 03 '15 at 23:54
  • 1
    @the_pantless_coder - Text-based formats (such as JSON or XML) require that binary data undergoes base64 encoding process that takes 8-bit binary data and represents it as a sequence of 64 different text characters. That encoding process outputs four text characters for every three bytes of input binary data. (You're taking 3 x 8-bit binary bytes and representing it as 4 x 6-bit text characters.) To avoid that overhead, use a transmission mechanism that doesn't require text format, i.e. one that doesn't require base64 encoding (such as `x-www-form-urlencoded`). – Rob Jul 04 '15 at 01:08

1 Answers1

2

What you have to do is set the Boundary for the Image as an example use the code to Convert the NSDATA of image to the boundary values

if let dta = data as? NSData {
                bodyData.appendData(String(format:"\r\n--\(boundary)\r\n").dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!);
                bodyData.appendData(String(format:"Content-Disposition: form-data; name=\"photo\(i)\"; filename=\"image.png\"\r\n").dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!);
                bodyData.appendData(String(format:"Content-Type: image/png\r\n\r\n").dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!);

                bodyData.appendData(dta);
            }

Here what you do is you set the image name and then the Image Data first you convert the data using allowLossyConversion and then send the POST data with the other data to service

request.HTTPBody = bodyData

just use this to send the image

Fatti Khan
  • 1,543
  • 1
  • 11
  • 19
  • Yep, that's how you create one part to the multipart request. This obviously presumes, though, that (a) that the request header properly designates this as a multipart request and what the boundary is; and (b) make sure to add a boundary terminator at the end of the request body. Otherwise, this won't be a well-formed request. – Rob May 11 '15 at 16:41
  • @Fatti Khan Ok, I edited the question to include my code for uploading text data. How should I implement the image into this? I already set data to be the `request.HTTPBody` – Matt Kelly May 18 '15 at 06:50