Dynamic Twitter Signature Images with PHP

Twitter is the latest and greatest craze in social networking sites. As such, many developers and businesses are using it as a marketing technique. Today we’re going to come up with a method for creating a dynamic signature image for forum posts and emails that will automatically load your Twitter feed and display your latest Twitter status. We’ll be using PHP to grab the content along with GD2 support to create the image.

I’m going to be presenting the code in this article in an object-oriented fashion using PHP 5.  If you’re not already using object-oriented programming techniques it’s important that you begin doing that.  You will be able to take advantage of more advanced features in PHP while building more robust applications.  In my opinion, it’s one of the subtle differences between a true programmer and a simple scripter.

The first step in creating this project was determining what size to make the final image.  I considered the standard IAB ad unit sizes for banners, but they were either too big or too small for our purposes.  The 60 pixel height on a full banner (also called impact banner) was perfect, but a width of 480 pixels takes up a bit more real estate than I would like for a low profile signature image.  The half banner cuts that width in half, but then doesn’t allow much room for both a user’s avatar and text. 

So I decided to shy away from a standard ad unit and compromise between the two, settling on a width of 380 pixels and a height of 60 pixels.  With this size a user’s avatar fits nicely inside the height and still allows about 300 pixels in width for the addition of text.  With the capacity to house four lines, this fits the Twitter status’ character length specification pretty nicely, as you can see in the live example below.

Once I decided on a unit size for the image, I needed to build a background image that was the proper size.  This is a simple background that will provide a nice- looking backdrop for the image as opposed to having it over a single background color.  You can use Gimp or any other image creation software to create your own, or download the one I created in Photoshop here.

{mospagebreak title=Building the class} 

With all of the basics out of the way, it’s time to dive into some PHP and begin building a class.  We’re going to create a class called TwitterSignature.  This class will load the background and user feed, create the signature image, and then output it to the browser as an image.  This will allow us to simply point the HTML source of an image to this PHP file and have it render in any page, as you’ll see later.

class SignatureImage

{

    private $screen_name;

    private $profile_image;

    private $status_text;

    private $local_avatar;   

    public function __construct($name, $bg_image, $adir)

    {

    }

}

Here’s the basic structure of the entire class.  We first create a few class-level variables that we will use as we start adding functions.  $screen_name, $profile_image, $status_text, and $local_avatar are all strings that will contain the Twitter screen name, URL to the Twitter avatar, the XML status feed, and local avatar directory path, respectively.  I’ll explain each of these in more detail as we go along. 

Notice also that I’m using a constructor for this class.  All of the class’s functions will be called internally through this constructor.  There won’t be any need to call functions when the class is actually implemented.

The constructor accepts three required parameters: the Twitter screen name to process, the location of the background image, and the local directory where avatars are/will be stored.  The Twitter screen name is the most important, as we’ll need that to access the Twitter feed.

Twitter provides an API with which you can access a user’s status feed in XML format.  This is available from a public access URL in the form of:

http://twitter.com/statuses/user_timeline/screenname.xml?count=1

Replace screenname with the user’s Twitter screen name.  Adding the query string “count=1” forces the API to return only the latest status message, slimming down the request a bit.  Since we’re only interested in the latest status, it shortens both the response time and the request length, which increases the performance of our script.  A user feed looks something like this:

<?xml version="1.0" encoding="UTF-8"?>

<statuses type="array">

<status>

  <created_at>Thu Apr 16 04:48:43 +0000 2009</created_at>

  <id>1531458683</id>

  <text>Just added myself to the http://wefollow.com twitter directory under:  #technology #windows #guru</text>

  <source>&lt;a href=&quot;http://wefollow.com&quot;&gt;WeFollow&lt;/a&gt;</source>

  <truncated>false</truncated>

  <in_reply_to_status_id></in_reply_to_status_id>

  <in_reply_to_user_id></in_reply_to_user_id>

  <favorited>false</favorited>

  <in_reply_to_screen_name></in_reply_to_screen_name>

  <user>

    <id>25939902</id>

    <name>Nilpo</name>

    <screen_name>WindowsGuru</screen_name>

    <location>Salem, Ohio</location>

    <description>Ask the Windows Guru!</description>

    <profile_image_url>http://s3.amazonaws.com/twitter_production/
profile_images/106885592/vista_logo_3__normal.jpg</profile_image_url>

    <url>http://www.nilpo.com</url>

    <protected>false</protected>

    <followers_count>15</followers_count>

    <profile_background_color>9AE4E8</profile_background_color>

    <profile_text_color>333333</profile_text_color>

    <profile_link_color>0084B4</profile_link_color>

    <profile_sidebar_fill_color>DDFFCC</profile_sidebar_fill_color>

    <profile_sidebar_border_color>BDDCAD</profile_sidebar_border_color>

    <friends_count>9</friends_count>

    <created_at>Mon Mar 23 02:56:34 +0000 2009</created_at>

    <favourites_count>0</favourites_count>

    <utc_offset>-18000</utc_offset>

    <time_zone>Eastern Time (US &amp; Canada)</time_zone>

    <profile_background_image_url>http://s3.amazonaws.com/
twitter_production/profile_background_images/8921066/
3237101143_78dbb23e39_o.jpg</profile_background_image_url>

    <profile_background_tile>false</profile_background_tile>

    <statuses_count>11</statuses_count>

    <notifications></notifications>

    <following></following>

  </user>

</status>

</statuses>

{mospagebreak title=Parsing the XML feed} 

The first programming step to creating our image is pretty obvious.  We need to retrieve the Twitter feed and parse the information that we need.  To do that, we’ll create a function called fetchUserInfo.  We’ll also create a function called curlRequest that will act as a wrapper function for the CURL process that will retrieve the external site content.

    private function fetchUserInfo($name)

    {

        $url = "http://twitter.com/statuses/user_timeline/{$name}.xml?count=1";

        $xml = $this->curlRequest($url);

        if ($xml === false) {

            // User feed unavailable.

        }

        $statuses = new SimpleXMLElement($xml);

        if (!$statuses || !$statuses->status) {

            // Invalid user channel.

        }

       foreach ($statuses->status as $status) {

            $this->status_text   = (string) $status->text;

            $this->profile_image = (string) $status->user->profile_image_url;

            $this->screen_name   = (string) $status->user->screen_name;

            break;

        }

    }

This function is much simpler than it looks initially.  It accepts a string containing the Twitter screen name.  That name is used to create a feed URL as described earlier, and then a request is made using $this->curlRequest (to be created) that returns the XML contents of the Twitter feed.  Next, we use the SimpleXMLElement class to parse the XML content and assign the information we need to class-level variables.  Of course, this is all of little worth if we don’t add the curlRequest function that performs the request for the feed.

    private function curlRequest($url)

    {

        if (!extension_loaded(‘curl’)) {

            // PHP extension CURL is not loaded.

        }

        $curl = curl_init($url);

        curl_setopt($curl, CURLOPT_HEADER, false);

        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

        $result = curl_exec($curl);

        if (curl_errno($curl) !== 0 || curl_getinfo($curl, CURLINFO_HTTP_CODE) !== 200) {

            $result === false;

        }

        curl_close($curl);

        return $result;

    }

If you’ve used CURL in the past, this function will look pretty basic.  First it checks that CURL is actually available, and then makes a request to the URL provided.  It returns the response from that request or a Boolean false if there’s an error.

Throughout these code samples, I’ve added error checking but left only comments as to the error.  We’ll be going back later to add proper error handling.

Now we can take advantage of our function by adding a call to $this->fetchUserInfo to the class’s constructor.  While we’re at it, we’ll add a call to $this->fetchAvatar, which is the function we’ll be creating next to load the user’s avatar image.  The constructor now looks like this.

    public function __construct($name, $bg_image, $adir)

    {

        $this->fetchUserInfo(strtolower($name));

        $this->fetchAvatar($this->profile_image, $adir);

    }

You may have also noticed that I’m using the strtolower function to force the user name to be lower-case.  This aids in feed caching, which is a feature we will be adding later.  For now, it just adds uniformity when creating the feed URLs.

{mospagebreak title=Grabbing the avatar image} 

One of the details we were able to parse from the XML feed was the location of the user’s Twitter avatar.  We’re going to display this on our signature image, so we’ll need to make another CURL request to grab the image and store a copy of it locally.

    private function fetchAvatar($url, $adir)

    {

        $fname      = end(explode(‘/’, $url));

        $adir       = preg_match(‘#^(.*?)/$#i’, $url) ? $adir : "{$adir}/";

        $fname      = $adir . $fname;

        if ( !file_exists($fname) ) {

            $img = $this->curlRequest($url);

            $fp = fopen($fname, ‘w’);

            fwrite($fp, $img);

            fclose($fp);

        }

        $this->local_avatar = $fname;

    }

This function is pretty basic.  It uses the curlRequest function to retrieve the avatar image and write it to a local file.  You’ll see a couple of really nifty PHP techniques employed in the first two lines.

The first technique is a quick method of parsing the image file name from a URL.  You’ll recall that URLs have several parts, all delimited by a forward slash.  PHP’s explode function can create an array from a string based on a string delimiter.  This very quickly creates an array of each of the URL parts.  The end function then returns the last element in the array (being the file name portion of the URL).  This is a quick and dirty technique for returning the end portion of a delimited string.

The second technique combines a regular expression match with the ternary operator.  It checks the avatar directory string for a trailing slash and returns either the path if it includes one or the path with a slash appended to it.  This nice one-liner ensures that our path always contains a trailing slash.

Recapping 

Our Twitter SignatureImage class is nearing completion.  We’ve added all of the functions to retrieve a user’s Twitter feed information and copy the user’s avatar image.  In the second part of this article series we’ll take a look at building and rendering the actual signature image.

We’re also going to look at adding appropriate error handling and a file caching feature.  The latter is important since Twitter limits the number of API requests a single IP may request in a specific amount of time.  Caching will store a copy of the XML feed locally to prevent making too many requests to the API service. 

I’ll also be demonstrating a quick method of tracking how many impressions your image gets which is useful if you’re using your image in forum signature.  And of course, I’ll show you how to actually implement the SignatureImage class.  Until next time, keep coding!

Google+ Comments

Google+ Comments