Using PHP and curl to post JSON data to the iMIS API

As a programming challenge, I recently decided to tackle using PHP and curl to connect to the iMIS API from outside the confines of RiSE. It’s relatively simple to get data from the iMIS API when you’re already logged in to an iMIS website, but I wanted to figure out how to post data to the API from an entirely different server. Documentation refers to this as direct access.

For my experiment, I created a PHP file on an external server. From a webpage within an instance of iMIS, I posted JSON data to my PHP file, which in turn retrieved an authorization token from iMIS and then used that token to submit the data to to the API.

<?php


// full URL of iMIS site
$url = "https://www.example.org";

// iMIS user's credentials
$username = "testuser";
$password = "testpassword";


if ($_SERVER["REQUEST_METHOD"] == "POST") {

    // JSON submitted by POST
    $json = file_get_contents("php://input");
    
    // ensure API URL and JSON are defined
    if ($_REQUEST["url"] != null && $json != null) {
    
        // address from which we get a token
        $tokenURL = $url . "/token";
        // API address to which we post data
        $apiURL = $url . "/api" . $_REQUEST["url"];
        
        callAPI($tokenURL, $username, $password, $apiURL, $json);
    } else {
    
        header("HTTP/1.0 401 Bad Request");
        
    $html = <<<EOT
<!DOCTYPE html>
<html lang="en-US">
    <head>
        <meta charset="utf-8">
        <title>401 Bad Request</title>
    </head>
    <body>
        <p>401 Bad Request</p>
    </body>
</html>
EOT;
        
        echo $html;
    }
}


// used to pass Ajax call to API
function callAPI($thisTokenURL, $thisUsername, $thisPassword, $thisAPIURL, $thisJSON) {

    // grab an authorization token to send to API with POST
    $token = getToken($thisTokenURL, $thisUsername, $thisPassword);
    
    // token length will be this short only if an HTTP error status code was returned
    if (strlen($token) < 5) {
        header("HTTP/1.0 " . $token);
    } else {
    
        // this is the header we will send to API
        $header = array("authorization: Bearer " . $token, "Content-Type: application/json");
        
        // initiate curl instance
        $curl = curl_init();
        
        curl_setopt_array($curl, array(
            CURLOPT_URL => $thisAPIURL,
            CURLOPT_HTTPHEADER => $header,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $thisJSON,
            CURLOPT_FAILONERROR => true
        ));
        
        $response = curl_exec($curl);
        
        // tell browser the result of the call
        header("HTTP/1.0 " . curl_getinfo($curl, CURLINFO_RESPONSE_CODE));
        
        curl_close($curl);
        
        return;
    }
}


// retrieve token for use in API call
function getToken($thisTokenURL, $thisUsername, $thisPassword) {

    // this is the username and password we will send
    $content = "grant_type=password&username=$thisUsername&password=$thisPassword";
    // this is the header we will send
    $header = array("Content-Type: application/x-www-form-urlencoded");
    
    $curl = curl_init();
    
    curl_setopt_array($curl, array(
        CURLOPT_URL => $thisTokenURL,
        CURLOPT_HTTPHEADER => $header,
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => $content,
        CURLOPT_FAILONERROR => true
    ));
    
    $response = curl_exec($curl);
    
    $json = null;
    $returnStr = "";
    
    // return HTTP status code if there was an error; otherwise, return token
    if (curl_errno($curl)) {
        $returnStr = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
    }
    else {
        $json = json_decode($response, true);
        $returnStr = $json["access_token"];
    }
    
    curl_close($curl);
    
    return $returnStr;
}


?>

Naturally, you wouldn’t use something unsecured like this in a production environment; with the iMIS credentials pre-populated, anyone who hit the page could submit data to the API with no questions asked! Definitely a no-go. In addition, this PHP code retrives a new token every time it runs; that token should be saved and re-used until it expires.

Nevertheless, figuring out how to make this work was an interesting exercise, and I was able to connect to the iMIS API from outside the confines of RiSE. Such knowledge could come in handy somewhere down the road.