Page 1 of 1

How to fetch Twitter updates in php

Posted: Mon Mar 01, 2010 12:11 am
by Neo
Would you like to integrate Twitter into your website? In this tutorial, I'll explain how to access the Twitter API to fetch a user's updates using raw PHP (version 5.0 or greater). This will be a very basic use of the Twitter API, but it should give you a starting point if you need to do something more advanced. There are also some Twitter libraries that will let you do the same thing without knowing how it all works.

We will be utilizing the statuses/user_timeline method of the Twitter REST API. Basically, this is a special URL that returns the requested data in the requested format. In this case, we will request the user_timeline as XML, so our URL looks like: "http://twitter.com/statuses/user_timeli ... e=username"[/b].

All we need to do is write a PHP script that fetches the URL and then parses the XML that it receives. We should also cache the results so we don't spam Twitter with a request every time someone views your page and exceed the limit. My caching method of choice it to store the data in a MySQL database, since it is most widely available, so let's create the needed tables now:

Code: Select all

CREATE TABLE `twitter` (
  `id` mediumint(8) NOT NULL AUTO_INCREMENT,
  `twid` bigint(32) NOT NULL,
  `text` varchar(256) NOT NULL,
  `time` bigint(11) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `twid` (`twid`)
);
 
CREATE TABLE `twitter_status` (
  `twid` bigint(32) NOT NULL,
  `time` bigint(11) NOT NULL
);
 
INSERT INTO `twitter_status` (`twid`, `time`) VALUES (0, 0);
We've created two tables here. The twitter table stores the actual data from Twitter for local access, and the twitter_status table has one row storing the last tweet ID and timestamp of the last update.

Fetching the Data
Now we're going to create a function that grabs a supplied user's timeline and returns a list of updates, each as an array of update ID, text, and date (as a Unix timestamp).

Code: Select all

function fetch_twitter_feed($user, $since = 0) {
    $url = 'http://twitter.com/statuses/user_timeline.xml?screen_name=' . $user;
    if($since > 0) {
        $url .= '&since_id=' . $since;
    }
    $data = file_get_contents($url);
    $xmlDoc = DOMDocument::loadXML($data);
    $statuses = $xmlDoc->getElementsByTagName('status');
    $updates = array();
    if($statuses->length > 0) {
        foreach($statuses as $status) {
            $id = $status->getElementsByTagName('id')->item(0)->nodeValue;
            $text = $status->getElementsByTagName('text')->item(0)->nodeValue;
            $date = strtotime($status->getElementsByTagName('created_at')->item(0)->nodeValue);
            $updates[] = array($id, $text, $date);
        }
    }
    return $updates;
} 
This uses a simple file_get_contents() to grab the raw data, then pass it to a DOMDocument object (which functions basically the same as JavaScript's XML parsing functions) via the loadXML method. Since each update is wrapped in a <status> tag, we grab all of those using the getElementsByTagName method. We can then iterate over the object returned using foreach and access the contents of the <id>, <text>, and <created_at> tags for each item.

We add each result to an array and then return the array when the loop is complete. One more thing to note is that we convert the time to a Unix timestamp using strtotime.

Caching the Data
Now that we can fetch the data from the Twitter API, we need to add some form of caching so we don't access the API on every page view. So we'll wrap the function in another function that will handle the caching, and we'll call it get_twitter_feed:

Code: Select all

function get_twitter_feed($user, $reverse = true, $limit = 10) {
    $db = new MySQLi('localhost', 'user', 'pass', 'database');
    if($result = $db->query("SELECT * FROM `twitter_status`")) {
        $row = $result->fetch_assoc();
        $result->close();
        if(time()-$row['time'] >= 300) {
            $updates = fetch_twitter_feed($user, $row['twid']);
            if(count($updates) > 0){
                krsort($updates);
                foreach($updates as $update) {
                    $id = $db->escape_string($update[0]);
                    $text = $db->escape_string($update[1]);
                    $time = $db->escape_string($update[2]);
                    $db->query("INSERT INTO `twitter` VALUES ('', '" . $id . "', '" . $text . "', '" . $time . "')");
                }
                $db->query("UPDATE `twitter_status` SET `twid` = '" . $id . "', `time` = '" . time() . "'");
            }
            else {
                $db->query("UPDATE `twitter_status` SET `time` = '" . time() . "'");
            }
        }
    }
    $limit = $db->escape_string($limit);
    $updates = array();
    if($result = $db->query("SELECT * FROM `twitter` ORDER BY `id` DESC LIMIT " . $limit)) {
        while($row = $result->fetch_assoc()) {
            $updates[] = array('id' => $row['id'], 'twid' => $row['twid'], 'text' => $row['text'], 'time' => $row['time']);
        }
        $result->close();
        if(!$reverse) {
            krsort($updates);
        }
        return $updates;
    }
    return false;
} 

The first part of the function checks the time from the twitter_status table, and if the time is more than 5 minutes (300 seconds) ago it will call fetch_twitter_feed to update the cache with any new entries, and then update twitter_status table with the time and last tweet ID. After checking/updating the cache, the function gets the data from the cache database and returns it as an array.

The get_twitter_feed function accepts 3 arguments: $user is the Twitter username, $reverse (optional, default true) decides whether to reverse sort the tweets from newest to oldest (just like Twitter does by default), and $limit (optional, default 10) specifies how many tweets to return.

Note: Be sure to replace the connection details at the top of this function with your own, or replace $db entirely with your own database implementation (here I use MySQLi).
Putting it all Together

Here's an example of this function in action:

Code: Select all

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Twitter Feed</title>
<style type="text/css">
<!--
#feed {
    padding: 4px;
    width: 400px;
    border: 1px solid #333333;
}
#feed ul {
    list-style-type: none;
    margin: 0px;
    padding: 0px;
}
#feed li {
    display: block;
    margin: 2px;
    padding: 4px;
    border: 1px solid #FFA119;
    font-size: 0.9em;
}
#feed .caption {
    font-size: 0.8em;
    font-style: italic;
    color: #333333;
}
-->
</style>
</head>
<body>
<div id="feed">
  <ul>
<?php
if($updates = get_twitter_feed('robot.lk')) {
    foreach($updates as $update) {
        $text = htmlspecialchars($update['text']);
        $time = date('m/d/y g:i A', $update['time']);
?>
    <li>
      <div class="caption"><?php echo $time; ?></div>
      <?php echo $text; ?></li>
<?php
    }
}
?>
  </ul>
</div>
</body>
</html>
As you can see, get_twitter_feed returns an array of associative arrays. You can iterate over the array with foreach and access the text and time from each item. Thanks for reading, and please let me know if you use this for anything!