Delivering the new RSS feed
We are finally ready to put the new Twitter RSS feed together based on the tweets we’ve collected in the database. Let’s review what Twitter normally delivers, and then we can try to improve it. The standard feed for @BarackObama is delivered with this URL: https://api.twitter.com/1/statuses/user_timeline.atom?screen_name=barackobama
And here is what it looks like in Google Reader:

Try loading this URL in your browser and viewing the source to see how the feed is structured. You can see that there is a header element that identifies the feed, and then a series of entry elements for each tweet. We need to create the same structure, and then we can populate it with our own version of the tweet data. I’m sure there are some fancy PHP libraries for generating the XML data we need for this type of output, but I have a much simpler model. I create a set of simple text files that act as templates. Then I insert macros where the data goes. The macros are just field names with brackets, as in [tweet_text]. My PHP code can then read the template and use str_replace() to substitute data for each macro. This makes sense when you see it in action.
I have a template for the header section that has macros for the data, and an [entries] macro that will be used to add a complete list of entry elements.
feed_header.txt
1 2 3 4 5 6 7 8 9 | <?xml version="1.0" encoding="UTF-8"?> <feed xmlns:twitter="http://api.twitter.com" xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US" xmlns:georss="http://www.georss.org/georss"> <title>140dev.com version of [screen_name]'s Twitter feed</title> <link type="text/html" rel="alternate" href="http://twitter.com/[screen_name]"/> <link type="application/atom+xml" rel="self" href="http://140dev.com/tutorials/twitter_rss_feed/rss_feed.php"/> <updated>[created_at]</updated> <subtitle>Twitter updates from [name] / [screen_name].</subtitle> [entries] </feed> |
I also created a template for the entry elements.
feed_entry.txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <entry>
<title>[title]</title>
<content type="html"><img src="[image]"/> [tweet_text]</content>
<id>tag:twitter.com,2007:http://twitter.com/[screen_name]/statuses/[tweet_id]</id>
<published>[created_at]</published>
<updated>[created_at]</updated>
<link type="text/html" rel="alternate" href="http://twitter.com/[screen_name]/statuses/[tweet_id]"/>
<link type="image/jpeg" href="[image]" rel="image"/>
<author>
<name>[name]</name>
<uri>[url]</uri>
</author>
<twitter:source>web</twitter:source>
<twitter:place/>
</entry> |
Now we can pull everything together and generate a custom feed.
rss_feed.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | <?php
// rss_feed.php
// This user data is hardcoded for this tutorial
// You can also collect this in a database and use that version
$screen_name = 'BarackObama';
$name = 'Barack Obama';
$url = 'http://www.barackobama.com';
$profile_image_url = 'http://a0.twimg.com/profile_images/1735360254/icon_normal.jpg';
// Load the template for the feed header
$feed_header = file_get_contents('feed_header.txt');
// Fill in the proper values
$feed_header = str_replace('[screen_name]',$screen_name,$feed_header);
$feed_header = str_replace('[created_at]',date('c'),$feed_header);
$feed_header = str_replace('[name]',$name,$feed_header);
// Start the final output string with the filled in header
$feed_output = $feed_header;
// Get the template for a feed entry
$feed_entry_template = file_get_contents('feed_entry.txt');
// Accumulate all the entries in this string
$feed_entries = '';
require_once('db_lib.php');
$oDB = new db;
// Get the most recent 20 tweets for this user
$query = "SELECT tweet_id, created_at, tweet_text
FROM rss_feed
WHERE screen_name = '$screen_name'
ORDER BY created_at DESC
LIMIT 20";
$result = $oDB->select($query);
while ($row=mysqli_fetch_assoc($result)) {
$tweet_id = $row['tweet_id'];
$created_at = $row['created_at'];
$tweet_text = $row['tweet_text'];
// Get a fresh copy of the entry template
$feed_entry = $feed_entry_template;
// Fill in all the values
$feed_entry = str_replace('[tweet_id]',$tweet_id,$feed_entry);
$feed_entry = str_replace('[created_at]',date('c',strtotime($created_at)),$feed_entry);
$feed_entry = str_replace('[tweet_text]',$tweet_text,$feed_entry);
$feed_entry = str_replace('[screen_name]',$screen_name,$feed_entry);
$feed_entry = str_replace('[name]',$name,$feed_entry);
$feed_entry = str_replace('[image]',$profile_image_url,$feed_entry);
$feed_entry = str_replace('[title]',$name . ": " . date('F, d',strtotime($created_at)),$feed_entry);
$feed_entry = str_replace('[url]',$url,$feed_entry);
// Add this to the accumlated entry string
$feed_entries .= $feed_entry . "\n";
}
// Insert the string of entries into the header template
$feed_output = str_replace('[entries]',$feed_entries,$feed_output);
// Return the feed
print $feed_output;
?> |
You can run this script from your browser to see the complete XML of the feed: http://140dev.com/tutorials/twitter_rss_feed/rss_feed_query.php
Your browser will probably show only the data, and not the XML. In that case, you can view the page source to see the actual XML. You can also subscribe to this new feed URL with something like Google Reader.

A major limitation of the Twitter version of the RSS feed is that it only delivers the most recent tweets. It would be much more useful if you could supply a search query, start date, and end date for the tweets you want to deliver. We can finish this tutorial with another version of the rss_feed_php script that can accept these values as URL arguments. Here is the code for this new version call rss_feed_query.php
rss_feed_query.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | <?php
// rss_feed_query.php
$screen_name = 'BarackObama';
$name = 'Barack Obama';
$url = 'http://www.barackobama.com';
$profile_image_url = 'http://a0.twimg.com/profile_images/1735360254/icon_normal.jpg';
$feed_header = file_get_contents('feed_header.txt');
$feed_header = str_replace('[screen_name]',$screen_name,$feed_header);
$feed_header = str_replace('[created_at]',date('c'),$feed_header);
$feed_header = str_replace('[name]',$name,$feed_header);
$feed_output = $feed_header;
$feed_entry_template = file_get_contents('feed_entry.txt');
$feed_entries = '';
require_once('db_lib.php');
$oDB = new db;
// Get the starting date, ending date, and query arguments sent in the URL
// Add any arguments to the SQL query
$start_date = '';
$end_date = '';
$query = '';
$where = '';
if (isset($_GET['start_date'])) {
// All values passed from outside must be escaped
// to prevent against SQL injection attacks
$start_date = $oDB->escape($_GET['start_date']);
$where .= " AND created_at >= '$start_date' ";
}
if (isset($_GET['end_date'])) {
$end_date = $oDB->escape($_GET['end_date']);
$where .= " AND created_at <= '$end_date' ";
}
if (isset($_GET['query'])) {
$query = $oDB->escape($_GET['query']);
$where .= " AND tweet_text LIKE '%$query%' ";
}
$query = "SELECT tweet_id, created_at, tweet_text
FROM rss_feed
WHERE screen_name = '$screen_name' $where
ORDER BY created_at DESC
LIMIT 20";
$result = $oDB->select($query);
while ($row=mysqli_fetch_assoc($result)) {
$tweet_id = $row['tweet_id'];
$created_at = $row['created_at'];
$tweet_text = $row['tweet_text'];
$feed_entry = $feed_entry_template;
$feed_entry = str_replace('[tweet_id]',$tweet_id,$feed_entry);
$feed_entry = str_replace('[created_at]',date('c',strtotime($created_at)),$feed_entry);
$feed_entry = str_replace('[tweet_text]',$tweet_text,$feed_entry);
$feed_entry = str_replace('[screen_name]',$screen_name,$feed_entry);
$feed_entry = str_replace('[name]',$name,$feed_entry);
$feed_entry = str_replace('[image]',$profile_image_url,$feed_entry);
$feed_entry = str_replace('[title]',$name . ": " . date('F, d',strtotime($created_at)),$feed_entry);
$feed_entry = str_replace('[url]',$url,$feed_entry);
$feed_entries .= $feed_entry . "\n";
}
$feed_output = str_replace('[entries]',$feed_entries,$feed_output);
print $feed_output;
?> |
To run this new script, you can add query string arguments to the URL. Each argument is optional and the order of the arguments does not matter, so any combination is acceptable. The only rule is that must be followed is that the dates should be in ‘YYYY-MM-DD’ format. Here are some examples. Again, your browser may require you to view the source of the resulting feed to actually see the XML.
http://140dev.com/tutorials/twitter_rss_feed/rss_feed_query.php?query=michele
http://140dev.com/tutorials/twitter_rss_feed/rss_feed_query.php?query=romney&start_date=2012-5-1
I know this has been a long tutorial, but hopefully you have learned a lot of useful techniques. I think we have satisfied all the original goals. We now have a Twitter RSS feed that can be called as many times as you want from your server with no rate limits. You can completely customize the appearance and data. Since this script generates XML, you can easily add the results to your web page to make it visible for Google SEO. In fact, you could always modify it to deliver HTML and embed that in your pages instead. And best of all, you collect and deliver all of the tweets in an account, not just the most recent 20.













