0

I am trying to return json from PHP / PDO but I get this error in Swift.

Error Domain=NSCocoaErrorDomain Code=3840 "Garbage at end." UserInfo={NSDebugDescription=Garbage at end.}

Here is the PHP file.

//*FUNCTION TO GET CARD FROM SEARCH WORD CALLED FROM GetCards.php   
public function getAllCards($word) {

//Connect to db using the PDO not PHP
$db = new PDO('mysql:host=localhost;dbname=xxxx', 'xxxx', 'xxxxx');

//Here we prepare the SELECT statement from the search word place holder :word
$sql = $db->prepare('SELECT * FROM carddbtable WHERE businessNameDB=:word OR lastNameDB=:word OR firstKeywordDB=:word OR    secondKeywordDB=:word OR thirdKeywordDB=:word OR fourthKeywordDB=:word OR fithKeywordDB=:word');

//We execute the $sql with the search word variable"$word"
$sql->execute([':word' => $word]);

//Looping through the results
while ($row = $sql->fetch(PDO::FETCH_ASSOC)) {

//Print to screen
 //  echo json_encode($row). "<br>"."<br>";

//Store all return rows in $returnArray
$returnArray[] = $row;
}

//Feedback results
return $returnArray;

}  

Here is the Swift.

    //Search and retrieve card / users
func doSearch (word : String) {

    //Search word from searchKeyWordVar
    let word = "TODAY"

    // URL path to GetCards.php
    let url = NSURL(string: "http://www.xxxxxxx.com/xxx/xx/GetCards.php")

    //Create URL request
    let request = NSMutableURLRequest(url: url! as URL)

    //Method to pass info to GetCards.php
    request.httpMethod = "POST"

    //body that passing info to php
//        let body = "word=\(word)"
    let body = "TODAY" //This is hard coded for testing

    //convert string to utf8 for all languages
    request.httpBody = body.data(using: String.Encoding.utf8)


    //Launch session
    URLSession.shared.dataTask(with: request as URLRequest) { (Data, response, error) in


        //Get main Queue
        DispatchQueue.main.async(execute: {

            if error == nil {

                do {
                    // declare json var to store $returnArray inf we got from GetCards.php
                    let json = try JSONSerialization.jsonObject(with: Data!, options: .mutableContainers) as? NSDictionary


                    // delcare new secure var to store json
                    guard let parseJSON = json else {
                        print("Error while parsing")
                        return
                    }

                    // declare new secure var to store $returnArray["users"]
                    guard let parseUSERS = parseJSON["users"] else {
                        print(parseJSON["message"] ?? [NSDictionary]())
                        return
                    }

                } catch {
                    print(error)
                }


                } else {
                    print(error as Any)
                }


    })

}.resume()


}

Agin the swift error is Error Domain=NSCocoaErrorDomain Code=3840 "Garbage at end." UserInfo={NSDebugDescription=Garbage at end.}

I just don't see it. when I run the test from a web page I get json that looks like this.

{"users":[{"idDB":"383","addressNotsDB":"\n","alternateNameDB":"","alternateNumberDB":"","businessMainCategoryDB":"News","businessNameDB":"TODAY"}]}

The app calls GetCards.php This calls the DBopperation.php This has a public_function named getAllCards($word)

This is the GetCards.php

//STEP: 1 Make connection to DB
//Including the db operation file for connection to DB
$cardConnect = require_once 'DbOperation.php';

//Checking if there is a connection to DB
if ($cardConnect) {
$returnArray1['Connected to DB'] = '200';
} else {
$returnArray1['Did not connect ot DB'] = '400';
}
//echo json_encode($returnArray1). "<br>"."<br>";


//STEP: 2 Connecting to Public Function
//Connecting the DbOperation.php file public fuction getAllCards to the       variable $card
$card = new DbOperation();

//If connected  
if ($card) {

//Checking connection to the DbOperation.php 
    $returnArray2['Connected to GetCards.php'] = '200';
} else {
    $returnArray2['Could not connect to GetCards'] = '400';
}
//echo json_encode($returnArray2). "<br>"."<br>";


//STEP: 3 Running the search
//Creating a varable to hold the search word and setting it to null
$word = null;

//Getting to search word from the app
if (!empty($_REQUEST["word"])) {
    $word = htmlentities($_REQUEST["word"]);
}
// STEP 4. Access searching func and retrieve data from server
$users = $card->getAllCards($word);

if (!empty($users)) {
    $returnArray3["users"] = $users;
} else {
    $returnArray3["message"] = 'Could not find records in GetCards';
}


// STEP 4. Close connection
$card->disconnect();

// STEP 5. Pass information back as json to user
echo json_encode($returnArray);
5
  • Based on your PHP code I see no way that your JSON response could possibly look like what you have posted. Commented Jul 12, 2017 at 0:16
  • If JSON parsing fails, you should print the contents of the data (e.g. print(String(data: data!, encoding: .utf8)) in Swift 3), so you can see exactly what it was trying to parse. Also note that Data is the name of a type in Swift 3, so I’d suggest using the variable name data rather than Data. Commented Jul 12, 2017 at 0:35
  • What calls getAllCards? Where is the response printed from the server? Commented Jul 12, 2017 at 0:38
  • After you edited your answer your JSON looks more plausible - at least more than just two column fields are being displayed. But in order to get the JSON "users" array you must at least be adding the row to an array object something like json_encode(array("users" => $returnArray)); Commented Jul 12, 2017 at 0:53
  • The DBOperation.php was ok. I had to edit the last line in the GetCards.php to echo json_encode($returnArray3): I left off the 3. In The swift I had to change //body that passing info to php // let body = "word=(word)" let body = "TODAY" //This is hard coded for testing "BACK TO" //body that passing info to php let body = "word=(word)" // let body = "TODAY" //This is hard coded for testing Everywhere there was Data I had to change to lowercase data. Thanks to all for your help. Commented Jul 12, 2017 at 2:30

3 Answers 3

1

Your issue is with the data being sent by the server it seems, firstly:

echo json_encode($row). "<br>"."<br>";

Why the garbage at the end? You are supposed to be sending back json, why are you adding erroneous html tags?

echo json_encode($row);

Secondly, why are you printing from the function?

You define your function, that for each row it fetches, will print a JSON Object. In the posted example, you seem to only have a singe row, with more then one row this will fail as {}{} is not a valid JSON Object.

Change it to this:

public function getAllCards($word) {

    ...

    //Looping through the results
    while ($row = $sql->fetch(PDO::FETCH_ASSOC)) {

        //Store all return rows in $returnArray
        $returnArray[] = $row;
    }

    //Feedback results
    return $returnArray;
}  

Then your caller should print it:

$arrayOfResults = getAllCards();
echo json_encode( $arrayOfResults );
Sign up to request clarification or add additional context in comments.

2 Comments

I edited the return json. This is what I get back when I echo.
HTML tag are for test stright from web page testing the pdo. I rem the echo out before running the code in the swift app.
0

The code echoes an "<br>"."<br>" at the end of each row, witch invalidate the JSON structure. You cannot see this because this PHP output a HTML response and in this case the "<br>"."<br>" just add some lines... but for parsing the JSON they are invalid.

I think the most correct is to output the array as JSON and tell the HTTP client that is a JSON output, like this:

//*FUNCTION TO GET CARD FROM SEARCH WORD CALLED FROM GetCards.php   
public function getAllCards($word) {

//Connect to db using the PDO not PHP
$db = new PDO('mysql:host=localhost;dbname=xxxx', 'xxxx', 'xxxxx');

//Here we prepare the SELECT statement from the search word place holder :word
$sql = $db->prepare('SELECT * FROM carddbtable WHERE businessNameDB=:word OR lastNameDB=:word OR firstKeywordDB=:word OR    secondKeywordDB=:word OR thirdKeywordDB=:word OR fourthKeywordDB=:word OR fithKeywordDB=:word');

//We execute the $sql with the search word variable"$word"
$sql->execute([':word' => $word]);

//Empty the returnArray
$returnArray = array();

//Looping through the results
while ($row = $sql->fetch(PDO::FETCH_ASSOC)) {

//Store all return rows in $returnArray
$returnArray[] = $row;
}

// Tell that is a JSON output
header('Content-Type: application/json');

//Feedback results
return json_encode($returnArray);

}  

3 Comments

Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
I have removed all echo's
Well, you can insert an object using something like:return json_encode(array("users" => $returnArray));... try it out! This outputs a JSON with an collection labeled "users", i think is that your Swift code needs...
0

If your JSON output is truly legitimate JSON than try replacing your DispatchQueue with this:

    DispatchQueue.main.async(execute: {

        if error == nil {

            do {

                guard let jsonData = Data? else{
                    return
                }

                let json = try? JSONSerialization.jsonObject(with: jsonData)

                guard let parseJSONDict = json as? [String : Any] else{
                    print("Error while parsing")
                    return
                }

                guard let parseUSERS = parseJSONDict["users"] else{
                    return
                }


            } catch {
                print(error)
            }


            } else {
                print(error as Any)
            }


}) 

4 Comments

When building It I gets an error. initializer for conditional binding must have Optional type, not 'Data.Type'
Probably needs guard let jsonData = Data? else
This was on the guard let jsonData = Data else{
I got it working now and I will post all the changes.. Thanks to all for the help. Thanks

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.