PHP Tutorial: Fetch and Display Tweets

September 8, 2010

CODE, FEATURED

This is hopefully the first in a few posts that will describe and explain a quick and easy method to get something up and running using PHP. This tutorial will talk through a class I wrote extremely quickly that can pull tweets using Twitter’s REST API from both protected and public accounts, and that will cache the fetched tweets for a specific period. These tweets can then be read and used on any webpage, to display however you like.

This QuickTwitter class is going to download our latest tweets from Twitter, cache the tweets locally, and then display them on our site. This will be done using three methods in our class: fetchTweets(), readCache() and writeCache(). The readCache() and writeCache() methods will both be private, as they only need to be called by the fetchTweets() method, not individually. The first step in building our class is to set up our initial class definition, along with some quick variables the class will use, and the basic method structure:

<?php
class QuickTwitter {
	private $cacheFolder = './cache/';
	private $cacheExpiration = 3600;
	private $maxTweets = 10;
	private $twitterUrl = 'http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=';

	public function fetchTweets($username, $password = null) {}
	private function readCache($username) {}
	private function writeCache($username $tweets) {}
}

There are four variables in the initial definition. $cacheFolder tells the script where it can store the downloaded tweets, and is currently set to a subfolder called cache. If you want to keep the cached files in the same folder the script file is in, change this value to ./. The cache folder itself must have write permissions, or the script will not be able to store the cache files. The $cacheExpiration variable stores how long the cache will remain valid for before the script needs to re-download more tweets. It is currently set to 1 hour (3600 seconds), but feel free to adjust this to your particular needs, depending on your number of visitors and how many times a day you tend to tweet! The $maxTweets variable stores how many tweets the script will display, and should normally be left alone because Twitter only makes available the latest tweets in it’s API by standard anyway. The final variable $twitterUrl is the beginning of the URL used to connect to Twitter, and should normally be OK as well.

Now that the initial class definition has been written, lets write the main method of the class, fetchTweets(). This will connect to Twitter, using the given username and password, if needed, and will pass the downloaded tweets to the writeCache() method to store them. Once the script has finished, it will return the downloaded tweets as an array of associative arrays. Here is the code for the fetchTweets() method:

public function fetchTweets($username, $password = null) {
    if(empty($username)) 'Error: You have not provided your Twitter username.';
    if(is_file($this->cacheFolder . $username . '.xml') &&
        time() - filemtime($this->cacheFolder . $username . '.xml') <= $this->cacheExpiration) {
        return $this->readCache($username);
    }
    if(!is_null($password)) {
        $stream = stream_context_create(array(
            'http'  =>  array('header' => 'Authorization: Basic' . base64_encode($username . ':' . $password))
        ));
        $tweets = file_get_contents($this->twitterUrl . $username, false, $context);
    } else {
        $tweets = file_get_contents($this->twitterUrl . $username, false);
    }
    if($http_response_header[0] == 'HTTP/1.1 200 OK') {
        $cacheError = $this->writeCache($username, $tweets);
        if(empty($cacheError)) {
            return $this->readCache($username);
        } else {
            return $cacheError;
        }
    } elseif($http_response_header[0] == 'HTTP/1.1 401 Unauthorized') {
        return 'Error: Your Twitter password is invalid or missing for accessing a protected account.';
    } elseif($http_response_header[0] == 'HTTP/1.1 404 Not Found') {
        return 'Error: The Twitter username provided could not be found.';
    } else {
        return 'Error: Twitter is not available at this time.';
    }
}

Now this method is quite long, since it’s doing an awful lot, so we’ll go through it carefully. Firstly, the method takes two variables, $username, which is required, and $password which is optional. The $password variable only needs to be passed if the Twitter account you are fetching tweets from is protected, otherwise do not bother passing this. I will explain this more later. The $username is required, and the first line of the method returns a descriptive error if the username is not passed.

After checking the username, the method then checks the cache. The if statement may look complex, but it is essentially doing two things, checking if the cache file for this username is present in the cache folder, and checking if the modification time of the file is within its expiry limit. If these two conditions are met, the method reads straight from the cache using the readCache() method and returns the cached tweets immediately. If either of these conditions fail, the method continues.

Next, the method connects to Twitter and downloads the tweets. This is done in one of two ways. If the method was given a password in the $password variable, the connection to Twitter is made using a wrapper for a socket which includes the HTTP headers required to authenticate with the Twitter API, passing the username and password in a string as follows: username:password. If no password was provided, the connection to Twitter is very simple. In both cases, the Twitter URL is built using a concatenation of the private $twitterUrl class variable, together with the username provided and the ‘.xml’ ending.

The connection to Twitter has been made, and any tweets have been fetched, but before writing the data to the cache, the data must first be verified. This is done using the $http_response_header array, which is automatically set when an HTTP connection is made in PHP. The first line of these headers contains the basic HTTP response code, and this is what will be checked using an if statement. One of four outcomes can happen from this statement:

  • The connection was successful, and the tweets were returned fine. The tweets are then sent to the writeCache() method to store them in the local cache. If the cache was successful, the tweets are returned using the readCache() method, otherwise an error message is displayed.
  • Twitter returned that the connection was not authorised. This means that either the Twitter account is protected and no password was provided, or that the password provided was incorrect.
  • Twitter returns that the username was not found.
  • If none of the other conditions are satisfied, it is assumed that Twitter itself is down or offline, which seems to be a frequent occurrence at times these days…

This is the end of the first method! Now we have to write the methods that were referred to in this method that read and write the cache.

Firstly, we will concentrate on the readCache() method, which is shown below:

private function readCache($username) {
    $xml = simplexml_load_file($this->cacheFolder . $username . '.xml');
    if(is_object($xml)) {
        $tweets = array();
        foreach($xml->status as $status) {
            $tweets[] = array(
                'created'   =>  (string) $status->created_at,
                'text'      =>  (string) $status->text
            );
        }
        return array_slice($tweets, 0, $this->maxTweets);
    } else {
        return 'Error: Cache is corrupted or has been modified and is no longer valid.';
    }
}

The method is given the username to read from, and attempts to load the file into an object using PHP’s SimpleXML implementation. The returned value of the function must be an object, otherwise the file is corrupted or does not exist, and so this is established first using a simple check on the returned value. Next, an array is initialised for the tweets to be stored in, and the method iterates through each status stored in the cache. Each tweet will contain the time the tweet was created, and the text of the tweet itself. These are returned as XML objects, so they must be cast back into string values. The array_slice() function uses the class variable $maxTweets to make sure that only that number of tweets can be returned. And that’s it! Reading the cache is very simple, and now all we need to do is write the cache when the tweets are downloaded.

The writeCache() method contains the following code:

private function writeCache($username, $tweets) {
    if(is_dir($this->cacheFolder)) {
        if(is_writable($this->cacheFolder)) {
            if(!file_put_contents($this->cacheFolder . $username . '.xml', $tweets)) {
                return 'Error: The file could not be stored.';
            } else {
                return '';
            }
        } else {
            return 'Error: The cache folder is not writable.';
        }
    } else {
        return 'Error: The cache folder does not exist.';
    }
}

Before the cache can be stored, a couple of conditions have to be met. Firstly, the cache folder which is set as a class variable MUST be a directory itself, and that directory MUST be writable, otherwise the cache cannot be stored. If the writable error occurs, you may need to set some permissions on the folder. Once these conditions have been met, the method attempts to store the tweets in the cached folder. This statement is cleverly contained inside an if condition, because the function would return false if the storage failed. If no errors have happened, the method returns an empty string, otherwise it returns whatever error stopped the cache from storing.

This is it! Our Twitter class is now complete, and we can use it to fetch some tweets from our account onto a webpage! This is the easy step, and involves using an include() statement and creating an object of the Twitter class to use:

include('QuickTwitter.class.php');
$twitter = new QuickTwitter();
$myTweets = $twitter->fetchTweets('zenithus');

The above three lines of code will give you some tweets in the $myTweets variable, obviously remove my Twitter username and replace it with your own, and pass the method a password too if your account is protected. To quickly show the fetched tweets on your website, and display any errors if needed, write some code similar to the following:

if(is_array($myTweets)) {
    echo '
<ul id="tweets">';
    foreach($myTweets as $tweet) {
        echo '
	<li>'
        . date('jS M Y (H:i)', strtotime($tweet['created']))
        . ' - ' . $tweet['text'] . '</li>
';
    }
    echo '</ul>
';
} else echo '

' . $myTweets . '

';

This will display your tweets in a simple HTML unordered list, which you can then style using CSS, but this can be changed to whatever you need for your site. You can also change the format of the date displayed using PHP’s date() formatting characters.

If you have any comments or questions, please either email me or leave a comment on the post, thanks!

,

One Response to “PHP Tutorial: Fetch and Display Tweets”

  1. Vicky Says:

    Dear Friend ,
    First of all thanx for ur code ,
    will u plz tell me how can i fetch tweets with profile images and links for reply and view full tweet.

    for exapmple i wanna make page like.–

    http://www.cbsnews.com/2718-500164_162-488.html?tag=cbsnewsSidebarArea.1

    Reply

Leave a Reply