0

I am trying to send an image to server, but the image should be in Base64 format. I am using this function to send it:

func upload_signature_staff(ticket: NSString){
        let defaults = NSUserDefaults.standardUserDefaults()
        let stringOne = defaults.stringForKey(defaultsKeys.staff_id)
        let stringtwo = defaults.stringForKey(defaultsKeys.mst_customer)
        let sig = defaults.stringForKey("staff_signature")
        let request = NSMutableURLRequest(URL: NSURL(string: "http://xxxxxxxxxxxxx/upload.php")!)
        request.HTTPMethod = "POST"
        let postString = "action=add_signature&mst_customer=\((stringtwo!))&ticket=\((ticket))&signature=\((sig!))&current_user=\((stringOne!))&item_type=10"
        print(postString)
        request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
        let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
            guard error == nil && data != nil else {                                                          // check for fundamental networking error
                print("error=\(error)")
                return
            }

            if let httpStatus = response as? NSHTTPURLResponse where httpStatus.statusCode != 200 {           // check for http errors
                print("statusCode should be 200, but is \(httpStatus.statusCode)")
                print("response = \(response)")
            }

            let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
            print("responseString = \(responseString)")
        }
        task.resume()
        //self.performSegueWithIdentifier("goto_main2", sender: self)
    }

The sig variable holds the Base64 string, it is being printed in my console so I can verify that the string is correct. I am also printing the postString and upon inspection it is also correct that the signature is matching the Base64 String. But when I open phpmyadmin, I see the field of my image with incomplete Base64 string, maybe 1/4 is just there.

Here's my php code, in case you want to see it:

<?php
require_once("../c.php");

$action = trim($_POST['action']);

if($action == "add_signature"){
    $mst_customer = trim($_POST['mst_customer']);
    $ticket = trim($_POST['ticket']);
    $signature = trim($_POST['signature']);
    $current_user = trim($_POST['current_user']);
    $item_type = trim($_POST['item_type']);
    $inputtime = time();

    $sql = "INSERT INTO ticket_items SET mst_customer = '$mst_customer', ticket = '$ticket', ticket_item_type = '$item_type', details = '$signature', addedby = '$current_user', lastupdate = '$inputtime' ";

    mysql_query($sql) or die(mysql_error());
}

?>
Jayson Tamayo
  • 2,741
  • 3
  • 49
  • 76
  • server side, try to determine whether the body `travelled` correctly (echo, print, log) $signature, to see if it is as you expect. If yes, check your table schema to make certain it can accommodate a variable length text field (b64). – YvesLeBorg Mar 29 '16 at 13:59
  • 1
    @YvesLeBorg my field is `varchar(255)` - maybe this is the culprit? What size should I put instead? – Jayson Tamayo Mar 29 '16 at 14:02
  • I don't know Swift and I didn't read your code but I simply have to ask... Are you url encoding your base64? Does the string break at `+`, `=` and `/`? If your base64 string is always cut to the same length, ignore my question and look for database fields that may be too small to hold the string instead. – jDo Mar 29 '16 at 14:04
  • @jDo It doesn't seem to cut right before those characters. – Jayson Tamayo Mar 29 '16 at 14:06
  • 1
    @JaysonTamayo hard to give you practical advice. I for one will tend to store variable length stuff as blob's rather than any other `textish` field type. If you persist with varchar, you will need a means to limit the source signature to a maximum length to ensure that you can later store it in your db. If you cant limit the source signature size (b64), whatever size you chose for the `varchar` will break one day or another. See [this](http://stackoverflow.com/questions/22756583/how-to-set-a-varchar-to-have-unlimited-length) on a related topic. – YvesLeBorg Mar 29 '16 at 14:11
  • 1
    @JaysonTamayo 255 characters seems way too small for handling binary data unless we're talking icons coupled with some heavy user input validation/restrictions. Speaking of which, your PHP is very hackable/injectable. – jDo Mar 29 '16 at 14:14
  • 1
    @jDo ... injection will be my epitaph , as you can see [here](https://xkcd.com/327/) – YvesLeBorg Mar 29 '16 at 14:15
  • @YvesLeBorg Classic! ;--) (mandatory injection smiley) – jDo Mar 29 '16 at 14:22
  • @YvesLeBorg Regardless of injection etc., my field is also used to have integer, timestamp and other data. If I don't opt for BLOB type, can I use `varchar(100000)`? – Jayson Tamayo Mar 29 '16 at 14:26
  • 1
    @JaysonTamayo errr .... to each his own. That would depend on your version of sql ... current limit is (i think) 65,535. Nothing like rtfm or read the links we put here to help you out. – YvesLeBorg Mar 29 '16 at 14:42
  • @jDo I changed my varchar size but my next problem is tha value in my field is missing + from the original Base64. Is there any way to fix it in PHP? – Jayson Tamayo Mar 29 '16 at 16:17
  • @jDo It is working now, I replaced all + to %2B. Thank you! – Jayson Tamayo Mar 29 '16 at 16:25
  • @JaysonTamayo The unpleasant truth is that if you want to reach production readiness, you'll have to redesign your DB layout and fix the PHP. Your frontend is untrusted per definition because the millions of hackers out there can simply skip/manipulate it and pound your API + DB directly. The rule of thumb regarding DB fields is that if you can separate the data even further, you should. E.g. JSON in DBs is a no-go and resorting to "blob" is laziness in most cases (there are exceptions). If the *"field is also used to have integer, timestamp and other data"* there is something wrong. – jDo Mar 29 '16 at 16:27
  • @JaysonTamayo For url encoding, use `urlencode()` which you can read about [here](https://secure.php.net/manual/en/function.urlencode.php) rather than manual replacement. For injection prevention, read up on PDO and prepared statements in general – jDo Mar 29 '16 at 16:29
  • @JaysonTamayo ...and you're welcome :) – jDo Mar 29 '16 at 16:34

1 Answers1

1

I think this was solved in the comments but here's a recap:

Inserting base64 strings that were too long (variable length?) in a varchar(255) field resulted in missing data. As far as I can tell, increasing the size of the field solved the immediate problem. I use the term "immediate" because, as @YvesLeBorg pointed out in the comments, this is bound to fail at some point without input size restrictions on the backend.

Additionally, I couldn't ignore the fact that the PHP/SQL code was wide open to injections.

Passing $mst_customer = trim($_POST['mst_customer']); on to "INSERT INTO ticket_items SET mst_customer = '$mst_customer' and then executing via mysql_query($sql) or die(mysql_error()); is dangerous!

Anybody could write anything in the $_POST parameter and SQL would happily accept it. Prepared statements, PDO, input sanitization etc. are there for a reason.

Finally, there was an issue concerning vanishing + signs in the base64 data. This was the result of missing url encoding of the post data.

I think that sums it up.

jDo
  • 3,962
  • 1
  • 11
  • 30