Ben Dodson

Freelance iOS, Apple Watch, and Apple TV Developer

TwitterFollowers PHP Class - A Better Way To Track Followers, Quitters, and Returning Followers on Twitter

Over the past few months, there have been a number of web apps that have popped up with the task of feeding your ego (or indeed deflating it) by telling you exactly who is following you on Twitter and giving you pretty graphs to show you how your followers are increasing - some of them even go so far as to estimate how many followers you are likely to have in a weeks time! However, the key thing for me that is missing from Twitter is the ability to see who has stopped following you and also those people that stopped but are now following you again as you don't get email alerts from Twitter for these two things. This is a useful piece of information to have as it will let you know when people drop off and whether they are important (e.g. friends who don't care what you are talking about thus suggesting you should stop talking crap) or not (e.g. spam bots).

I did a bit of research and the only real web app to fulfill this need that I could find was the beautifully designed Qwitter. However, the problem with Qwitter is that it only gives you the details for one person with the idea being that you say "tell me when this username stops following me" - it's a little bit stalkerish in my opinion! Like any PHP developer, I decided that I could build my own little system to give me my Twitter ego boost and so have come up with the class below which you can all now take and use as you see fit.

Update: Turns out I was wrong about Qwitter as the username you put in to follow is supposed to be yours, not the person you want to watch when they leave you. They need to do better copywriting! In any case, the class below serves as a good demo of the public Twitter data and allows you to extend it the way you want.

Note: This won't work straight out of the box - I've put in a few comments which say "SQL Required". This is because you may well have your own schema (although I do provide one) and you may have your own framework or DB connection functions (I know I do). Once you've done those, just substitute the constants for your own details and it should all work

TwitterFollowers.class.php

<?php

/**
 * Crawls Twitter Followers and sends an email alert to show you who has started following, stopped following, and started re-following
 *
 * @author Ben Dodson
 **/
class TwitterFollowers
{
	// define constants
	const username	= 'bendodson';
	const email 	= 'ben@bendodson.com';
	const subject	= 'Twitter Updates';
	const from	= 'TwitterBot <twitter@bendodson.com>';
	
	// define internal variables
	protected $actualFollowers = array();
	protected $internalFollowers = array();
	protected $followerChanges = array();
	protected $now = '';
	
	function __construct()
	{
		$this->now = date('Y-m-d H:i:s');
		
		$json = file_get_contents('http://twitter.com/followers/ids/'.self::username.'.json');
		$this->actualFollowers = json_decode($json);
		$this->internalFollowers = $this->getInternalFollowers();
		
		foreach ($this->actualFollowers as $actualFollower) {
			if (!in_array($actualFollower, $this->internalFollowers)) {
				if ($this->getTweeter($actualFollower)) {
					$this->followerChanges['returning follower'][] = $actualFollower;
					/*
					--SQL REQUIRED--
					UPDATE TwitterFollowers SET start = $this->now, end = NULL WHERE id = $actualFollower
					*/
				} else {
					$this->followerChanges['new follower'][] = $actualFollower;
					/*
					--SQL REQUIRED--
					INSERT INTO TwitterFollowers (id) VALUES ($actualFollower)
					*/
				}
			}
		}
		
		foreach ($this->internalFollowers as $internalFollower) {
			if (!in_array($internalFollower, $this->actualFollowers)) {
				$this->followerChanges['stopped following'][] = $internalFollower;
				/*
				--SQL REQUIRED--
				UPDATE TwitterFollowers SET end = $this->now WHERE id = $internalFollower
				*/
			}
		}
		
		$this->sendEmail();	
	}
	
	protected function getInternalFollowers()
	{
		$data = array();
		$raw = 
		/*
		--SQL REQUIRED--
		SELECT id FROM TwitterFollowers WHERE end IS NULL
		*/
		foreach ($raw as $r) {
			$data[] = $r['id'];
		}
		return $data;
	}

	protected function getTweeter($id)
	{
		return
		/*
		--SQL REQUIRED--
		SELET * FROM TwitterFollowers WHERE id = $id LIMIT 1
		*/		
	}
	
	protected function getTweeterDetails($id)
	{
		$json = file_get_contents('http://twitter.com/users/show/'.$id.'.json');
		$tweeter = json_decode($json);
		return $tweeter->name . ' ('.$tweeter->screen_name . ')';
	}
	
	protected function sendEmail()
	{
		$to      = self::email;
		$subject = self::subject;
		$headers = 'From: ' . self::from . "\r\n" . 'Reply-To: ' . self::from;

		$message = 'Hi,' . "\r\n\r\n";
		$message .= 'Here are your Twitter Updates:' . "\r\n";
		
		if (count($this->followerChanges) > 0) {
			foreach ($this->followerChanges as $changeType => $change) {
				$message .= "\r\n" . '--'.strtoupper($changeType).'--' . "\r\n\r\n";
				foreach ($change as $tweeter) {
					$message .= '*' . $this->getTweeterDetails($tweeter) . "\r\n";
				}
			}
		} else {
			$message .= "\r\n" . '--NO UPDATES FOUND--' . "\r\n";
		}
		
		mail($to, $subject, $message, $headers);
	}

}

?>

MySQL Database Schema

CREATE TABLE IF NOT EXISTS `TwitterFollowers` (
  `id` int(20) NOT NULL,
  `start` timestamp NOT NULL default CURRENT_TIMESTAMP,
  `end` timestamp NULL default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

How does it work?

First of all, you will need to substitute the SQL sections for your own particular schema and database functions. Once you've done that, alter the class constants so that they are your own username and the email address you want to send your updates to. Finally, set up a CRON job so that it runs at a certain point every day. I currently have mine set to run at 9am every morning but I may well change it to run every time I post a tweet as then I'd be able to see which tweet had made people start or stop following me.

The script works by checking the publicly accessible JSON feed of your followers and getting all of their IDs. I say it's publicly accessible, but I don't think it is if you have protected your updates which will of course cause problems! Once it has all of the IDs, it checks this against the IDs stored in your database - if there aren't any then everyone will show up as following you on the first run. If it finds an ID in your database that isn't in your JSON string then you've been dumped! Conversely, if it finds an ID in the JSON string but not in the DB then, congratulations, you've got a new follower. The final instance is if it finds an ID in the JSON string that is in the DB but has an end datetime assigned to it. This means the person was following you, stopped, and has now decided to re-follow you.

The whole lot then gets packaged up and emailed to you with each section broken down so you can read it clearly. In order to do this, it looks up each ID that goes into the email against that persons publicly available Twitter information to give you both their "real name" and "username".

Known Problems

  • I don't think it will work if you have your updates set to hidden.
  • If one of your followers gets banned from Twitter, then their name won't show up in the email (it will just be blank)
  • This script won't work if you have more than 5000 followers - this is because that is the maximum result set from the JSON string. You'd need to add paging information to get more than 5000 although this would be fairly easily. Alas I don't have that many followers to be able to test that out!

Conclusion

So now you can easily (if you know PHP) get updates on all your Twitter followers and non-followers. Feel free to use all the above code and modify to your hearts content - if you found it to be useful, then please leave a comment below. Oh, and I couldn't possibly write a post about Twitter without reminding you that you can follow me @bendodson ;)

Mastering phpMyAdmin 3.1 for Effective MySQL Management » « Getting Xbox Live Achievements Data: Part 2 - The AppleScript Solution