In yesterday’s article, we took a look at the server’s reply format. You now have all the information you need to construct the core of a library and start making server requests.

Here is some sample PHP code for making POST and GET style queries. This library will let you make a query, and return a stdClass object containing the serialised fields as described yesterday, from this you can build wrapper functions for the methods.

$API_CLIENT = new stdClass;

// Configure your client
$API_CLIENT->api_key = "your api key";
$API_CLIENT->secret = "your secret key";
$API_CLIENT->api_endpoint = "http://elggvoices.com/api/v1/";
$API_CLIENT->hmac_algo = 'sha256';
$API_CLIENT->postdata_hash_algo = 'md5';

// Status variables we can query later
$LAST_CALL = null;
$LAST_CALL_RAW = "";
$LAST_ERROR = null;

/**
* Generate our HMAC.
*/
function calculate_hmac($algo, $time, $api_key, $secret_key, $get_variables, $post_hash = "")
{
$ctx = hash_init($algo, HASH_HMAC, $secret_key);
hash_update($ctx, trim($time));
hash_update($ctx, trim($api_key));
hash_update($ctx, trim($get_variables));
if (trim($post_hash)!="") hash_update($ctx, trim($post_hash));
return hash_final($ctx);
}

/**
* Generate our POST hash.
*/
function calculate_posthash($postdata, $algo)
{
$ctx = hash_init($algo);
hash_update($ctx, $postdata);
return hash_final($ctx);
}

/**
* Serialise HTTP headers.
*/
function serialise_headers(array $headers)
{
$headers_str = "";
foreach ($headers as $k => $v)
$headers_str .= trim($k) . ": " . trim($v) . "\r\n";
return trim($headers_str);
}

/**
* Make a raw call.
* @param array $method Method call parameters.
* @param string $postdata Optional POST data.
* @param string $content_type The content type.
* @return stdClass
*/
function call(array $method, $postdata = "", $content_type = 'application/octet-stream')
{

// Get the config
global $API_CLIENT, $LAST_CALL, $LAST_CALL_RAW, $LAST_ERROR;

$headers = array();
$encoded_params = array();

$time = microtime(true); // Get the current time in microseconds
$request = ($postdata!="" ? "POST" : "GET"); // Get the request method, either post or get

// Hard code the format - we're using PHP, so lets use PHP serialisation.
$method['format'] = "php";

// URL encode all the parameters
foreach ($method as $k => $v){
$encoded_params[] = urlencode($k).'='.urlencode($v);
}

$params = implode('&', $encoded_params);

// Put together the query string
$url = $API_CLIENT->api_endpoint."?". $params;

// Construct headers
$posthash = "";
if ($request=='POST')
{
$posthash = calculate_posthash($postdata, $API_CLIENT->postdata_hash_algo);
$headers['X-Searunner-posthash'] = $posthash;
$headers['X-Searunner-posthash-algo'] = $API_CLIENT->postdata_hash_algo;
$headers['Content-type'] = $content_type;
$headers['Content-Length'] = strlen($postdata);
}

$headers['X-Searunner-apikey'] = $API_CLIENT->api_key;
$headers['X-Searunner-time'] = $time;
$headers['X-Searunner-hmac-algo'] = $API_CLIENT->hmac_algo;
$headers['X-Searunner-hmac'] = calculate_hmac($API_CLIENT->hmac_algo,
$time,
$API_CLIENT->api_key,
$API_CLIENT->secret,
$params,
$posthash
);

// Configure stream options
$opts = array(
'http'=>array(
'method'=> $request,
'header'=> serialise_headers($headers)
)
);

// If this is a post request then set the content
if ($request=='POST')
$opts['http']['content'] = $postdata;

// Set stream options
$context = stream_context_create($opts);

// Send the query and get the result and decode.
$LAST_CALL_RAW = file_get_contents($url, false, $context);
$LAST_CALL = unserialize($LAST_CALL_RAW);

if (($LAST_CALL) && ($LAST_CALL->status!=0)) // Check to see if this was an error
$LAST_ERROR = $LAST_CALL;

return $LAST_CALL; // Return a stdClass containing the API result
}

// Example GET call
$get = call(
array (
'method' => 'test.test',
'variable1' => 1,
'variable2' => "test string"
)
);

// Example POST call
$post = call(
array (
'method' => 'test.test',
'variable1' => 1,
'variable2' => "test string"
),
"Some post data"
);

// Output
echo "Example GET result: \n";
print_r($get);

echo "Example POST result: \n";
print_r($post);

One thought on “Getting started with the elggVoices API (part 4 – Putting it all together)

Leave a Reply