Created
November 2, 2020 16:20
-
-
Save pingpoli/ae6c140001d82a5e94d772d7222f37ac to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// based on https://stackoverflow.com/questions/12684765/twitter-api-returns-error-215-bad-authentication-data | |
require_once( "mysql_config.php" ); | |
define( 'ACCESS_TOKEN' , 'YOUR_ACCESS_TOKEN' ); | |
define( 'ACCESS_TOKEN_SECRET' , 'YOUR_ACCESS_TOKEN_SECRET' ); | |
define( 'CONSUMER_KEY' , 'YOUR_CONSUMER_KEY' ); | |
define( 'CONSUMER_KEY_SECRET' , 'YOUR_CONSUMER_KEY_SECRET' ); | |
// get the follower ids | |
// query parameters | |
$query = array( | |
'screen_name' => 'YOUR_TWITTER_USERNAME', | |
'stringify_ids' => true | |
); | |
$result = twitterRequest( "https://api.twitter.com/1.1/followers/ids.json" , "GET" , $query ); | |
$json = json_decode( $result ); | |
if ( isset( $json->ids ) ) | |
{ | |
// build a comma seperated list of all follower ids | |
$followerIDs = ""; | |
foreach ( $json->ids as $id ) | |
{ | |
$followerIDs .= $id.","; | |
} | |
$followerIDs = rtrim( $followerIDs , "," ); | |
// mysql connect | |
$mysql = new mysqli( MYSQL_HOST , MYSQL_USER , MYSQL_PASS , MYSQL_DATABASE ); | |
if ( $mysql->connect_errno ) error_log( "Failed to connect to MySQL: ".$mysql->connect_error.PHP_EOL ); | |
$mysql->set_charset( "utf8mb4" ); | |
// because this is executed at 2 am, the data is for yesterday, which means the real yesterday is the two days ago | |
$yesterdaysDataFound = false; | |
$yesterdaysData = ""; | |
$sql = "SELECT ids FROM followers WHERE `date`=SUBDATE(CURDATE(),2)"; | |
if ( $result = lmysql_select( $mysql , $sql , "" ) ) | |
{ | |
if ( $result->num_rows > 0 ) | |
{ | |
$row = $result->fetch_assoc(); | |
$yesterdaysDataFound = true; | |
$yesterdaysData = $row['ids']; | |
} | |
} | |
$numberOfFollowers = count( $json->ids ); | |
$new = ""; | |
$unfollowed = ""; | |
if ( $yesterdaysDataFound ) | |
{ | |
$today = explode( "," , $followerIDs ); | |
$yesterday = explode( "," , $yesterdaysData ); | |
// new followers are people that are in the data from today but not in the data from yesterday | |
for ( $i = 0 ; $i < count( $today ) ; ++$i ) | |
{ | |
$newFollower = true; | |
for ( $j = 0 ; $j < count( $yesterday ) ; ++$j ) | |
{ | |
if ( $today[$i] == $yesterday[$j] ) | |
{ | |
$newFollower = false; | |
break; | |
} | |
} | |
if ( $newFollower ) | |
{ | |
$new .= $today[$i].","; | |
} | |
} | |
// unfollowers are people that are in yesterdays data but not in todays | |
for ( $i = 0 ; $i < count( $yesterday ) ; ++$i ) | |
{ | |
$hasUnfollowed = true; | |
for ( $j = 0 ; $j < count( $today ) ; ++$j ) | |
{ | |
if ( $yesterday[$i] == $today[$j] ) | |
{ | |
$hasUnfollowed = false; | |
break; | |
} | |
} | |
if ( $hasUnfollowed ) | |
{ | |
$unfollowed .= $yesterday[$i].","; | |
} | |
} | |
} | |
$new = rtrim( $new , "," ); | |
$unfollowed = rtrim( $unfollowed , "," ); | |
echo "new: ".$new."<br>"; | |
echo "unfollowed: ".$unfollowed."<br>"; | |
$newUsernames = ""; | |
$unfollowersUsernames = ""; | |
// get new followers usernames | |
if ( $new != "" ) | |
{ | |
// query parameters | |
$query = array( | |
'user_id' => $new | |
); | |
$newUsernamesResult = twitterRequest( "https://api.twitter.com/1.1/users/lookup.json" , "POST" , $query ); | |
$jsonUserObjects = json_decode( $newUsernamesResult ); | |
foreach ( $jsonUserObjects as $jsonUserObject ) | |
{ | |
if ( isset( $jsonUserObject->screen_name ) ) | |
{ | |
$newUsernames .= $jsonUserObject->screen_name; | |
$newUsernames .= ","; | |
} | |
} | |
$newUsernames = rtrim( $newUsernames , "," ); | |
} | |
// get unfollowers usernames | |
if ( $unfollowed != "" ) | |
{ | |
// query parameters | |
$query = array( | |
'user_id' => $unfollowed | |
); | |
$newUsernamesResult = twitterRequest( "https://api.twitter.com/1.1/users/lookup.json" , "POST" , $query ); | |
$jsonUserObjects = json_decode( $newUsernamesResult ); | |
foreach ( $jsonUserObjects as $jsonUserObject ) | |
{ | |
if ( isset( $jsonUserObject->screen_name ) ) | |
{ | |
$unfollowersUsernames .= $jsonUserObject->screen_name; | |
$unfollowersUsernames .= ","; | |
} | |
} | |
$unfollowersUsernames = rtrim( $unfollowersUsernames , "," ); | |
} | |
echo "<br>newUsernames: ".$newUsernames."<br>"; | |
echo "<br>unfollowersUsernames: ".$unfollowersUsernames."<br>"; | |
$sql = "INSERT INTO followers ( `date` , `followers` , `ids` , `new` , `unfollowed` ) VALUES ( SUBDATE(NOW(),1) , ? , ? , ? , ? )"; | |
if ( !lmysql_execute( $mysql , $sql , "isss" , $numberOfFollowers , $followerIDs , $newUsernames , $unfollowersUsernames ) ) | |
{ | |
echo "failed to insert<br>"; | |
} | |
} | |
function twitterRequest( $url , $method , $query ) | |
{ | |
// oauth parameters | |
$oauth = array( | |
'oauth_consumer_key' => CONSUMER_KEY, | |
'oauth_token' => ACCESS_TOKEN, | |
'oauth_nonce' => (string)mt_rand(), | |
'oauth_timestamp' => time(), | |
'oauth_signature_method' => 'HMAC-SHA1', | |
'oauth_version' => '1.0' | |
); | |
// must be encoded before sorting | |
$oauth = array_map( "rawurlencode" , $oauth ); | |
$query = array_map( "rawurlencode" , $query ); | |
$arr = array_merge( $oauth , $query ); // combine the values then sort | |
asort( $arr ); // secondary sort (value) | |
ksort( $arr ); // primary sort (key) | |
// http_build_query automatically encodes, but the parameters are already encoded, and must be by this point, so we undo the encoding step | |
$querystring = urldecode( http_build_query( $arr , '' , '&' ) ); | |
// mash everything together for the text to hash | |
$base_string = $method."&".rawurlencode($url)."&".rawurlencode($querystring); | |
// same with the key | |
$key = rawurlencode(CONSUMER_KEY_SECRET)."&".rawurlencode(ACCESS_TOKEN_SECRET); | |
// generate the hash, which is the oauth signature | |
$oauth['oauth_signature'] = rawurlencode( base64_encode( hash_hmac( 'sha1' , $base_string , $key , true ) ) ); | |
// some query parameters include commas and they don't work when the parameter is urlencoded above, so decode it here and use it raw, WARNING: this may be a little hacky | |
if ( $method == "GET" ) | |
{ | |
// build the GET parameters | |
$url .= "?"; | |
while ( $element = current($query) ) | |
{ | |
$url .= key($query)."=".urldecode($element)."&"; | |
next($query); | |
} | |
$url = rtrim( $url , "&" ); | |
} | |
else | |
{ | |
// build the POST parameters | |
$postParameters = ""; | |
while ( $element = current($query) ) | |
{ | |
$postParameters .= key($query)."=".urldecode($element)."&"; | |
next($query); | |
} | |
$postParameters = rtrim( $postParameters , "&" ); | |
} | |
// this is the full value of the authorization line | |
$auth = "OAuth ".urldecode( http_build_query( $oauth , '' , ', ' ) ); | |
// curl options | |
$options = array( CURLOPT_HTTPHEADER => array("Authorization: $auth"), | |
CURLOPT_HEADER => false, | |
CURLOPT_URL => $url, | |
CURLOPT_RETURNTRANSFER => true, | |
CURLOPT_SSL_VERIFYPEER => false); | |
// add the POST parameters | |
if ( $method == "POST" ) | |
{ | |
$options[CURLOPT_POSTFIELDS] = $postParameters; | |
} | |
// curl | |
$curl = curl_init(); | |
curl_setopt_array( $curl , $options ); | |
$result = curl_exec( $curl ); | |
curl_close( $curl ); | |
if ( !$result ) | |
{ | |
echo "twitter request failed".PHP_EOL; | |
return false; | |
} | |
return $result; | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment