Foreach loop through JSON API with one element


#1

Hi guys, got a little bit of an issue here. I’m using a function which acts as a search function. It gives a curl request to an API which then returns the data as JSON as an Array and if there are multiple entries it populates the table.

If it only returns one entry, however, I get an error saying "Illegal string offset ‘(header name)’. Now I tested this by outputting the entirety of the array which looks like this:

Array ( [id] =>; 19 [firstname] =>; ayden [lastname] =>; guy [companyname] =>; [email] =>; ay@mail.com [datecreated] =>; 2018-10-17 [groupid] =>; 0 [status] =>; Active )

If I try to output the elements of the array it just prints out “Active”.

Here is the PHP + HTML:

<?php
session_start();

if(!isset($_SESSION['user'])) {
        // user is not logged in, do something like redirect to login.php
        header("Location: index.php");
        die();
}
?>
<!DOCTYPE html>
<?php
session_start();

if(!isset($_SESSION['user'])) {
        // user is not logged in, do something like redirect to login.php
        header("Location: index.php");
        die();
}
$page_title = "Hyperslice Management Dashboard";
$page_description = "Internal Hyperslice Management Dashboard";
?>
<!DOCTYPE html>
<html lang="en">
<head>

  <meta charset="utf-8">
  <title><?php echo $page_title; ?></title>
  <meta name="description" content="<?php echo $page_description; ?>">
  <meta name="author" content="">

  <meta name="viewport" content="width=device-width, initial-scale=1">

  <link href="//fonts.googleapis.com/css?family=Raleway:400,300,600" rel="stylesheet" type="text/css">

  <link rel="stylesheet" href="css/normalize.css">
  <link rel="stylesheet" href="css/skeleton.css">
  <link rel="stylesheet" href="css/othertable.css">
  <link rel="stylesheet" href="css/form.css">

  <link rel="icon" type="image/png" href="images/favicon.png">

</head>
<body>

<?php include("includes/header.html");?>

<center><h2>Search and Create new Clients</h2></center>
<form method ="post" action = "veeam.php">
<ul class="form-style-1">
    <li><label>Name or Email <span class="required">*</span></label><input type="text" name="clientsearch" class="field-divided" placeholder="Enter details" />
    <li>
        <input type="submit" name="submit" onSubmit="invokeapi()"/>
    </li>
</ul>
</form>

<?php

function invokeapi()
{
 
 $client = $_POST["clientsearch"];

  $username = 'username';
  $password = 'password';
  $url = 'http://apicall/?command=Check-ClientWHMCS%20'.$client;

  $ch = curl_init();

  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
  curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Length: 0'));
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 
    if (curl_errno($ch)) {
        echo 'Error:' . curl_error($ch);
    }

  $output = curl_exec($ch);
  
  curl_close($ch);
    $clientlist = array();
    $clientlist = json_decode($output, 1);
    
    
    if($clientlist != ""){
    ?>
    <table>
        <caption>Clients Found</caption>
    <thead>
    <tr>
      <th scope="col">ID</th>
      <th scope="col">Forename</th>
      <th scope="col">Surname</th>
      <th scope="col">Email</th>
      <th scope="col"></th>
    </tr>
    </thead>
    <tr>
      
    <?php
    
    foreach($clientlist as $clients){
    ?>

    <tbody>
    <tr>
      <td data-label="ID"><?php echo $clients['id'];?></td>
      <td data-label="Forename"><?php echo $clients['firstname'];?></td>
      <td data-label="Surname"><?php echo $clients['lastname'];?></td>
      <td data-label="Email"><?php echo $clients['email'];?></td>
      <td>
      <form method="post" action= "editjob.php">
      <input type="hidden" id="custId" name="custId" value="<?php $clients[id];?>">
      <input type ="submit" name="edit" value="select" onSubmit="editClient()"/>
      </form>
      </td>
    </tr>
    <?php    
    }
    unset($clients);
    print_r($clientlist);
    ?>

    </tbody>
    </table>
    <?php
    }
    else{
        echo "Please enter a search term";
    }
}

if(isset($_POST['clientsearch']))
{
    invokeapi();
}


?>

And the JSON looks like this:

{
    "id":  19,
    "firstname":  "ayden",
    "lastname":  "guy",
    "companyname":  "",
    "email":  "ay@mail.com",
    "datecreated":  "2018-10-17",
    "groupid":  0,
    "status":  "Active"
}

I’m completely stumped here, I apologise that the code is really messy and hard to follow but i’ve tried to explain it as best I can.

Any help would be appreciated.


#2

That’s some annoying API. It appears that when there is only one result it doesn’t return an array with only that object as you would expect (and what most APIs do), but it just returns the one object.

What you could do is the following:

$clientlist = json_decode($output, 1);
if (isset($clientlist['id'])) {
    $clientlist = [$clientlist];
}

rather annoying, but at least it has small impact on the code as whole.

The best solution would be to contact the vendor of the API and tell them to fix their API.


#3

I’m working with the guy who created the API but he’s just gone home for the day.

If I search for something with multiple values, the JSON will format as such:

[
    {
        "id":  2,
        "firstname":  "Edward",
        "lastname":  "Franks",
        "companyname":  "",
        "email":  "EdwardFranks@mail.com",
        "datecreated":  "2018-10-09",
        "groupid":  0,
        "status":  "Inactive"
    },
    {
        "id":  1,
        "firstname":  "Frank",
        "lastname":  "Tighe",
        "companyname":  "U32 Consultation",
        "email":  "frank@mail.co.uk",
        "datecreated":  "2018-10-08",
        "groupid":  0,
        "status":  "Active"
    }
]

So, when it returns multiple it’s an array but if it returns singular it only returns an object?


#4

Also, what you sent me has fixed the problem entirely. I’ve spent about three hours on this so thank you!


#5

That should be mentioned in the API documentation.

Generally, the same API end-point should always return the same result data type.


#6

He’s using powershell to do the API and he’s still learning it (and i’m learning PHP) so i’ll let him know what’s going on.