I am maintaining a website that aggregate a large number of Twitter accounts’ tweets. For this purpose we’ve been given one of the accounts with the high API request rate limit – usually it is possible to call the Twitter API’s 150 times every hour. We have a rate limit of 20.000 hourly requests and we use most of them to keep up a near real time picture of the activity of the user base.
Recently Twitter disabled regular basic HTTP authentication supporting only OAuth – which generally is a good thing, In this case we simply read the RSS-version of the user_timeline and OAuth seems overkill for reading a simple public time line. Aaaanyways – we are using PHP with cURL multi and OAuth introduces a bit of extra code. Sure – there are plenty of OAuth API’s and OAuth API’s for Twitter out there, but the specific combination of PHP cURL multi and GET’ing user_timelines required a combination of Google’ing and a bit of guesswork.
Preparations
- First Register your application with Twitter – You’ll need a couple of tokens and secrets from your app-page and from the specific token page.
- If you need to make more than 150 requests per hour, apply for whitelisting here. It’ll take a while for Twitter to process your request.
- Make sure you have cURL for PHP installed
Specifically preparing the GET connections for cURL presented a challenge – this piece of code did the trick for us:
<?php
// $url_array is an array of Twitter RSS-feed URL's that we need to read
$mh = curl_multi_init();
foreach($url_array as $i => $item) {
// Keys and secrets from http://dev.twitter.com/apps/
$consumer_secret = '<get your own from http://dev.twitter.com/apps/_your_app_id_/>';
$token_secret = '<get your own from http://dev.twitter.com/apps/_your_app_id_/my_token>';
// Build ud an array of OAuth parameters
$params = Array();
$params['oauth_consumer_key'] = '<get your own from http://dev.twitter.com/apps/_your_app_id_/>';
$params['oauth_token'] = '<get your own from http://dev.twitter.com/apps/_your_app_id_/my_token>';
$params['oauth_signature_method'] = 'HMAC-SHA1';
$thetime = time();
$params['oauth_timestamp'] = $thetime;
$params['oauth_nonce'] = SHA1($thetime);
$params['oauth_version'] = '1.0';
// Sort the array alphabetically
ksort($params);
// Build the paramter string for the GET request
$concatenatedParams = '';
foreach($params as $k => $v)
{
$k = urlencode($k);
$v = urlencode($v);
$concatenatedParams .= "{$k}={$v}&";
}
$unencodedParams = substr($concatenatedParams,0,-1);
// URL-encode the parameters for signature use
$concatenatedParams = urlencode(substr($concatenatedParams,0,-1));
$signatureBaseString = "GET&".urlencode($item['url'])."&".$concatenatedParams;
$params['oauth_signature'] = base64_encode( hash_hmac('sha1', $signatureBaseString, $consumer_secret."&".$token_secret, true) );
// Initiate a new cURL connection and set up it's URL
$conn[$i] = curl_init();
curl_setopt($conn[$i], CURLOPT_URL, $item['url'] . '?' . $unencodedParams);
curl_setopt($conn[$i], CURLINFO_HEADER_OUT, 1);
// Build the HTTP header for the request
$curlheader = Array();
$curlheader[]='Content-Type: application/x-www-form-urlencoded';
$curlheader[] = 'Authorization: OAuth';
foreach($params as $ky=>$va) {
$curlheader[] = "$ky=$va,\n";
}
// Initiate a new cURL connection and assign URL + HTTP header to it
$conn[$i] = curl_init($item['url']);
curl_setopt($conn[$i], CURLOPT_HTTPHEADER, $curlheader);
curl_setopt($conn[$i], CURLOPT_HTTPGET, 1);
// Add the connection to the cURL multi handle
curl_multi_add_handle ($mh,$conn[$i]);
}
// Now execute curl_multi_exec on the $mh handle