1

I have been struggling to get a web service to work with a native Swift application when a user is attempting to upload data using the "&" character, amongst others.

After various attempts at escaping the request, I am at a loss and looking for some advice to solving this. I have included a some code from both the Swift application and the PHP scripts for reference. The data is able to be posted to the server (I am using FileMaker Server PHP API), but not when the "&" is included in a user-submitted value as the JSON is being cut short when PHP hits that character.

The postData argument in the Swift request sample is a dictionary in JSON format, which is encoded using the below code from JSONStringify:

func JSONStringify(value: AnyObject, prettyPrinted: Bool = false) -> String {
    let options = NSJSONWritingOptions.PrettyPrinted
    if NSJSONSerialization.isValidJSONObject(value) {
        do {
            let data = try NSJSONSerialization.dataWithJSONObject(value, options: options)
            if let string = NSString(data: data, encoding: NSUTF8StringEncoding) {
                return string as String
            }
        } catch {
            return ""
        }
    }
    return ""
}

Swift Request

class func returnAnyObject (phpFile:String, postData:String) -> AnyObject? {
    let server:String = "http://myserver.com"
    let url = NSURL(string: "\(server)\(phpFile)")
    let cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData
    let request = NSMutableURLRequest(URL: url!, cachePolicy: cachePolicy, timeoutInterval: 10.0)
    request.HTTPMethod = "POST"

    // set data
    let dataString = postData.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
    let requestBodyData = (dataString as NSString).dataUsingEncoding(NSUTF8StringEncoding)
    request.HTTPBody = requestBodyData

    var response: NSURLResponse? = nil
    do {
        let reply: NSData = try NSURLConnection.sendSynchronousRequest(request, returningResponse:&response)
        if let results = NSString(data:reply, encoding:NSUTF8StringEncoding) {
            return results
        } else {
            return nil
        }
    } catch {
        return nil
    }
}

PHP

Below is the relevant portion of the PHP script. Perhaps there is some step I am missing with this as well?

<?php
    error_reporting(E_ERROR | E_WARNING | E_PARSE);
    $req1 = '../../FileMaker.php';
    $req2 = '../../FM_Connect.php';
    require_once $req1;
    require_once $req2;

    //set fixed variables
    $layout = 'php_Lineitems';

    //Define passed variables
    $json = $_POST['json'];
    $json = stripslashes($json);
    $fieldArray = json_decode($json); // This is now an associative array
?>
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Michael Voccola
  • 1,827
  • 6
  • 20
  • 46
  • 2
    I agree with meda: If you're going to POST JSON, then just post JSON, and completely eliminate this percent escaping stuff, to say nothing of the round-tripping the JSON from `NSData` to `String` and back. If you really feel compelled to put this JSON inside a `application/x-www-form-urlencoded` request, then `stringByAddingPercentEscapesUsingEncoding` is not up to the job, as it will let ampersands go my unescaped. See http://stackoverflow.com/a/25154803/1271826 for alternative that will percent-escape properly. But posting JSON directly (without any percent escaping) is far cleaner approach. – Rob Jun 25 '15 at 20:55

1 Answers1

2

Don't put the JSON as a string, you don't need to stringify it, should be of NSData type.

Then you set that in the body of your request directly.

Note on the PHP side you won't be able to access $_POST['json'].

You will need to change your code to:

$json = json_decode(file_get_contents('php://input'));
meda
  • 45,103
  • 14
  • 92
  • 122
  • Doing this, the PHP script stops at the JSON line you suggested adding. Using `echo` to test, it will echo a line before the $json line, but does not run or throw an errors after. Is there anything else the PHP file needs to know? In the Swift side, I am setting `request.HTTPMethod = "POST` and doing this `let requestBodyData = try! NSJSONSerialization.dataWithJSONObject(postDict, options: NSJSONWritingOptions(rawValue:0)) request.HTTPBody = requestBodyData` – Michael Voccola Jun 25 '15 at 23:23
  • You can try var_dump before encoding and also try to turn on error reporting – meda Jun 25 '15 at 23:29
  • Got it! changed the definition of `$json` to `$json = file_get_contents('php://input');`, removing the `$json_decode()` portion. Thanks! – Michael Voccola Jun 25 '15 at 23:34
  • Oh I see my typo I meant the $json would be the decoded data, good luck – meda Jun 25 '15 at 23:58