Weiter zu Netlog

noch Sekunden

Developer / Documentation / OpenSocial tutorial part 4

The OpenSocial PHP client library

This is part 4 of our OpenSocial tutorial. Here's what the previous parts were about:

  • part 1 - building an openSocial gadget within Netlog (OpenSocial JS API).
  • part 2 - applications hosted on external sites using OpenSocial REST
  • part 3 - an example application with source code illustrating some techniques from part 1 and 2.

We will now do OpenSocial REST again, but this time using the OpenSocial PHP client library. It is open source library in PHP, you can study and download it on the Google code page. !Warning - the library version downloadable from the official site will fail to do POST requests to Netlog (see below).

This library does exactly the same type of REST requests to the container (Netlog) as the ones we constructed ourselves in part 2. However, the library provides a nice OO framework to construct these calls, and is meant to work accross different social networks. Most important though is what it does for authentication. The openSocial PHP library handles all the token exchanging/signing/authenticating that comes with working with OAuth.

Just as in part 2, let us write a simple class in PHP that authenticates with Netlog in the constructor, and has methods for our usual calls: fetching viewer info, fetching viewer friends, fetching viewer photos, posting an activity about the viewer, and posting notifications.

Note that, since OAuth is in fact meant to communicate with Netlog from an external site, the 'owner / viewer' concept does not make sense. We are always talking to the application itself, not the app installed by some specific user whose profile we are visiting.

Intermezzo: Authenticating with OAuth

The end goal of authenticating with OAuth is obtaining an access token key + secret (let's call such a key/secret pair just 'tokens' from hereon), with which you can sign your openSocial calls to Netlog - and get a better response than '403 not authorised'. By the way, OAuth was created as a generic method for authenticating between web sites, and openSocial is but one of its uses.

Authenticating with 3-legged OAuth happens typically from an entirely external site, which means Netlog does not trust you until you got a consumer key + secret from us, and the user gave explicit permission to use his data. So everything starts with those 'consumer' key and secret Netlog gave you beforehand. Given these, the steps to obtain your precious access tokens (all done by the openSocial PHP library) are:

  • Do a http request to Netlog signed with your consumer tokens to which Netlog can send you request tokens in return.
  • Redirect the user to Netlog, passing along your newly obtained request token + secret, and the callback Url where the user will be sent to after approving.
  • The user signs in (if he didn't yet) on Netlog, grants your app/site permission to use his data, and gets redirected back to your website. You detect 'this is a user coming back after authorisation'. The opensocial php library does this by putting ?oauth_contue=1 in the callback url.
  • You now know the user authorised you (if he did), and you do another call to Netlog with the request tokens and also your consumer tokens (so Netlog knows who you are). Netlog remembers a user just came by to grant the app (and thus the request tokens that came along with the user) access, so in response to the request tokens it happily sends access tokens in return.
  • Your app now has the coveted access tokens and can start doing openSocial calls to Netlog to work with the user's social data!

The 2-legged OAuth case is less cumbersome, and does not require the access token and key (but it does need the consumer credentials!). This is because Netlog already 'trusts' your app, meaning that we do not have to send the user around to give it permission. Of course, this implies that your app already needs to 'know' the user somehow - at least his user id that is. It is typically used in a 'phone home' situation: a gadget embedded within Netlog does requests (makeRequest) to a remote server, which in turn wants to work with social information.

Furthermore, 2-legged OAuth has the advantage that, once the user is known to the application (by interacting with it within Netlog), the app can then use his id to send 'offline' messages.

In our code we will use the OpenSocial PHP client library to authenticate (using 2-legged OAuth) and to do the desired calls to Netlog.

Setting it up

Download the opensocial PHP library

You can find the official site of the opensocialPHP library here, including the library to download. However, we made a slightly modified version which has important changes (including stuff that simply will not work when using the official version on Netlog).

The library uses storage for debug logs and, when using 3-legged OAuth, to maintain a 'session' per user during the authentication. This storage happens trough any of a number of objects in the folder /src/storage, each of which implements a different way to store key-value pairs. We added a class mysqlstorage.php.

  • A new storage object, called osapiMySQLStorage.php. This assumes that you have a MySQL database with a table called my_social_table.
  • An extra method in the osapiNetlogProvider.php file, needed for signing POST requests! If you wonder why fetching stuff works but posting it doesn't, it's likely because of this. Show me that code

The entire openSocial PHP library that has the above changes can be downloaded here. This ZIP contains the class.osapirest.php file which should make working with the library a bit easier (it has functions like 'getViewerFriends()').

Obtain OAuth token secret and token key

These you should receive (or have received) from Netlog. In the code (or when working with class.osapirest.php), use them to instantiate the OsapiNetlogProvider class.

Authenticating with 2-legged OAuth

The typical use cases for 2-legged and 3-legged OAuth are described on The openSocial wiki.

The general mechanism

Firs a bit about the general mechanism. Requests with the opensocial php library happen by creating, add into and sending a 'batch', a mechanism quite similar to that used with the OpenSocial JS API (only there they are called 'requests'). So here are the basic steps:

  • Create a new osapiBatch object using something like
    $batch = $osapi->newBatch();
  • Add specific requests to the batch, including additional parameters, and a key string to identify each chunk of data within the response, e.g.:
     $profile_fields = array(
     'aboutMe',
     'displayName',
     'thumbnailUrl',
     );
     $self_request_params = array(
     'userId' => $this->userId, 
     'groupId' => '@self', 
     'fields' => $profile_fields 
     );
     $batch->add($osapi->people->get($self_request_params), 'self');
     
  • Send the request and store the response in a variable:
    $response = $batch->execute();
  • Parse the result. It will typically contain a mix of OsapiSomething objects and arrays, so you may want to turn those objects into arrays too, using something like:
     $result = get_object_vars($response['self']);
     

In our helper class, the things that need to be done for each openSocial call in the constructor. As you see, we need to create a different authentication object depending on whether we use 2-legged or 3-legged OAuth.

//token key and secret should be provided by Netlog
//friends will only be fatched from the same Netlog language version!
function __construct($tokenkey, $tokensecret, $numberOfLegs = 2, $language = 'nl', $userId = false)
{
 $this->showDebug = true; //echo debugs within this class
 osapiLogger::setEchoLogs(true); //echo logs from php client (handy for seeing detailed requests + responses)
 $this->tokenkey = $tokenkey;
 $this->tokensecret = $tokensecret;
 date_default_timezone_set('Europe/London'); // Set the default timezone since many servers won't have this configured (NOTE: where is this needed?)
 ini_set('error_reporting', E_ALL | E_STRICT); // Report everything, better to have stuff break here than in production
 set_include_path(get_include_path() . PATH_SEPARATOR . '..'); // Add the osapi directory to the include path
 // Enable logger. (careful: in my opensocial-php-netlog-1 library logging is replaced by echo's)
 osapiLogger::setLevel(osapiLogger::INFO);
 osapiLogger::setAppender(new osapiFileAppender("/tmp/logs/osapi.log"));
 $this->storage = new osapiFileStorage('/tmp/osapi'); //for logging and/or 3-legged session
 $osapi = false;
 $strictMode = false;
 $this->userId = '@me'; //$userId ? $userId : '@me';
 $this->appId = '@app'; //'@app';
 // Create an identifier for the local user's session
 session_start();
 $localUserId = 007;
 $useStaging = 0;
 $apiBaseUrl = $useStaging ? 'http://woutersmet4.staging.comcore.be' : 'http://' . $language . '.api.netlog.com';
 if ($numberOfLegs == 2)
 {
 $this->provider = new osapiNetlogProvider(null, $apiBaseUrl); 
 $this->provider->rpcEndpoint = null; //to use REST endpoint instead of rpc endpoint (which is default)
 $this->osapi = new osapi($this->provider, new osapiOAuth2Legged($this->tokenkey, $this->tokensecret));
 }
 else //3-legged case would be: 
 { 
 $this->auth = osapiOAuth3Legged::performOAuthLogin($this->tokenkey, $this->tokensecret, $this->storage, $this->provider, $this->localUserId);
 $osapi = new osapi($this->provider, $this->auth);
 }
 $this->viewer = $this->getViewer();
 $this->debug("Init osapi object - Userid ".$this->userId." - App ID " . $this->appId);
 $this->debug("Viewer: ".$this->viewer['nickname']); 
}

For easy debugging, our class has a debug() method which simply echos things to the browser based on a property 'showDebug' of our class:

function debug($string)
{
 if ($this->showDebug)
 {
 echo '<div style="color:#333;background-color:white;">'.$string . '<br /></div>';
 }
}

Fetching viewer friends

function getViewerFriends($count = 10, $startIndex=0) //inspired by /examples/listfriends.php
{
 $this->debug("getting $count viewer friends starting from index $startIndex...");
 $friend_count = $count;
 // Start a batch so that many requests may be made at once.
 $batch = $this->osapi->newBatch();
 $profile_fields = array(
 'aboutMe',
 'displayName',
 'thumbnailUrl',
 'gender',
 'networkPresence', //currently online?
 'connected'
 );
 $friends_request_params = array(
 'userId' => $this->userId, // Person whose friends we are fetching. (can be @me or a userid integer)
 'groupId' => '@friends', // @friends for the Friends group.
 'fields' => $profile_fields, // Which profile fields to request.
 'count' => $friend_count, // Max friends to fetch.
 'startIndex' =>$startIndex
 );
 $batch->add($this->osapi->people->get($friends_request_params), 'friends');
 $response = $batch->execute();
 $this->debug("Response:<br /><pre>" . print_r($response,true) . "</pre>");
 $result = $response['friends']->list;
 foreach ($result as &$friend)
 {
 $friend = get_object_vars($friend); //convert osapiPersonObjects to arrays 
 }
 $this->debug("Friends result:<pre>" . print_r($result,true) . "</pre>");
 return $result;
}

Posting an activity about the viewer

For now, please refer to the examples in the src/examples directory in the openSocial library files.

Sending a notification

For now, please refer to the examples in the src/examples directory in the openSocial library files. Remember that notifications are a type of 'messages' from the OS point of view.

Fetching viewer photos

For now, please refer to the examples in the src/examples directory in the openSocial library files. Remember that photos are a type of 'mediaItems' from the OS point of view.

Uploading photos / setting profile photo

For now, please refer to the examples in the src/examples direct

For now, please refer to the examples in the src/examples directory in the openSocial library files. Remember that photos are a type of 'mediaItems' from the OS point of view.