How to start with the Omniture REST API in PHP

by adierl on 11/25/10

With my first post on developer.omniture.com I'd like to cover a common question: "How to start with the Omniture REST API in PHP".

The easiest way to query the REST API is using cURL. Current PHP versions usually have this module build-in out-of-the-box. For older versions you can add the cURL support.

Although you can use the curl functions directly I prefer using this small and simple REST class from Tony Chang https://github.com/tonychang/PhpRestClient (saved as SimpleRestClient.class.php for my examples)

First we need to take care about the authentication headers to successfully query the API. (Details: https://developer.omniture.com/gettingstarted/authenticateAPI)
You need 4 values:

  • Username
    You'll get your Username from your SiteCatalyst Admin or under SiteCatalyst -> Admin Console > Company > Web Services.
  • Nonce
    The Nonce is a simple unique id to each call to prevent MITM attacks.
    Easiest way to create them:
    $nonce = md5(rand());
  • Created
    The current timestamp in ISO-8601 format. PHP supports this format natively:
    $nonce_ts = date('c');
  • PasswordDigest
    The Password digest is a concatenation of the nonce, its timestamp and your password (from the same location as your username) which runs through SHA1 and then through a base64 encoding:
    $digest = base64_encode(sha1($nonce.$nonce_ts.$secret));

Those values will be added to the REST call as a HTTP header.

The API server you need to send you call to depends on your data center location. It should be either api.omniture.com (San Jose aka. 112) or api2.omniture.com (Dallas aka. 122)

Ok, enough text, let's make our first API call. I'll use Company.GetTokenUsage since it does not require any additional parameters:


<?php
	include_once("SimpleRestClient.class.php");

	$username = '%%YOUR-USERNAME%%';
	$secret = '%%YOUR-SECRET%%';
	$nonce = md5(rand());
	$nonce_ts = date('c');
	
	$digest = base64_encode(sha1($nonce.$nonce_ts.$secret));
	
	$server = "https://api.omniture.com";
	$path = "/admin/1.2/rest/";
	
	$rc=new SimpleRestClient();
	$rc->setOption(CURLOPT_HTTPHEADER, array("X-WSSE: UsernameToken Username=\"$username\", PasswordDigest=\"$digest\", Nonce=\"$nonce\", Created=\"$nonce_ts\""));
	
	$query="?method=Company.GetTokenUsage";
	
	$rc->getWebRequest($server.$path.$query);
	
	if ($rc->getStatusCode()==200) {
		$response=$rc->getWebResponse();
		var_dump($response);
	} else {
		echo "something went wrong\n";
		var_dump($rc->getInfo());
	}
?>

This should get you something like:

string(185) "{"allowed_tokens":10000,"used_tokens_total":4,"token_period":"month","status":"normal","overage_enabled":"0","token_usage":[{"login":"jdoe","name":"John Doe","used_tokens":"4"}]}"

As you can see this API returns a JSON string and not XML as SOAP or some other REST APIs might use. JSON is a lightweight method to exchange data with less overhead than XML. (More info: http://json.org). PHP >= 5.2.0 has a JSON decoder on-board

$json=json_decode($response);

This will give you a clean object with no further need to parse the JSON string or similar.

Ok, let's go one step further and pull the first report from SiteCatalyst.


<?php
	include_once("SimpleRestClient.class.php");

	function GetAPIData($method, $data='') {
		$username = '%%YOUR-USERNAME%%';
		$secret = '%%YOUR-SECRET%%';
		$nonce = md5(rand());
		$nonce_ts = date('c');
		$digest = base64_encode(sha1($nonce.$nonce_ts.$secret));
		
		$server = "https://api.omniture.com";
		$path = "/admin/1.2/rest/";
		
		$rc=new SimpleRestClient();
		$rc->setOption(CURLOPT_HTTPHEADER, array("X-WSSE: UsernameToken Username=\"$username\", PasswordDigest=\"$digest\", Nonce=\"$nonce\", Created=\"$nonce_ts\""));
	
		$rc->postWebRequest($server.$path.'?method='.$method, $data);
		
		return $rc;
	}
	
	$method="Report.QueueRanked";
	$data='{
			"reportDescription":{
				"reportSuiteID":"%%YOUR_RSID%%",
				"dateFrom":"2010-10-01",
				"dateTo":"2010-10-31",
				"metrics":[{"id":"pageviews"}],
				"elements":[{"id":"page","top":"25"}]
			}
		   }';
	
	$rc=GetAPIData($method, $data);
	
	if ($rc->getStatusCode()==200) {
		$response=$rc->getWebResponse();
		$json=json_decode($response);
		if ($json->status=='queued') {
			$reportID=$json->reportID;
		}
		else {
			$error=true;
			echo "not queued - ";
		}
	} else {
		$error=true;
		echo "something went really wrong\n";
		var_dump($rc->getInfo());
		echo "\n".$rc->getWebResponse();
	}
	
	while (!$done && !$error) {
		sleep(15);
		
		$method="Report.GetStatus";
		$data='{"reportID":"'.$reportID.'"}';
		
		$rc=GetAPIData($method, $data);
		
		if ($rc->getStatusCode()==200) {
			$response=$rc->getWebResponse();
			$json=json_decode($response);
	
			if ($json->status=="done") {
				$done=true;
			}
			else if ($json->status=="failed" || strstr($json->status, "error")>0) {
				$error=true;
			}
		} else {
			$done=true;
			$error=true;
			echo "something went really wrong\n";
			var_dump($rc->getInfo());
			echo "\n".$rc->getWebResponse();
		}
	}
	
	if ($error) {
		echo "report failed:\n";
		echo $response;
	}
	else {
		$method="Report.GetReport";
		$data='{"reportID":"'.$reportID.'"}';
		
		$rc=GetAPIData($method, $data);
		if ($rc->getStatusCode()==200) {
			$response=$rc->getWebResponse();
			$json=json_decode($response);
			echo "your report:\n";
			//var_dump($json);
			echo "Page:PageViews\n";
			foreach ($json->report->data as $el) {
				echo $el->name.":".$el->counts[0]."\n";
			}
		} else {
			echo "something went really wrong\n";
			var_dump($rc->getInfo());
			echo "\n".$rc->getWebResponse();
		}
	}
	
?>

This sample will give you the Top25 Pages of the given Report Suite ID. I've encapsulate the API call into a function since the nonce and so the digest need to be recreated for every new call. You can also build a new class if you want to combine the REST class with the API wrapper.
No, I did neither pretty-print the results nor commented the code, that's your job now ;)

To easily test a new function or JSON request string, I strongly suggest the use of the API Explorer: https://developer.omniture.com/apiexplorer

Hope this post was helpful. If you have further questions send me a tweet http://twitter.com/ad0815 or shout out to the community via the #omniture hashtag.

Happy coding,
Andreas

Comments (0)

Must be logged in to comment. or register now to comment!