1

I'm trying to send data (first name, last name, age, image) to a MySQL database. And I can. The following is what I have.

class PostViewController: UIViewController {
    @IBAction func selectTapped(_ sender: UIButton) {
        postData()
    }

    func postData() {
        var request = URLRequest(url: URL(string: "http://www.mywebsite.tv/post.php")!)
        request.httpMethod = "POST"
        let fName = firstField.text!
        let lName = lastField.text!
        let ageStr = ageField.text!
        let image = imageView.image!
        guard let pictStr = convertImageBase64(image: image) else {
            return
        }
        let postString = "a=\(fName)&b=\(lName)&c=\(ageStr)&d=\(pictStr)"
        request.httpBody = postString.data(using: .utf8)
        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            guard let data = data, error == nil else {
                print("error=\(String(describing: error))")
                return
            }

            if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
                print("statusCode should be 200, but is \(httpStatus.statusCode)")
                print("response = \(String(describing: response))")
            }

            let responseString = String(data: data, encoding: .utf8)
            print("responseString = \(String(describing: responseString))")
        }
        task.resume()
    }

    func convertImageBase64(image: UIImage) -> String? {
        guard let pictData = UIImagePNGRepresentation(image) else {
            return nil
        }
        let strBase64: String = pictData.base64EncodedString(options: Data.Base64EncodingOptions.lineLength64Characters)
        return strBase64
    }
}

And populating UITableView with data from MySQL..

class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, DataModelProtocol {
    // MARK: - Variables
    var myItems = NSArray()

    // MARK: - IBOutlets
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // somehow loading data //    
    }

    // MARK: - TableView
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return myItems.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ProfileTableViewCell
        let item: PictureModel = myItems[indexPath.row] as! PictureModel
        cell.firstLabel.text = item.fName
        cell.lastLabel.text = item.lName
        cell.ageLabel.text = item.ageStr
        print(item.pictStr!) // returning iVBORw0KGgoAAAANSUh...
        if let img = convertBase64Image(base64String: item.pictStr!) {
            cell.pictureImageView.image = img
        }
        return cell
    }

    func convertBase64Image(base64String: String) -> UIImage? {
        if let pictData = Data(base64Encoded: base64String, options: Data.Base64DecodingOptions.ignoreUnknownCharacters) {
            return UIImage(data: pictData)
        } else {
            return nil
        }
    }
}

The thing is cell.pictureImageView.image is always nil. And I now know why. When I post a picture, a sample base64 string is

iVBORw0KGgoAAAANSUhEUgAAAFYAAACACAYAAACRMZ7FAAAAAXNSR0IArs4c6QAA\r\nABxp...

And the decoded string that I get is

iVBORw0KGgoAAAANSUhEUgAAAFYAAACACAYAAACRMZ7FAAAAAXNSR0IArs4c6QAA ABxp...

So the Data.Base64DecodingOptions.ignoreUnknownCharacters option actually replaces \r\n with a white space. How can I encode an image and then decode it back the same?

Cœur
  • 37,241
  • 25
  • 195
  • 267
El Tomato
  • 6,479
  • 6
  • 46
  • 75
  • 1
    Why do you do `.lineLength64Characters`? I would simply remove that and you should be good to go. – luk2302 Feb 26 '18 at 11:59
  • @luk2302 's comment should be the answer. – davidethell Feb 26 '18 at 12:02
  • @luk2302 I don't know anything about Base64, and that's what I got here the other day when I needed to encode image into Base64 for Firebase Database. How can I change the convertImageBase64 function? Thanks. – El Tomato Feb 26 '18 at 12:02
  • 1
    Why are you base64 encoding binary data and then storing in a `BLOB` column? Just store the raw binary. – eggyal Feb 26 '18 at 12:05
  • @eggyal Thanks. It's just a suggestion that I got from some web site. Thanks for advice. I'll change it. – El Tomato Feb 26 '18 at 12:10
  • 2
    @ElTomato: You might like to read [this answer](https://stackoverflow.com/a/14042709). – eggyal Feb 26 '18 at 12:54
  • @eggyal That's very nice of you. Thanks a lot. – El Tomato Feb 26 '18 at 12:59
  • @eggyal It's just that it was also a suggestion by many here for Firebase Database. So I've used it here as well. – El Tomato Feb 26 '18 at 13:00
  • @eggyal How would you change my 'postString' so that it could be sent to MySQL as raw binary as you've suggested? – El Tomato Feb 26 '18 at 13:08
  • @ElTomato: You can still `POST` the data to the HTTP server in Base64-encoded form if you want (it's definitely an easy approach, but look at [this answer](https://stackoverflow.com/a/26163136) for details on how you can submit raw binary as `multipart/formdata` if you want—although you might decide to use a third party library to do much of the grunt for you); I'm just saying that, once received at the HTTP server, it should be stored in MySQL in raw form: i.e. *decode* it first and then store in the database. – eggyal Feb 26 '18 at 13:33
  • @eggyal Thanks, eggyal. – El Tomato Feb 26 '18 at 13:41

1 Answers1

0

Drop the .lineLength64Characters options:

func convertImageBase64(image: UIImage) -> String? {
    guard let pictData = UIImagePNGRepresentation(image) else {
        return nil
    }
    let strBase64: String = pictData.base64EncodedString(options: [])
    return strBase64
}

That way the string will not have a \r\n in it in the first place.

luk2302
  • 55,258
  • 23
  • 97
  • 137