Track unfollower on Twitter

Sometimes, I'm curious about who unfollow me on Twitter.
So I had the idea, to write a little script to save all my followers in a simple text file line by line and then, I use Git to see the changes since the last time I executed it.

So far so good. I started with the composer package abraham/twitteroauth .

The most popular PHP library for use with the Twitter OAuth REST API.

It's an easy to use library when you want to interact with Twitter's Rest API. All what you need is a registered App on Twitter. You can create a folder somewhere and type composer require abraham/twitteroauth.
Now create a file like follower.php and write this:

<?php

use Abraham\TwitterOAuth\TwitterOAuth;                                                                                  
                                                                                                                        
require "vendor/autoload.php";

$api = new TwitterOAuth(
	CONSUMER_KEY, 
	CONSUMER_SECRET, 
	ACCESS_TOKEN, 
	ACCESS_TOKEN_SECRET
);

That's it. $api-> gives you now a lot of methods to interact with the Twitter's REST Api.

A list of my followers

I searched in Twitter's REST API documentation and the only thing I found was the the possibility to get a list of IDs who follow me. GET followers/ids.

Returns a cursored collection of user IDs for every user following the specified user. At this time, results are ordered with the most recent following first — however, this ordering is subject to unannounced change and eventual consistency issues. Results are given in groups of 5,000 user IDs and multiple "pages" of results can be navigated through using the next_cursor value in subsequent requests. See Using cursors to navigate collections for more information.
This method is especially powerful when used in conjunction with GET users / lookup, a method that allows you to convert user IDs into full user objects in bulk.

That looks good. With the list of the IDs I can use another endpoint to fetch the correct usernames to the IDs.
I don't have 5000 followers, so I can ignore the cursored stuff.

Fetch all IDs who follow me

$userIds = $api->get("followers/ids", [
    'screen_name' => 'mnlwldr',
    'count'       => 5000,
]);

It works. I get a response with a long list of IDs who follow me. Now I try to call the other endpoint to get the correct usernames because it's easier to read mnlwldr than 14367681! The GET followers/ids documentation gave me already the hint to use GET users/lookup.

Returns fully-hydrated user objects for up to 100 users per request, as specified by comma-separated values passed to the user_id and/or screen_name parameters. This method is especially useful when used in conjunction with collections of user IDs returned from GET friends / ids and GET followers / ids.

Ok, that means I can send up to 100 IDs per request. I chunk the array of IDs I got from GET followers/ids with PHP's array_chunk() method and use implode() to generate a comma seperated list of IDs.

/* chunk the array in smaller pieces of 100 Ids */
$chunkedUserIds	= array_chunk($userIds, 100);

foreach($chunkedUserIds as $chunk) {

	/* call the users/lookup endpoint with comma seperated list of IDs */
	$profiles = $api->get('users/lookup', [
		'user_id' => implode(',', $chunk)
	]);

	/* Iterate over the response and print the name line by line */
	foreach($profiles as $profile) {
		print $profile->screen_name.PHP_EOL;
	}
}

Now I have two posibilities to wrote this in a text file.

I can pipe the output into a file with <code>php follower.php > follower.txt</code>
or I do it in the script

/* chunk the array in smaller pieces of 100 Ids */                                                                         
$chunkedUserIds   = array_chunk($userIds, 100);                                                                            

/* 'w' place the file pointer at the beginning of the file and truncate the file to zero length */
$fp = fopen('follower.txt', 'w'); 

foreach($chunkedUserIds as $chunk) {                                                                                       
   $profiles = $api->get('users/lookup', [                                                                                 
      'user_id' => implode(',', $chunk)                                                                                    
   ]);                                                                                                                     
   foreach($profiles as $profile) {                                                                                        
   	fwrite($fp, $user->screen_name . PHP_EOL);
	}                                                                                                                       
}                                                                                                                          
/* close the file */
fclose($fp);

Everytime we execute the script now, follower.txt will be updated and we can use git diff to see the changes.

The whole script

<?php

use Abraham\TwitterOAuth\TwitterOAuth;

require "vendor/autoload.php";

$api = new TwitterOAuth(
	CONSUMER_KEY, 
	CONSUMER_SECRET, 
	ACCESS_TOKEN, 
	ACCESS_TOKEN_SECRET
);

$userIds = $api->get("followers/ids", [
    'screen_name' => 'mnlwldr',
    'count'       => 5000,
]);

                                                                                                        
/* chunk the array in smaller pieces of 100 Ids */                                                                         
$chunkedUserIds   = array_chunk($userIds, 100);                                                                            
$fp = fopen('follower.txt', 'w');                                                                                                         

foreach($chunkedUserIds as $chunk) {                                                                                       
	$profiles = $api->get('users/lookup', [
		'user_id' => implode(',', $chunk)                                                                                    
	]);                                                                                                                     
	foreach($profiles as $profile) {                                                                                        
		fwrite($fp, $user->screen_name . PHP_EOL);
	}                                                                                                                       
}                                                                                                                          
fclose($fp);

I'm a huge fan of Laravel's collections. To refactor this to collections, all we need is tightenco/collect.
composer require tightenco/collect

<?php

use Abraham\TwitterOAuth\TwitterOAuth;
use Tightenco\Collect\Support\Collection;

require "vendor/autoload.php";

$api = new TwitterOAuth(
    CONSUMER_KEY,
    CONSUMER_SECRET,
    ACCESS_TOKEN,
    ACCESS_TOKEN_SECRET
);

$userIds = $api->get("followers/ids", [
    'screen_name' => 'mnlwldr',
    'count'       => 5000,
]);
$fp      = fopen('follower.txt', 'w');

collect($userIds->ids)
    ->chunk(100)
    ->flatMap(function (Collection $userIds) use ($api) {
        return $api->get('users/lookup', [
            'user_id' => $userIds->implode(','),
        ]);
    })->each(function (stdClass $user) use ($fp) {
        fwrite($fp, $user->screen_name . PHP_EOL);
    });
fclose($fp);

That’s it. You can commit and push the follower.txt in a github repo and do whatever you want :)