Pressure is nothing more than the shadow of great opportunity. - Michael Johnson

Creating a server side del.icio.us badge with PHP

10 years, 4 months ago

Introduction

del.icio.us recently released a JavaScript tagometer badge. For each page you add the badge to it displays the number of times the page has been bookmarked as well as associated tags and provides a direct link for bookmarking. This makes it a really useful for site authors to see at a glance how their pages are performing as well as giving visitors an indication of how popular pages are and perhaps the perceived quality of the information each contains.

As it's implemented in JavaScript it does have one or two accessibility drawbacks as well as being hard to integrate with my page theming system. This prompted me to investigate the feasibility of writing a server side version.

Data Feed

The badge gets its data from a feed which returns JSON formatted data. This feed is documented on del.icio.us here.

It takes one of two arguments, the URL or a MD5 hash of the URL. I used the URL variant as it seemed more fault tolerant:

  • http://badges.del.icio.us/feeds/json/url/data?url=
  • http://badges.del.icio.us/feeds/json/url/data?hash=

The JSON returned has the following format:

  1. [
  2. {
  3. "hash":"f3f0c2f15df3cb73270a8936301a6f86",
  4. "top_tags":{
  5. "css":45,
  6. "blogs":8,
  7. "javascript":23,
  8. "blog":23,
  9. "webdesign":12,
  10. "web":10,
  11. "design":16,
  12. "php":38,
  13. "programming":8,
  14. "html":21,
  15. "development":24
  16. },
  17. "url":"http://www.ejeliot.com/",
  18. "total_posts":68
  19. }
  20. ]

For those unfamiliar with JSON, it's a lightweight data exchange format which works really well as a simplified replacement to XML. It's supported natively by JavaScript but there are many libraries available for other programming languages. Simon has a good explanation of Why JSON isn't just for JavaScript.

PHP has several libraries for both encoding and decoding JSON. A native library is included by default in PHP 5.2 and this should be used wherever possible. Unfortunately my web host uses PHP 5.1.x so I've plumped for a PHP version which works really well (source code), if a touch slower. There's a good comparison of JSON libraries for PHP here.

My Server-Side Badge

My badge is very similar to the tall version of the del.icio.us tagometer badge. Visually, the only real difference is that I've rendered the various tags with font sizes relative to their popularity, just like a normal tag cloud. This was possible because, as you'll see from the sample above, the feed returned from del.icio.us includes additional data, not currently used in the del.icio.us badge, which details the number of times each tag is used. You can view an example here. The badge is also displayed on all pages of my site.

It's made up of three files as well as some additional support libraries:

  1. badge.inc.php - this requests data for the current page and sets up a PHP variable containing the various data components. You can include this in the header of your page or at the position that you want the badge template to appear but in either case you'll need to ensure this proceeds badge-html.inc.php in your source.
  2. badge-html.inc.php - renders the data against an HTML template. It should be located in your source at the position you want the badge to appear.
  3. badge.css - the rules in this file can be added to your main stylesheet or included separately. Either way you'll probably need to modify font, background and border properties to ensure the badge fits with your site styling. If you're using a reset file you may also want to remove the padding and margin resetting rules.

In addition http.inc.php takes care of requesting the data via either CURL or file_get_contents, depending on which is available, and JSON-PHP is used for parsing the returned data. You can optionally include my caching class which, if present, will cache the returned data for a specified time period. If using this you'll need to enter suitable values for the following constants:

  1. define('CACHE_PATH', '/tmp/'); // include trailing slash
  2. define('CACHE_TIME', 3600); // cache for 1 hour by default

Finally you can specify how many tag sizes the badge should display. You'll need to modify your CSS accordingly if you change this constant:

  1. define('NUM_TAG_CLOUD_SIZES', 5);

Including The Badge

An example for including the badge in your pages is shown below:

  1. <?php require('badge.inc.php'); ?>
  2. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
  3. <html lang="en">
  4. <head>
  5. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  6. <title>Server-Side Delicious Badge Example</title>
  7. <link type="text/css" rel="stylesheet" href="badge.css">
  8. </head>
  9. <body>
  10. <div style="width: 230px;"> <!-- sample page container, badge width constrained by container -->
  11. <?php require('badge-html.inc.php'); ?>
  12. </div>
  13. </body>
  14. </html>

Download

You can use the links to the various files above or for convenience I've bundled all files into a ZIP file you can download here. The ZIP excludes the JSON library which you can download here.

Comments

  • Excellent! I was hoping someone would write something like this. :) And, kudos for implementing caching - that means this PHP version is even friendlier to del.icio.us than the original JS include.

    Reading through things, I should note that the url parameter is actually *less* fault tolerant than the hash parameter. With URLs-as-URL-parameters, you need to make sure your encoding is always right. Also, it leads to very long feed URLs when you have multiple URLs to look up. The hash parameter is always the same set of URL-friendly characters and is always the same length.

    On the other hand, it's often easier to throw in an encoded URL than to calculate an MD5. This shouldn't be a concern in PHP, though.

    And, on the other other hand, the url parameter isn't actually documented on that help page - only hash is. That url parameter *might* go away - though there are no immediate plans toward that end.

    l.m.orchard - 30th December 2006 #

  • Les - Thanks for stopping by and providing feedback.

    I'll switch the code to use hashes instead. I'd being debating whether or not to go with URL or hash. Initially I'd chosen URL as I figured del.icio.us could then take care of working out the components of the URL needed to create the right MD5 hash (with/without http://, trailing slashes etc).

    Ed Eliot - 31st December 2006 #

  • Yeah, there's no intelligence whatsoever in del.icio.us mapping URLs to MD5s. We punt on concerns like trailing slashes, index.html, and whatnot.

    It's just a straight hash, used to normalize all the bits of the URL. The code and services behind the feed actually sling MD5s around internally, so the url parameter gets hashed right away anyway.

    l.m.orchard - 9th January 2007 #

  • Les - Thanks for checking back and providing clarification.

    Ed Eliot - 9th January 2007 #

  • Hello,

    I recently moved from MyWeb to Delicious. I would like to build a sort of linkblog based on Delious. However for that I would need the badge to display the notes I write for each bookmakrs. I believe i would have to modify the Javascript and host it myself on my server right?

    Now i dunno which part of the javascript to modify. Do you think you could help me here?

    My Javascript should be here:http://del.icio.us/feeds/js/guillaumeb

    Thanks a lot and keep up the good work

    GuillaumeB - 24th February 2007 #

  • Guillaume - for what you're trying to achieve you'd probably be better to use my PhpDelicious class (a wrapper to the del.icio.us api). It includes a GetRecentPosts() method which would allow you to implement a link blog. Download PhpDelicious.

    The following code would retrieve recent posts from your del.icio.us account:

    <?php
       require('php-delicious.inc.php');
    
       $oPhpDelicious = new PhpDelicious('YOUR_USER', 'YOUR_PASS');
    
       if ($aPosts = $oPhpDelicious->GetRecentPosts()) {
          print_r($aPosts);
       }
    ?>

    Ed Eliot - 24th February 2007 #

  • Ed,

    Amazing tutorial, I really appreciate it.

    One note for you though. In the badge-html.inc.php file you have, there's a syntax error. For the part that says "be the first to bookmark this page!", it closes a but the element is never opened to begin with. You go from

    Jonathan Dingman - 6th November 2007 #

Help make this post better

Notes: Standard BBCode for links, bold, italic and code are supported. rel="nofollow" is added to all links. Your email address will never be displayed on the site.

Back to index