Fixing Twitter Feeds

by Kean Richmond
See Dave Speak SMX London

By next week (March 2013) Twitter will be switching off version 1 of its API forcing everyone to use version 1.1. For most the only difference you need to know between these two is that v1.1 requires authentication before you can access any goodies.

And it's this authentication that means any script, plugin or website that makes use of version 1 of the API will need to change, and change quickly, to the newer API. If this isn't done then best case is you won't see any new tweets on your website. Worst case is it could break your whole website if it's heavily dependent on Twitter.

What to do?

If you use a third party plugin then simply ensure it's up to date, and that the plugin is still being developed. It might be the latest version but that could have been released years ago and the plugin isn't actually being maintained anymore.

If it's not a plugin and it doesn't already use v1.1 of the API you need to either update the code yourself if you're proficient or get a developer to do it for you. If it's not using OAuth anywhere in the code then chances are it needs updating.

We've had to do this for many of our clients Twitter feeds as we've always used a custom script to get a person or companies latest tweets.

Previously

Our code as it stood last week looked like this:

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
function outputTwitter($account,$num){
 
	$fileloc = "cache/twitter.html";
	$time = 3600; // An Hour
 
	if(checkRateLimit() && (!file_exists($fileloc) || time() - filemtime($fileloc) > $time)){
		$xml_link = 'https://api.twitter.com/1/statuses/user_timeline.json?include_entities=true&trim_user=true&include_rts=true&screen_name='.$account.'&count='.$num;
		$json = curling($xml_link);
		$tweets = json_decode($json);
		$arrTweets = array();
 
		if(!$tweets->error){
			for($i=0;$i<$num;$i++){
				$item = array(
					'text' => $tweets[$i]->text,
					'created_at' => strtotime($tweets[$i]->created_at)
					);
				array_push($arrTweets, $item);
			}	
			$output_file = '';
			foreach($arrTweets as $value){
				$output_file .= $value['text'] . " :: " . $value['created_at'] . " :::: ";
			}
			cacheIt($output_file,$fileloc);
		}
	}
	if(file_exists($fileloc)){
		$input = file_get_contents($fileloc);
		$parts = explode(' :::: ', $input);
		if(empty($parts[count($parts)-1])) {
			unset($parts[count($parts)-1]);
		}
		$return = array();
		foreach($parts as $value){
			$object = new stdClass;
			$bits = explode(' :: ', $value);
			$tweet = preg_replace("#((http|https|ftp)://(S*?.S*?))(s|;|)|]|[|{|}|,|"|'|:|<|$|.s)#ie","'<a href="$1" target="_blank">$1</a>$4'",$bits[0]);
			$tweet = preg_replace("#((@)([A-z0-9_]*))#","<a href="http://twitter.com/$3" target="_blank">$1</a>$4",$tweet);
			if($bits[0]){ 
				$object->text = $tweet;
				$object->created = $bits[1];
			}
			array_push($return,$object);
		}
	}
	return $return;
 
}

And some other functions the above code is dependent on.

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
 
// curling
//------------------------------------------------------------------------------------------
 
function curling($url){
	$ch = curl_init($url);
	curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt ($ch, CURLOPT_TIMEOUT, 4);
	$output = curl_exec($ch);
	curl_close($ch);
	return $output;
}
 
// cacheIt
//------------------------------------------------------------------------------------------
function cacheIt($output,$filename){
	$fp = fopen($filename, 'w');
	fwrite($fp, $output);
	fclose($fp);
}
 
// checkRateLimit
//------------------------------------------------------------------------------------------
function checkRateLimit(){
	$xml_link = 'https://api.twitter.com/1/account/rate_limit_status.json';
	$json = json_decode(curling($xml_link));
	if($json->remaining_hits > 0){
		return true;
	}
}

If it wasn't for the fact it was about to break we'd have happily left this as it was as the code had been refined over time to be pretty handy. It included things like a cache and also checked Twitter rate limits. I'm sure there's more that could have been done to refine it but it did the job.

Today

From midday our code now looks like this (we've not copied some of the child functions that haven't changed):

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
function outputTwitter($account,$num){
 
	require_once ('includes/codebird.php');
	$fileloc = "cache/twitter.html";
	$time = 3600; // An Hour
 
	if(!file_exists($fileloc) || time() - filemtime($fileloc) > $time){
		// Uses default application for all feeds
		Codebird::setConsumerKey('INSERT-CONSUMER-KEY','INSERT-CONSUMER-SECRET');	
		$cb = Codebird::getInstance();
		$cb->setToken('INSERT-ACCESS-TOKEN', 'INSERT-ACCESS-SECRET');
		$params = array('screen_name'=>$account,'count'=>$num);
		$tweets = $cb->statuses_userTimeline($params);
 
		$arrTweets = array();
		if($tweets->httpstatus == 200){
			foreach($tweets as $key => $value){
				if(is_int($key)){
					$item = array(
						'text' => $value->text,
						'created_at' => strtotime($value->created_at)
						);
					array_push($arrTweets, $item);
				}
			}
			$output_file = '';
			foreach($arrTweets as $value){
				$output_file .= $value['text'] . " :: " . $value['created_at'] . " :::: ";
			}
			cacheIt($output_file,$fileloc);
		}
	}
	if(file_exists($fileloc)){
		$input = file_get_contents($fileloc);
		$parts = explode(' :::: ', $input);
		if(empty($parts[count($parts)-1])) {
			unset($parts[count($parts)-1]);
		}
		$return = array();
		foreach($parts as $value){
			$object = new stdClass;
			$bits = explode(' :: ', $value);
			$tweet = preg_replace("#((http|https|ftp)://(S*?.S*?))(s|;|)|]|[|{|}|,|"|'|:|<|$|.s)#ie","'<a href="$1" target="_blank">$1</a>$4'",$bits[0]);
			$tweet = preg_replace("#((@)([A-z0-9_]*))#","<a href="http://twitter.com/$3" target="_blank">$1</a>$4",$tweet);
			if($bits[0]){ 
				$object->text = $tweet;
				$object->created = $bits[1];
			}
			array_push($return,$object);
		}
	}
	return $return;
 
}

This time we've used a library to help deal with the complexities of OAuth and save us some time. Where possible we like to use our own code but we're a little limited for time so we just needed a workable solution and CodeBird was one of the most lightweight libraries we came across.

This implementation also requires creating an application at dev.twitter.com to generate consumer keys and access tokens.

Much of the code works as it did before; the only differences are the change in how we access the information and the removal of us checking the rate limit.

Limiting the rate limit

When we came to changing this part of the script we found that there was a limit on checking the rate limit. That was a bit of a head scratcher. And as we checked the rate limit more than we actually got new tweets in the previous script we've just removed this.

It's somewhat helpful that v1.1 provides a higher limit than v1 so hopefully we won't hit the limit all that often anyway, especially given we only check once per hour, per domain.

Test, Test, Test

If you do look at our code above and want to use it feel free but there is a disclaimer…

We've only had this running on one site for a few hours. It's working great so far but if something goes wrong for you we're not responsible :P

Making your inbox more interesting
Looking to keep up to date, or find out those things we can’t mention on the blog? Then sign up to our semi-regular newsletter. Don’t worry, we won’t spam you.

Comments are closed.

Get in Touch

Things are better when they’re made simpler. That’s why the David Naylor blog is now just that; a blog. No sales pages, no contact form - just interesting* info about SEO.

If you’d like to find out more about the Digital Marketing services we do provide then head over to Bronco (our main company website) to get in touch.

Get in Touch Today * Interestingness not guaranteed
Part of the Bronco family