-
Notifications
You must be signed in to change notification settings - Fork 0
/
gfl.php
120 lines (95 loc) · 3.37 KB
/
gfl.php
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
<?php
include 'vendor/autoload.php';
use Abraham\TwitterOAuth\TwitterOAuth;
use Dotenv\Dotenv;
const PAGINATION_TOKENS_FILE = 'pagination_tokens.csv';
// read username from params
if (empty($argv[1])) die("Please enter username\n");
// Get username from first argument
$name = str_replace('@', '', $argv[1]);
echo "getting followers of user $name ... \n";
// load environmental variables
$dotenv = Dotenv::createUnsafeImmutable(__DIR__);
$dotenv->load();
// set Twitter api connection
$connection = new TwitterOAuth(
getenv('API_KEY'),
getenv('API_KEY_SECRET'),
getenv('ACCESS_TOKEN'),
getenv('ACCESS_TOKEN_SECRET')
);
$connection->setApiVersion('2');
// get user id
$response = $connection->get("users/by/username/$name");
$id_str = $response->data->id ?? ''; // user_id
if (!$id_str) die('no such user, or wrong credentials for api connection');
// set Twitter api connection
$connection = new TwitterOAuth(
getenv('API_KEY'),
getenv('API_KEY_SECRET'),
getenv('ACCESS_TOKEN'),
getenv('ACCESS_TOKEN_SECRET')
);
$connection->setApiVersion('2');
outputFollowers($id_str, $connection);
/**
* Recursively output followers into twitter_users_data table
*/
function outputFollowers(string $id_str, TwitterOAuth $connection, string $next_token = ''): void
{
$options = [
'max_results' => 1000,
'user.fields' => 'name,description',
];
if (!empty($next_token)) {
$options['pagination_token'] = $next_token;
echo PHP_EOL;
} elseif ($next_token = getCachedNextToken($id_str)) {
echo "resuming from cache ...\n";
$options['pagination_token'] = $next_token;
echo PHP_EOL;
}
$response = $connection->get("users/$id_str/followers", $options); // that gives 1000 results and next token
// wait for 15 minutes on rate limit
if (isset($response->status) && $response->status == 429) {
echo "\nRate limit. Waiting 15 minutes...\n";
sleep(900);
outputFollowers($id_str, $connection, $next_token);
return;
}
foreach ($response->data as $data) echo $data->name . PHP_EOL;
// call for the next page till pagination ends
if (!empty($response->meta->next_token)) {
saveNextToken($id_str, $response->meta->next_token);
outputFollowers($id_str, $connection, $response->meta->next_token);
}
removeNextTokens($id_str); // remove next tokens for user from db when we got all the followers
}
/**
* Save API pagination next page token
*/
function saveNextToken(string $id_str, string $next_token): void
{
removeNextTokens($id_str); // remove if we already have pagination for user
// Save to file
file_put_contents(PAGINATION_TOKENS_FILE, "$id_str,$next_token");
}
/**
* Remove API pagination tokens for user
*/
function removeNextTokens(string $id_str): void
{
if (!file_exists(PAGINATION_TOKENS_FILE)) return;
$file = file(PAGINATION_TOKENS_FILE);
$file = array_filter($file, fn($line) => !str_contains($line, "$id_str,"));
file_put_contents(PAGINATION_TOKENS_FILE, $file);
}
function getCachedNextToken(string $id_str): ?string
{
if (!file_exists(PAGINATION_TOKENS_FILE)) return null;
$file = file(PAGINATION_TOKENS_FILE);
$file = array_filter($file, fn($line) => str_contains($line, "$id_str,"));
if (!count($file)) return null;
$token = explode(',', $file[array_key_last($file)]);
return $token[1];
}