memcached practice: A weird twitter gadget

memcached is widely used in modern websites like flickr, wikipedia, twitter, youtube, digg, WordPress and a long hot continuing list. In the past years, everyone is talking about XXX 2.0, and recently, yes, you got it, NoSQL….

Here’s a weird twitter gadget, to be used by other pages as gadget. You may notice some bad practice on variable naming, function organizing, but ignore them.
The main purpose is to demonstrate a memcached usage, when combined with HTTP cache control.

source generated by “php -s”

`
<?php
define(‘SECRETSTRING’, ‘===’); // base64_encode(‘user:password’)
define(‘USERTIMELINEURL’, ‘https://api.twitter.com/1/statuses/user_timeline.json?count=20‘);
define(‘EXPIRESECONDS’, 300);

function gettweets()
{
$MEMCACHE_SERVERS = array(
“127.0.0.1”, //localhost
);
$keyname = ‘fvn:tweets’;

$mc = new Memcache();
foreach($MEMCACHE_SERVERS as $server){
$mc->addServer ( $server );
}
$ret = FALSE;
if( !(isset($_SERVER[‘HTTP_IF_MODIFIED_SINCE’]))) {// force refresh
$tweets = gettweetsdirectly();
if ($mc->get($keyname) === FALSE) {
$ret = $mc->set($keyname, $tweets, MEMCACHE_COMPRESSED, EXPIRESECONDS);
} else {
$ret = $mc->replace($keyname, $tweets, MEMCACHE_COMPRESSED, EXPIRESECONDS);
}
} else {
$tweets = $mc->get($keyname);
if ($tweets === FALSE)
{
$tweets = gettweetsdirectly();
// cache for 10 minutes
$mc->set($keyname, $tweets, MEMCACHE_COMPRESSED, EXPIRESECONDS);
}
}
return $tweets;
}

function gettweetsdirectly()
{
$context = stream_context_create(array(
‘http’ => array(
‘header’ => “Authorization: Basic “ . SECRETSTRING)
)
);
$data = file_get_contents(USERTIMELINEURL, false, $context);
$tweets = json_decode($data, true);
if ($tweets == NULL)
return FALSE;
return $tweets;
}

// from http://github.com/dizzytree/PHP-Twitter-Client/blob/master/config.php
function format_tweet($str)
{
$formatted_text = preg_replace(‘/(\b(www.|http\:\/\/|https\:\/\/)\S+\b)/‘, “$1“, $str);
$formatted_text = preg_replace(‘/#(\w+)/‘, “#$1“, $formatted_text);
$formatted_text = preg_replace(‘/\@(\w+)/‘, “@$1“, $formatted_text);
return $formatted_text;
}

$t = gettweets();
if ($t == FALSE)
{
header (‘Failed to get tweets.’, 500);
exit;
}

//cache control
$lasttime = strtotime($t[0][‘created_at’]);
if (isset($_SERVER[‘HTTP_IF_MODIFIED_SINCE’]) && (strtotime($_SERVER[‘HTTP_IF_MODIFIED_SINCE’]) == $lasttime)) {
header(‘Last-Modified: ‘.gmdate(‘D, d M Y H:i:s’, $lasttime).’ GMT’, true, 304);
exit;
} else {
header(‘Last-Modified: ‘ . gmdate(“D, d M Y H:i:s”, $lasttime) . ‘ GMT’);
header(‘Expires: ‘ . gmdate(“D, d M Y H:i:s”, $lasttime + EXPIRESECONDS) . ‘ GMT’);
}

//echo tweets
echo ‘

    ‘;
    $len = count($t);
    for ($i = 0; $i < $len; $i++)
    {
    echo ‘

  • ‘;
    echo format_tweet($t[$i][‘text’]);
  • echo ‘


    ‘;
    }
    echo ‘‘;

    ?>

    `