PHP: Displaying Twitter Search Results in HTMLHere's a new use for our RSS Feed Reader - displaying content returned by the Twitter API. In this article we are simply fetching and presenting the most recent 'tweets' containing a particular string, but there's no reason why the same code can't be used for other RSS content returned by Twitter. Fetching the feed contents from TwitterThe first step is to define our parameters: <?PHP
if(!isset($_GET['q']) || !$q = $_GET['q']) $q = 'twitter';
$NUMITEMS = 10;
$BLOGURL = "http://search.twitter.com/search.rss?q=" . urlencode($q) , "&rpp=$NUMITEMS";
$TIMEFORMAT = "j F Y, g:ia";
$CACHEFILE = "/tmp/" . md5($BLOGURL);
$CACHETIME = 0.5; # hours
You can see from the first line that this script accepts a single $_GET parameter $q defining the search string. If this variable is not set then the default search is for 'twitter'. The other parameters should be self-explanatory. To do a search on Twitter we just send an HTTP request to their search script including the format (in this case 'rss') and the query string. Other more advanced options (see References below) are also available. For our purposes just the rpp (number of tweets to return per page) parameter is enough. No authentication is necessary as we're only reading public content, but it is rate limited. For security it's a good idea to expand any 'shortened' urls in the results. That way people know what they're clicking on. We do this using curl and a crafty regular expression that detects most known url-shortening services: # Original PHP code by Chirp Internet: www.chirp.com.au
# Please acknowledge use of this code by including this header.
function expandLinks(&$input)
{
# links matching the following regular expressions will be checked for redirects and expanded
$domains = array(
'[a-z0-9]{2,3}\.[a-z]{2}', '[a-z]{3,4}url\.com'
);
if(preg_match_all("@http://((" . implode("|", $domains) . ")/[-a-z0-9]+)@i", $input, $matches)) {
$matches = array_unique($matches[1]);
foreach($matches as $shorturl) {
$command = "curl --head " . escapeshellarg($shorturl) . " | awk '($1 ~ /^Location/){print $2}'";
if($expandedurl = exec($command)) {
$input = str_replace("http://$shorturl", htmlspecialchars($expandedurl), $input);
}
}
}
}
We could also just try to expand every URL detected, but then you're making a lot of unnecessary HEAD requests for those links that pass through Twitter unshortened. Important: Using the PHP Curl library is also possible and might be necessary if you're using Windows. The script presented above requires command-line curl access and the awk function. You can find a script that uses PHP Curl under References below. Now we need a way to download and store (cache) the feed contents. We do this using a simple function: function updateFeed()
{
global $BLOGURL, $CACHEFILE;
ini_set('user_agent', "TheArtOfWeb (http://{$_SERVER['HTTP_HOST']})");
if($feed_contents = file_get_contents($BLOGURL)) {
# expand shortened urls
expandLinks($feed_contents);
# write feed contents to cache file
$fp = fopen($CACHEFILE, 'w');
fwrite($fp, $feed_contents);
fclose($fp);
}
}
The updateFeed function when called simply downloads and stores the raw RSS file contents. Note that before making the API request to Twitter we are setting the user agent. You don't have to set a user agent, but if you don't your requests can be rate-limited. Displaying the search results in HTML formatIn the next section we display a short paragraph introducing the search results. Both the search string and the last modified date of the cached file are displayed: echo "<p>Read the latest tweets mentioning <b>$q</b> as of ";
if(file_exists($CACHEFILE)) {
echo date('g:ia', filemtime($CACHEFILE)) . ' local time';
} else {
echo 'right now';
}
echo ":</p>\n\n";
If no cached file exists for this query the updateFeed function is called to fetch it for the first time. # download the feed iff cached version is missing
if(!file_exists($CACHEFILE)) updateFeed();
Finally we're ready to display the search results on the page. This section is almost identical to that introduced in previous articles, the only difference being that it's been customised specifically for Twitter content: include "class.myrssparser.php";
$rss_parser = new myRSSParser($CACHEFILE);
# read feed data from cache file
$feeddata = $rss_parser->getRawOutput();
extract($feeddata['RSS']['CHANNEL'][0], EXTR_PREFIX_ALL, 'rss');
# display feed items
if($rss_ITEM) {
echo "<table border=\"0\" cellpadding=\"5\" cellspacing=\"0\">\n";
foreach($rss_ITEM as $itemdata) {
preg_match("/^(.*)@twitter\.com \((.*)\)$/", $itemdata['AUTHOR'], $regs);
list($foo, $author, $name) = $regs;
echo "<tr>\n";
echo "<td><a title=\"$name\" href=\"http://twitter.com/$author\" target=\"_blank\"><img src=\"{$itemdata['GOOGLE:IMAGE_LINK']}\" width=\"48\" height=\"48\" border=\"0\" alt=\"$author\"></a></td>\n";
echo "<td><p><a href=\"http://twitter.com/$author\" target=\"_blank\">$author</a>: ";
echo str_replace('<a ', '<a target="_blank" ', stripslashes($itemdata['DESCRIPTION']));
echo "<br>\n";
echo "<small>";
echo date($TIMEFORMAT, strtotime($itemdata['PUBDATE']));
echo " <a href=\"{$itemdata['GUID']}\" target=\"_blank\">View Tweet</a>";
echo "</small>";
echo "</p></td>\n";
echo "</tr>\n";
}
echo "</table>\n\n";
}
?>
The output, as you can probably work out, will be a two-column HTML table displaying the users twitter icon, the update text and timestamp. We've also included some links where appropriate. As a final step the following code should be placed right at the end of the page after all the HTML has been displayed: <?PHP
# download the feed iff cached version is too old
if((time() - filemtime($CACHEFILE)) > 3600 * $CACHETIME) {
flush();
updateFeed();
}
?>
The function of this code and the reason for placing it at the end of the page has been described in a previous article. Sample output of Twitter search resultsHere you can see the output of this script more or less exactly as presented. All we've done is added some smilies: Read the latest tweets mentioning twitter as of 8:05am local time: This script is experimental so you use it at your own risk. Please send questions and comments via the Feedback link below. Contents of the Twitter search RSS FeedHere you can see exactly what kind of data we're receiving back from Twitter in RSS format: <?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:google="http://base.google.com/ns/1.0" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:twitter="http://api.twitter.com/">
<channel>
<title>twitter - Twitter Search</title>
<description>twitter - Twitter Search</description>
<link>http://search.twitter.com/search?q=twitter</link>
<twitter:refresh_url>http://search.twitter.com/search.rss?q=twitter&rpp=10&since_id=22864692773</twitter:refresh_url>
<pubDate>Fri, 03 Sep 2010 06:05:13 +0000</pubDate>
<openSearch:itemsPerPage>10</openSearch:itemsPerPage>
<item>
<title>@TRAEABN gotta aske Twitter n it'll take months!!!</title>
<link>http://twitter.com/DjChablo/statuses/22864692773</link>
<description><a href="http://twitter.com/TRAEABN">@TRAEABN</a> gotta aske <b>Twitter</b> n it&apos;ll take months!!!</description>
<pubDate>Fri, 03 Sep 2010 06:05:13 +0000</pubDate>
<guid>http://twitter.com/DjChablo/statuses/22864692773</guid>
<author>DjChablo@twitter.com (Richard Boyle)</author>
<media:content type="image/jpg" height="48" width="48" url="http://a2.twimg.com/profile_images/1053325930/lol_normal.jpg"/>
<google:image_link>http://a2.twimg.com/profile_images/1053325930/lol_normal.jpg</google:image_link>
<twitter:metadata>
<twitter:result_type>recent</twitter:result_type>
</twitter:metadata>
</item>
<item>
<title>[WOW]GET FOR 100 FREE TWITTER FOLLOWERS http://letgetmorefollowers.com/index.php?invitecodes=07a9aa9f2b4a25fa9dc2a984b56870e9</title>
<link>http://twitter.com/Andrei__santos/statuses/22864692421</link>
<description>[WOW]GET FOR 100 FREE <b>TWITTER</b> FOLLOWERS <a href="http://letgetmorefollowers.com/index.php?invitecodes=07a9aa9f2b4a25fa9dc2a984b56870e9">http://letgetmorefollowers.com/index.php?invitecodes=07a9aa9f2b4a25fa9dc2a984b56870e9</a></description>
<pubDate>Fri, 03 Sep 2010 06:05:13 +0000</pubDate>
<guid>http://twitter.com/Andrei__santos/statuses/22864692421</guid>
<author>Andrei__santos@twitter.com (Andrei Santos)</author>
<media:content type="image/jpg" height="48" width="48" url="http://a3.twimg.com/profile_images/1116111535/Snapshot_20100514_1_normal.jpg"/>
<google:image_link>http://a3.twimg.com/profile_images/1116111535/Snapshot_20100514_1_normal.jpg</google:image_link>
<twitter:metadata>
<twitter:result_type>recent</twitter:result_type>
</twitter:metadata>
</item>
<item>
<title>twitter itu pemborosan kata nyokap. Gw ga mau nyusain nyokap lg</title>
<link>http://twitter.com/Reza_Jae/statuses/22864692350</link>
<description><b>twitter</b> itu pemborosan kata nyokap. Gw ga mau nyusain nyokap lg</description>
<pubDate>Fri, 03 Sep 2010 06:05:13 +0000</pubDate>
<guid>http://twitter.com/Reza_Jae/statuses/22864692350</guid>
<author>Reza_Jae@twitter.com (Reza Imam Pratama)</author>
<media:content type="image/jpg" height="48" width="48" url="http://a0.twimg.com/profile_images/1113826988/llll_normal.jpg"/>
<google:image_link>http://a0.twimg.com/profile_images/1113826988/llll_normal.jpg</google:image_link>
<twitter:metadata>
<twitter:result_type>recent</twitter:result_type>
</twitter:metadata>
</item>
<item>
<title>I JUST GET 100 FREE TWITTER FOLLOWERS! http://PlusFollower.com/get-more-twitter-followers-4ce42f12cf2847d0bd87811796f3b2e4.html</title>
<link>http://twitter.com/igerryl/statuses/22864691754</link>
<description>I JUST GET 100 FREE <b>TWITTER</b> FOLLOWERS! <a href="http://PlusFollower.com/get-more-twitter-followers-4ce42f12cf2847d0bd87811796f3b2e4.html">http://PlusFollower.com/get-more-twitter-followers-4ce42f12cf2847d0bd87811796f3b2e4.html</a></description>
<pubDate>Fri, 03 Sep 2010 06:05:12 +0000</pubDate>
<guid>http://twitter.com/igerryl/statuses/22864691754</guid>
<author>igerryl@twitter.com (Gerry Anugrah K.)</author>
<media:content type="image/jpg" height="48" width="48" url="http://a2.twimg.com/profile_images/1116055358/Copy_of_DSTC02645__HDTV__720___normal.jpg"/>
<google:image_link>http://a2.twimg.com/profile_images/1116055358/Copy_of_DSTC02645__HDTV__720___normal.jpg</google:image_link>
<twitter:metadata>
<twitter:result_type>recent</twitter:result_type>
</twitter:metadata>
</item>
<item>
<title>@emann4real omg!!! Ummmm llel ! Don't be crying on twitter now! Are u in ur normal state of mind ryt now?</title>
<link>http://twitter.com/ThatRedAce/statuses/22864691054</link>
<description><a href="http://twitter.com/emann4real">@emann4real</a> omg!!! Ummmm llel ! Don&apos;t be crying on <b>twitter</b> now! Are u in ur normal state of mind ryt now?</description>
<pubDate>Fri, 03 Sep 2010 06:05:11 +0000</pubDate>
<guid>http://twitter.com/ThatRedAce/statuses/22864691054</guid>
<author>ThatRedAce@twitter.com (Mikeisha.... )</author>
<media:content type="image/jpg" height="48" width="48" url="http://a2.twimg.com/profile_images/1098053130/151540115_normal.jpg"/>
<google:image_link>http://a2.twimg.com/profile_images/1098053130/151540115_normal.jpg</google:image_link>
<twitter:metadata>
<twitter:result_type>recent</twitter:result_type>
</twitter:metadata>
</item>
<item>
<title>I JUST GET FOR 100 FREE TWITTER FOLLOWERS http://PlusFollower.com/get-more-twitter-followers-5f301296cc08a8ba4800eea91562e5c9.html</title>
<link>http://twitter.com/igerryl/statuses/22864690707</link>
<description>I JUST GET FOR 100 FREE <b>TWITTER</b> FOLLOWERS <a href="http://PlusFollower.com/get-more-twitter-followers-5f301296cc08a8ba4800eea91562e5c9.html">http://PlusFollower.com/get-more-twitter-followers-5f301296cc08a8ba4800eea91562e5c9.html</a></description>
<pubDate>Fri, 03 Sep 2010 06:05:11 +0000</pubDate>
<guid>http://twitter.com/igerryl/statuses/22864690707</guid>
<author>igerryl@twitter.com (Gerry Anugrah K.)</author>
<media:content type="image/jpg" height="48" width="48" url="http://a2.twimg.com/profile_images/1116055358/Copy_of_DSTC02645__HDTV__720___normal.jpg"/>
<google:image_link>http://a2.twimg.com/profile_images/1116055358/Copy_of_DSTC02645__HDTV__720___normal.jpg</google:image_link>
<twitter:metadata>
<twitter:result_type>recent</twitter:result_type>
</twitter:metadata>
</item>
<item>
<title>HIT - GETTING 100 FREE FOLLOWERS http://hitfollow.com/get-more-twitter-followers-e16d8e528f2bf260adf20d976904ec0c.html</title>
<link>http://twitter.com/socioculturais/statuses/22864690047</link>
<description>HIT - GETTING 100 FREE FOLLOWERS <a href="http://hitfollow.com/get-more-twitter-followers-e16d8e528f2bf260adf20d976904ec0c.html">http://hitfollow.com/get-more-twitter-followers-e16d8e528f2bf260adf20d976904ec0c.html</a></description>
<pubDate>Fri, 03 Sep 2010 06:05:10 +0000</pubDate>
<guid>http://twitter.com/socioculturais/statuses/22864690047</guid>
<author>socioculturais@twitter.com (Captação de Recursos)</author>
<media:content type="image/jpg" height="48" width="48" url="http://a1.twimg.com/profile_images/845183997/a_01_normal.jpg"/>
<google:image_link>http://a1.twimg.com/profile_images/845183997/a_01_normal.jpg</google:image_link>
<twitter:metadata>
<twitter:result_type>recent</twitter:result_type>
</twitter:metadata>
</item>
<item>
<title>@EyMariahh you're welcome @BiebersGrapes but i feel like a poor twitter account :( :P @MontrealBIEBERS jump right after him :)</title>
<link>http://twitter.com/purple_ninjaJB/statuses/22864689606</link>
<description><a href="http://twitter.com/EyMariahh">@EyMariahh</a> you&apos;re welcome <a href="http://twitter.com/BiebersGrapes">@BiebersGrapes</a> but i feel like a poor <b>twitter</b> account :( :P <a href="http://twitter.com/MontrealBIEBERS">@MontrealBIEBERS</a> jump right after him :)</description>
<pubDate>Fri, 03 Sep 2010 06:05:10 +0000</pubDate>
<guid>http://twitter.com/purple_ninjaJB/statuses/22864689606</guid>
<author>purple_ninjaJB@twitter.com (✔vεяiƒiε∂ βεℓiεβεя)</author>
<media:content type="image/jpg" height="48" width="48" url="http://a3.twimg.com/profile_images/1112185887/148727554-c335fd19a9137afb291ce1ac5cde4a63_4c702938-scaled_normal.jpg"/>
<google:image_link>http://a3.twimg.com/profile_images/1112185887/148727554-c335fd19a9137afb291ce1ac5cde4a63_4c702938-scaled_normal.jpg</google:image_link>
<twitter:metadata>
<twitter:result_type>recent</twitter:result_type>
</twitter:metadata>
</item>
<item>
<title>Twitter is dry and I'm tired, Goodnight</title>
<link>http://twitter.com/shortee88/statuses/22864689217</link>
<description><b>Twitter</b> is dry and I&apos;m tired, Goodnight</description>
<pubDate>Fri, 03 Sep 2010 06:05:09 +0000</pubDate>
<guid>http://twitter.com/shortee88/statuses/22864689217</guid>
<author>shortee88@twitter.com (Dana )</author>
<media:content type="image/jpg" height="48" width="48" url="http://a1.twimg.com/profile_images/1108914773/glow_normal.jpg"/>
<google:image_link>http://a1.twimg.com/profile_images/1108914773/glow_normal.jpg</google:image_link>
<twitter:metadata>
<twitter:result_type>recent</twitter:result_type>
</twitter:metadata>
</item>
<item>
<title>Bon, Facebook, twitter et plurk c'est sympa mais, faudrait partir je pense (@ FrenchWicile) http://4sq.com/cVgZIU</title>
<link>http://twitter.com/FrenchW/statuses/22864689132</link>
<description>Bon, Facebook, <b>twitter</b> et plurk c&apos;est sympa mais, faudrait partir je pense (@ FrenchWicile) <a href="http://4sq.com/cVgZIU">http://4sq.com/cVgZIU</a></description>
<pubDate>Fri, 03 Sep 2010 06:05:09 +0000</pubDate>
<guid>http://twitter.com/FrenchW/statuses/22864689132</guid>
<author>FrenchW@twitter.com (FrenchW)</author>
<media:content type="image/jpg" height="48" width="48" url="http://a1.twimg.com/profile_images/57756541/_FredBureauOfficiel_normal.jpg"/>
<google:image_link>http://a1.twimg.com/profile_images/57756541/_FredBureauOfficiel_normal.jpg</google:image_link>
<twitter:metadata>
<twitter:result_type>recent</twitter:result_type>
</twitter:metadata>
</item>
</channel>
</rss>
All the code in one placeBy popular request, here's a copy of all the above code in one place. It's a direct copy of the code used to display the results on this page: <?PHP
if(!isset($_GET['q']) || !$q = $_GET['q']) $q = 'twitter';
$NUMITEMS = 10;
$BLOGURL = "http://search.twitter.com/search.rss?q=" . urlencode($q) . "&rpp=$NUMITEMS";
$TIMEFORMAT = "j F Y, g:ia";
$CACHEFILE = "/tmp/" . md5($BLOGURL);
$CACHETIME = 0.5; # hours
# Original PHP code by Chirp Internet: www.chirp.com.au
# Please acknowledge use of this code by including this header.
function expandLinks(&$input)
{
# links matching the following regular expressions will be checked for redirects and expanded
$domains = array(
'[a-z0-9]{2,3}\.[a-z]{2}', '[a-z]{3,4}(url|ly)\.com'
);
if(preg_match_all("@http://((" . implode("|", $domains) . ")/[-a-z0-9]+)@i", $input, $matches)) {
$matches = array_unique($matches[1]);
foreach($matches as $shorturl) {
$command = "curl --head " . escapeshellarg($shorturl) . " | awk '($1 ~ /^Location/){print $2}'";
if($expandedurl = exec($command)) {
$input = str_replace("http://$shorturl", htmlspecialchars($expandedurl), $input);
}
}
}
}
function updateFeed()
{
global $BLOGURL, $CACHEFILE;
ini_set('user_agent', "TheArtOfWeb (http://{$_SERVER['HTTP_HOST']})");
if($feed_contents = file_get_contents($BLOGURL)) {
# expand shortened urls
expandLinks($feed_contents);
# write feed contents to cache file
$fp = fopen($CACHEFILE, 'w');
fwrite($fp, $feed_contents);
fclose($fp);
}
}
echo "<p>Read the latest tweets mentioning <b>$q</b> as of ";
if(file_exists($CACHEFILE)) {
echo date('g:ia', filemtime($CACHEFILE)) . ' local time';
} else {
echo 'right now';
}
echo ":</p>\n\n";
# download the feed iff cached version is missing
if(!file_exists($CACHEFILE)) updateFeed();
include "class.myrssparser.php";
$rss_parser = new myRSSParser($CACHEFILE);
# read feed data from cache file
$feeddata = $rss_parser->getRawOutput();
extract($feeddata['RSS']['CHANNEL'][0], EXTR_PREFIX_ALL, 'rss');
# display feed items
if($rss_ITEM) {
echo "<table border=\"0\" cellpadding=\"5\" cellspacing=\"0\">\n";
foreach($rss_ITEM as $itemdata) {
preg_match("/^(.*)@twitter\.com \((.*)\)$/", $itemdata['AUTHOR'], $regs);
list($foo, $author, $name) = $regs;
echo "<tr>\n";
echo "<td><a title=\"$name\" href=\"http://twitter.com/$author\" target=\"_blank\"><img src=\"{$itemdata['GOOGLE:IMAGE_LINK']}\" width=\"48\" height=\"48\" border=\"0\" alt=\"$author\"></a></td>\n";
echo "<td><p style=\"width: 600px; overflow: auto;\"><a href=\"http://twitter.com/$author\" target=\"_blank\">$author</a>: ";
echo str_replace('<a ', '<a rel="nofollow" target="_blank" ', stripslashes($itemdata['DESCRIPTION']));
echo "<br>\n";
echo "<small><a style=\"text-decoration: none; color: inherit;\" href=\"{$itemdata['GUID']}\" target=\"_blank\">";
echo date($TIMEFORMAT, strtotime($itemdata['PUBDATE']));
echo "</a></small>";
echo "</p></td>\n";
echo "</tr>\n";
}
echo "</table>\n\n";
}
?>
And here's the code again to be included at the end of the page: <PHP
# download the feed iff cached version is too old
if((time() - filemtime($CACHEFILE)) > 3600 * $CACHETIME) {
flush();
updateFeed();
}
?>
Related Articles
ReferencesSend Feedback |
|
|
© Copyright 2010 Chirp Internet
- Page Last Modified: 8 July 2010
|
|