News Archive
PhpRiot Newsletter
Your Email Address:

More information

How to Create Your Own Twitter Widget in PHP, Part 3

Note: This article was originally published at Planet PHP on 7 January 2011.
Planet PHP

In part 1 of this series, we examined the Twitter API, created a PHP TwitterStatus class, and imported the latest tweets in JSON format. In Part 2, we parsed the Twitter data, replaced links, and generated the complete html for our widget. In this last post, we'll cache our widget and translate tweet dates into a friendlier format - download the full source code here.

The case for caching

Currently, our TwitterStatus class will fetch the most recent tweets every time we call the Render() method. Retrieving and parsing that data takes several seconds and incurs a significant processing overhead. It's simply not necessary: we could receive 10 visitors per second to our website, yet only post a single tweet every month. In addition, Twitter will prevent applications making too many unnecessary calls to the API.

Therefore, we'll cache our resulting html code in a file on the local system. If the age of that file is less than $CacheFor seconds (a public property), it will be retrieved and used rather than interrogating the Twitter API.

Our Render() method will therefore generate a filename in the local $cache string. It's set to $this-cache (the directory where data is cached), followed by the Twitter ID, a dash, the number of tweets, and a .html extension, e.g. a/twitter/cache/sitepointdotcom-10.html':

public function Render() { // returned html string $render = ''; // cached file available? $cache = $this-cache . $this-ID . '-' . $this-Count . '.html';

We can then calculate the number of seconds which have expired since the file was created (assuming it exists):

$cacheage = (file_exists($cache) ? time() - filemtime($cache) : -1);

If the cache file doesn't exist or the number of seconds is greater than $CacheFor, we need to re-generate the html widget cache file using the code we wrote in part 2:

if ($cacheage $this-CacheFor) {

If the html is correctly generated in our $render string, we can save it to our cache file:

// update cache file file_put_contents($cache, $render); important: File permissions

File permissions are the most likely and frustrating problem you'll encounter with this code. Your web server and/or PHP must have permission to read, write and modify files within the cache directory. On Linux and Mac systems, chmod 755 may be enough a but not always. On Windows, it's usually a matter of granting appropriate folder permissions to the IIS user account.

In the code I've supplied, a caching failure will simply re-fetch the data from Twitter. That's not always desirable in a production environment - it may be preferable to raise an error.

The $render string will be empty if a valid cache file exists. It will also be empty if the Twitter API call fails: in that situation, we'll retrieve the last available cached file:

// fetch from cache if ($render == '' && $cacheage 0) { $render = file_get_contents($cache); }

To complete our Render() method, we return $render to the calling code. However, we must parse the dates firsta

return $this-ParseDates($render);

Date parsing

In part 2, you will have noticed that tweet creation dates are rendered as ao{DATE:Thu Dec 23 10:00:00 +0000 2010}a. So why didn't we convert these to nicely-formatted dates when the html was generated?

Had we simply wanted to display the tweet's date and time, we could have parsed it during the caching phase to result in something like ao10:10am on 23 December 2010a. However, we can optionally show relative date strings such as aojust nowa, ao10 minutes agoa, aoyesterdaya, aolast weeka or ao3 months agoa. If these were generated at the caching stage, they could be incorrect within a few minutes.

For example, if a tweet was shown as ao2 minutes agoa, that text would remain static for the lifetime of the cache file. If we're caching for 15 minutes and re-visited the page 5 minutes later, it would still show ao2 minutes agoa rather than ao7 minutes agoa

Truncated by Planet PHP, read more at the original (another 4954 bytes)