Using the Digg API with PHP and PEAR

November 2, 2010

Tutorials

No News Is Good News

A few weeks ago, a client asked me to add a feed of interesting news stories to his Web application. Naturally, my thoughts turned immediately to Digg, which invariably has something interesting to read and which also offers a Web service API that makes possible to develop customized applications on top of the base service. This API, currently in its second incarnation, allows access to a number of important Digg functions, including searching and commenting on stories.

A little Googling, and I found the PEAR Services_Digg2 class, which exposes a neat little PHP interface to the Digg API. As you might imagine, with all these tools to hand, it didn’t take long to quickly integrate a feed of Digg stories into the application. Not content to leave it at that, I experimented a little more with the API and PEAR package; keep reading and let me tell you all about it.

Getting Started

Before diving into the code, a few notes and assumptions. I’ll assume throughout this article that you’re familiar with HTML, SQL and XML, and that you have a working Apache/PHP/MySQL development environment. I’ll also assume that you know the basics of working with classes and objects in PHP, as the PEAR components used in this article are written in compliance with OOP principles.

In order to get started using PHP and the Digg API, there are a couple of things you’ll need:

  • First, you need the Services_Digg2 package, which you can freely download from the PEAR Web site. This package is currently maintained by the Digg development team, and can be installed using the PEAR installer, as shown below:
shell> pear install Services_Digg2
  • Second, you need the HTTP_OAuth package, also available from PEAR. This package works with Services_Digg to handle OAuth authentication for the Digg API. You can install it using the PEAR installer, as shown below:
shell> pear install HTTP_OAuth
  • Third, you need to keep a copy of the Digg API documentation easily accessible. This documentation is your roadmap to working with the Digg API – it contains detailed information on available API calls, input parameters, error codes and return values, together with information on how to integrate and use the Digg API with different programming languages. You’ll be referring to it frequently throughout this tutorial.

All set up? Let’s go digg-ing.

API Ahoy!

Digg’s API can be accessed using standard HTTP methods. When using GET, the method name and arguments are encoded into the request URL and the method response is returned as a JSON document. Here’s an example of one such API request:

GET http://services.digg.com/2.0/story.getTopNews?limit=5

Every GET request must include the method name (story.getTopNews in this case), with additional arguments appended to the request as additional GET parameters if needed.

Here’s an example of the response packet returned by the Digg API for the request above:

It’s worth noting that some parts of the Digg API also require the user to be authenticated with a separate OAuth authentication token. This is discussed in detail further along in this article.

Top Gear

Now that you know the basics of the Digg API, let’s look at it in the context of a PHP application. Consider the following script, which uses Services_Digg2 to parse the JSON packet returned by the story.getTopNews method (as shown in the previous page) and convert it to a set of stdClass objects, which can then be processed and displayed in a Web page:

<?php
// include package
require_once 'Services/Digg2.php';

try { 
  // initialize service object
  $service = new Services_Digg2;
  $service->setVersion('2.0');
  
  // get all stories
  // via the story.getTopNews API method
  $result = $service->story->getTopNews();
} catch (Exception $e) {
  die ('ERROR: ' . $e->getMessage());  
}
?>
<html>
  <head></head>
  <body>
    <h2>Recent stories</h2>
    <ul>
    <?php foreach ($result->stories as $s): ?>
      <li>
        <a href="<?php echo $s->permalink; ?>"><?php echo $s->title; ?></a> <br/>
        <?php echo $s->description; ?> <br/>
        <span style="font-size: smaller"><?php echo date('d M Y h:i', $s->date_created); ?> | <?php echo $s->diggs; ?> diggs | <?php echo $s->comments; ?> comments</span> <br/>
      </li>
    <?php endforeach; ?>
    </ul>
  </body>
</html>

This script begins by initializing a Services_Digg2 object and setting the version of the Digg API to use (the package works for both v1.0 and v2.0 of the Digg API). It then invokes the $obj->story->getTopNews() method; this is internally converted into the story.getTopNews API call via the __get() and __call() magic methods. The Services_Digg2 class then constructs the complete URL and sends a GET request for the URL via the HTTP_Request2 client. The JSON response to the request is converted into a set of stdClass objects, which looks like this:

Individual elements of the response can now be accessed as object properties. This is illustrated in the previous example, which uses $object->property notation to navigate through the response and extract specific pieces of information for display.

Here’s what the output might look like:

Searching for Godot

A common use case involves searching for news items matching a specific keyword. This is addressed by the search.search method, which returns a list of stories matching search criteria. Here’s an example, which illustrates by allowing the user to enter search terms into a form and returning Digg stories matching those terms:

<?php
// include package
require_once 'Services/Digg2.php';
?>
<html>
  <head></head>
  <body>
    <?php if (!isset($_POST['submit'])): ?>
    <h2>Search</h2>
    <form action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>" method="post">
    Search for: <input type="text" name="q" />
    <input type="submit" name="submit" />
    </form>    
    <?php else: ?>
    <?php
    // validate and sanitize this properly    
    $q = htmlentities($_POST['q']);
    
    try { 
      // initialize service object
      $service = new Services_Digg2;
      $service->setVersion('2.0');
          
      // search for stories
      // via the search.search API method
      $options = array(
        'query' => $q,
      );
      $result = $service->search->search($options);
    } catch (Exception $e) {
      die ('ERROR: ' . $e->getMessage());  
    }
    ?>    
    <h2>Search results for '<?php echo $q; ?>'</h2>
    <ul>
    <?php foreach ($result->stories as $s): ?>
      <li>
        <a href="<?php echo $s->href; ?>"><?php echo $s->title; ?></a> <br/>
        <?php echo $s->description; ?> <br/>
        <span style="font-size: smaller"><?php echo date('d M Y h:i', $s->submit_date); ?> | <?php echo $s->diggs; ?> diggs | <?php echo $s->comments; ?> comments</span> <br/>
      </li>
    <?php endforeach; ?>
    </ul>
    <?php endif; ?>
  </body>
</html>

As in the previous example, the Services_Digg2 object converts the $obj->search->search() method call into the search.search API method, passing it the query terms. The return value is a set of Digg stories, represented as an array of stdClass objects, which can be iterated over and displayed. Here’s what it looks like:

Note that the search.search method also takes additional parameters, to allow sorting, date range filtering, pagination and domain-specific searches. Look in the API documentation for more details.

No Comment

Each story in the Digg universe has a unique story ID, and the API includes a number of methods to get specific details of a particular story. The main method you should know about here is the story.getInfo method, which accepts an array of story IDs, and returns information on each. Here’s an example of it in action:

<?php
// include package
require_once 'Services/Digg2.php';

try { 
  // initialize service object
  $service = new Services_Digg2;
  $service->setVersion('2.0');
  
  // get information on specific story
  // via the story.getInfo API method
  $result = $service->story->getInfo(array(
      'story_ids' => 'SOME-STORY-ID'
  ));
  print_r($result);

} catch (Exception $e) {
  die ('ERROR: ' . $e->getMessage());  
}
?>

If you don’t have a story ID, you can also use story.getInfo to return information on stories by title, or on stories linked by a common URL. The story information returned by story.getInfo contains the story title, permalink, images, number of diggs and comments, and details of the original poster. Here’s what the output looks like:

It’s quite easy to format this information into a readable page, especially if you add in the comments posted on the story through the story.getComments method. Here’s a script which does this:

<?php
// include package
require_once 'Services/Digg2.php';

try { 
  // initialize service object
  $service = new Services_Digg2;
  $service->setVersion('2.0');
  
  // get information on specific story
  // via the story.getInfo API method
  $result = $service->story->getInfo(array(
      'story_ids' => 'SOME-STORY-ID'
  ));

  // get comments on specific story
  // via the story.getComments API method
  $result2 = $service->story->getComments(array(
      'story_id' => 'SOME-STORY-ID',
  ));
  
} catch (Exception $e) {
  die ('ERROR: ' . $e->getMessage());  
}
?>
<html>
  <head></head>
  <body>
    <h2>Story information</h2>
    <ul>
    <?php foreach ($result->stories as $s): ?>
      <li>
        <a href="<?php echo $s->permalink; ?>"><?php echo $s->title; ?></a> <br/>
        <?php echo $s->description; ?> <br/> 
        <span style="font-size: smaller"><?php echo date('d M Y h:i', $s->date_created); ?> | <?php echo $s->diggs; ?> diggs | <?php echo $s->comments; ?> comments</span> <br/>
        <br />
        <div style="margin-left: 30px">        
        Comments: <br />
        <?php foreach ($result2->comments as $c): ?>
        <?php echo $c->user->username . ' says: ' . $c->text; ?> <br/>
        <span style="font-size: smaller">
        <?php echo date('d M Y h:i', $c->date_created); ?> | <?php echo $c->diggs; ?> diggs <br/><br/>
        </span>
        <?php endforeach; ?>
        </div>
      </li>
    <?php endforeach; ?>
    </ul>
  </body>
</html>

This script retrieves both story and comment information via two separate API calls, and combines the information into a single page. Here’s what the output looks like:

Getting Fresh

You can also obtain a list of recent reader comments across Digg.com stories, via the comment.getRecent method. The return value of this method contains a list of recent comments, together with information on the commenting user and the story being commented on. Here’s an example of how you can use this:

<?php
// include package
require_once 'Services/Digg2.php';

try { 
  // initialize service object
  $service = new Services_Digg2;
  $service->setVersion('2.0');
  
  // get recent comments
  // via the comment.getRecent API method
  $result = $service->comment->getRecent();
} catch (Exception $e) {
  die ('ERROR: ' . $e->getMessage());  
}
?>
<html>
  <head></head>
  <body>
    <h2>Recent comments</h2>
    <ul>
      <?php foreach ($result->comments as $c): ?>
      <?php echo $c->text; ?> <br/>
      <span style="font-size: smaller">
      By <?php echo $c->user->name; ?> on <a href="<?php echo $c->item->shorturl->short_url; ?>"><?php echo $c->item->title; ?></a> | <?php echo date('d M Y h:i', $c->date_created); ?> <br/><br/>
      </span>
      <?php endforeach; ?>
    </ul>
  </body>
</html>

And here’s an example of what the result might look like:

As you may know, Digg.com categorizes stories into topics, making it possible for users to view only stories about, say, technology or gaming. The topic name can be used as a filter in the comment.getRecent method, allowing you to display recent comments only about particular topics. To do this, add the topic name as an option to the comment.getRecent API method call.

Access Granted

Speaking of comments, the Digg API also lets you programmatically post comments on a story, via the comment.post method. This API method requires OAuth authentication and so, before you can use it, you need to fully understand how OAuth works, and how to use it with the Digg API. You’ll also need to create an application that Digg knows about, so that you can get an access key and secret for OAuth requests.

To create an application, visit the Digg Developer Center and use the “My Apps” link to create a new application. You’ll need to enter a title for your application, and Digg will provide you with an API access key and secret for the application. Store these carefully, because you’ll need them for your OAuth requests. Then, create a script to connect to Digg, get an OAuth request token and access token, and call the comment.post method, as shown below:

<?php
// include required classes
require_once 'HTTP/OAuth/Consumer.php';
require_once 'Services/Digg2.php';

// set access and secret keys
$apiKey = 'API-KEY';
$secretKey = 'SECRET-KEY';

// start session
session_start();

// check if OAuth verifier exists in URL
// if not, get request token
// if exists, get and store access token
try {
  if (!isset($_GET['oauth_verifier'])) {
    $consumer = new HTTP_OAuth_Consumer($apiKey, $secretKey);
    $consumer->getRequestToken('http://services.digg.com/oauth/request_token', 'http://myhost/callback.php');
    $_SESSION['token']        = $consumer->getToken();
    $_SESSION['token_secret'] = $consumer->getTokenSecret();
    $url = $consumer->getAuthorizeUrl('http://digg.com/oauth/authorize');
    header('Location: '. $url); 
  } else {
    $consumer = new HTTP_OAuth_Consumer($apiKey, $secretKey, $_SESSION['token'], $_SESSION['token_secret']);
    $consumer->getAccessToken('http://services.digg.com/oauth/access_token', $_GET['oauth_verifier']);
    $_SESSION['token']        = $consumer->getToken();
    $_SESSION['token_secret'] = $consumer->getTokenSecret();
      
    // now proceed with authenticated API request
    $consumer = new HTTP_OAuth_Consumer($apiKey, $secretKey, $_SESSION['token'], $_SESSION['token_secret']);
    
    // initialize service object
    $service = new Services_Digg2;
    $service->setVersion('2.0');
    
    // connect service object to OAuth consumer object
    $service->accept($consumer);
   
    // add comment to story
    // via the comment.post method
    $result = $service->comment->post(array(
      'story_id' => 'SOME-STORY-ID',
      'comment_text' => 'Testing via API, please ignore',
    ));    
    echo 'Comment successfully added with id: ' . $result->comment->comment_id;
  }
} catch (Exception $e) {
  echo 'ERROR: ' . $e->getMessage();
  var_dump($consumer->getLastResponse()); 
  exit();
}
?>

This script uses the HTTP_OAuth package to create and send the various OAuth requests. It begins by first creating and sending a signed request for an OAuth request token to Digg, and then redirecting the user to Digg’s authorize URL to verify the application requesting access. Once the application is authorized by the user, the script gets an OAuth access token and secret and uses these to create an authenticated request for the comment.post method. Note the accept() method of the Services_Digg2 object, which is used to connect the API service object with the authenticated OAuth request.

The comment.post method is passed the story ID and comment text, which is then posted to the corresponding Digg story. The result value of the comment.post method includes the complete comment body, together with the unique comment ID.

Just as you can post comments, so too can you bury them…although you’ll need the comment ID to do so. Consider the following script, which uses the comment.bury method to bury a comment:

<?php
// include required classes
require_once 'HTTP/OAuth/Consumer.php';
require_once 'Services/Digg2.php';

// set access and secret keys
$apiKey = 'API-KEY';
$secretKey = 'SECRET-KEY';

// start session
session_start();

// check if OAuth verifier exists in URL
// if not, get request token
// if exists, get and store access token
try {
  if (!isset($_GET['oauth_verifier'])) {

    // get request token here
    // code snipped
 
  } else {

    // get access token here
    // code snipped

    // now proceed with authenticated API request
    $consumer = new HTTP_OAuth_Consumer($apiKey, $secretKey, $_SESSION['token'], $_SESSION['token_secret']);
    
    // initialize service object
    $service = new Services_Digg2;
    $service->setVersion('2.0');
    
    // connect service object to OAuth consumer object
    $service->accept($consumer);
   
    // bury comment 
    // via the comment.bury method
    $result = $service->comment->bury(array(
      'comment_id' => 'COMMENT-ID',
    ));    
    echo 'Comment successfully buried.';
  }
} catch (Exception $e) {
  echo 'ERROR: ' . $e->getMessage();
  var_dump($consumer->getLastResponse()); 
  exit();
}
?>

Note that the OAuth conversation is snipped out of this and subsequent scripts to make them easier to read. And here is another example of OAuth authentication with Digg.

Story Collection

The most recent iteration of Digg.com features the ability for users to save stories of interest to their account. This feature is replicated in the Digg API via the user.saveStory and user.getSavedStories methods. Here’s an example, which demonstrates how to save stories using the Digg API.

<?php
// include required classes
require_once 'HTTP/OAuth/Consumer.php';
require_once 'Services/Digg2.php';

// set access and secret keys
$apiKey = 'API-KEY';
$secretKey = 'SECRET-KEY';

// start session
session_start();

// check if OAuth verifier exists in URL
// if not, get request token
// if exists, get and store access token
try {
  if (!isset($_GET['oauth_verifier'])) {

    // get request token here
    // code snipped

  } else {

    // get access token here
    // code snipped

    // now proceed with authenticated API request
    $consumer = new HTTP_OAuth_Consumer($apiKey, $secretKey, $_SESSION['token'], $_SESSION['token_secret']);
    
    // initialize service object
    $service = new Services_Digg2;
    $service->setVersion('2.0');
    
    // connect service object to OAuth consumer object
    $service->accept($consumer);
   
    // add story to authenticated user's saved stories list
    // via the user.saveStory method
    $result = $service->user->saveStory(
      array('story_id' => 'SOME-STORY-ID')
    );    
    echo 'Story successfully saved.';
  }
} catch (Exception $e) {
  echo 'ERROR: ' . $e->getMessage();
  var_dump($consumer->getLastResponse()); 
  exit();
}
?>

There’s also a user.getSavedStories method, which makes it possible to retrieve the list of saved stories for a user. Here’s an example of the code:

<?php
// include required classes
require_once 'HTTP/OAuth/Consumer.php';
require_once 'Services/Digg2.php';

// set access and secret keys
$apiKey = 'API-KEY';
$secretKey = 'SECRET-KEY';

// start session
session_start();

// check if OAuth verifier exists in URL
// if not, get request token
// if exists, get and store access token
try {
  if (!isset($_GET['oauth_verifier'])) {

    // get request token here
    // code snipped

  } else {

    // get access token here
    // code snipped
      
    // now proceed with authenticated API request
    $consumer = new HTTP_OAuth_Consumer($apiKey, $secretKey, $_SESSION['token'], $_SESSION['token_secret']);
    
    // initialize service object
    $service = new Services_Digg2;
    $service->setVersion('2.0');
    
    // connect service object to OAuth consumer object
    $service->accept($consumer);
   
    // get user's saved stories list
    // via the user.getSavedStories method
    $result = $service->user->getSavedStories();    
  }
} catch (Exception $e) {
  die('ERROR: ' . $e->getMessage());
}
?>
<html>
  <head></head>
  <body>
    <h2>Saved stories</h2>
    <ul>
    <?php foreach ($result->stories as $s): ?>
      <li>
        <a href="<?php echo $s->permalink; ?>"><?php echo $s->title; ?></a> <br/>
        <?php echo $s->description; ?> <br/> 
        <span style="font-size: smaller"><?php echo date('d M Y h:i', $s->date_created); ?> | <?php echo $s->diggs; ?> diggs | <?php echo $s->comments; ?> comments</span> <br/>
      </li>
    <?php endforeach; ?>
    </ul>
  </body>
</html>

And here’s what the script output might look like (a Digg screenshot showing the same information on Digg.com is inset):

To remove a story from a user’s saved story list, there’s also a user.removeStory method, which accepts an array of story IDs to be removed.

Follow The Leader

Digg.com now also includes the ability to follow or unfollow other Digg users, to see what stories they find interesting or noteworthy. You can access this feature via the user.follow and user.unfollow API methods, simply by providing the user’s Digg.com username. Both these methods require OAuth authentication to work. Here’s an example:

<?php
// include required classes
require_once 'HTTP/OAuth/Consumer.php';
require_once 'Services/Digg2.php';

// set access and secret keys
$apiKey = 'API-KEY';
$secretKey = 'SECRET-KEY';

// start session
session_start();

// check if OAuth verifier exists in URL
// if not, get request token
// if exists, get and store access token
try {
  if (!isset($_GET['oauth_verifier'])) {

    // get request token here
    // code snipped
 
  } else {

    // get access token here
    // code snipped
      
    // now proceed with authenticated API request
    $consumer = new HTTP_OAuth_Consumer($apiKey, $secretKey, $_SESSION['token'], $_SESSION['token_secret']);
    
    // initialize service object
    $service = new Services_Digg2;
    $service->setVersion('2.0');
    
    // connect service object to OAuth consumer object
    $service->accept($consumer);
   
    // follow a user
    // via the user.follow method
    $service->user->follow(array('username' => 'user_to_follow'));    
    
    // unfollow another user
    // via the user.unfollow method
    $service->user->unfollow(array('username' => 'user_to_unfollow'));    
    
  }
} catch (Exception $e) {
  var_dump($consumer->getLastResponse()); 
}
?>

As these examples, will have illustrated, the Digg API makes it possible to easily integrate Digg news stories into a PHP application, and also build in sophisticated functions that enable direct interaction with the Digg.com Web site. Try it out the next time you have a hankering to play with a Web service…and have fun!

Copyright Melonfire, 2010. All rights reserved.

One Response to “Using the Digg API with PHP and PEAR”

  1. solarpanel101 Says:

    I’m having difficulties when it comes to codes like JavaScript. But, somehow you’ve just given me tips how to understand them.

    <a href="http://ebpsolarpanel.com//">Homemade Electricity</a>
    <a href="http://ebpsolarpanel.com//">http://ebpsolarpanel.com</a&gt;