Warning: I wrote this blog in 2010. That is a long time ago, especially on the internet. My opinions may have changed since then. Technological progress may have made this information completely obsolete. Proceed with caution.
Earlier this week I was informed that Twitter will soon be ending its support for “BasicAuth” in the Twitter API, in favor of OAuth authentication. This affects me because I use the API to automatically post a “just blogged!” link to Twitter after every new blog post. Using BasicAuth, this was super simple:
function postStatus($status, $username, $password)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://www.twitter.com/statuses/update.xml');
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'status=' . urlencode($status));
curl_setopt($ch, CURLOPT_USERPWD, $username . ':' . $password);
return curl_exec($ch);
}
OAuth is a little more complicated, but I got it to work after about four or five hours of banging away it with the help of this article. Since I couldn’t find anywhere that this was described in detail, I decided I would document the whole process here on my blog. I don’t claim that this code is great, but it gets the job done. If you couldn’t care less about the workings of OAuth, and just want a give-me-teh-codez solution, then this is for you.
The first thing you have to do is register a new app. This sounds scary but it’s actually very easy. When filling out the form, note the following fields:
- Application Name: this is what will show up under your tweets. In my case, I chose “vacantnebula.com” since all tweets from my app are announcements of new posts on this site.
- Application Website: this is the URL that application name will link to.
- Application Type: I’m not sure if it matters, but I chose “client”.
- Default Access Type: you must select “read & write” to be able to update status (i.e. “write”).
After registering your application, you can view application details. Here you will see your consumer key and your consumer secret. You will need these keys later.
For a single-user application (which is what I’m describing), you will need to click on my access token. This will give you the access token (oauth_token) and access token secret (oauth_token_secret). Again, you will need these later.
And without further ado, here is the code:
<?php
class twitter
{
//FILL IN THESE VALUES!!
private $consumerKey = '???';
private $consumerSecret = '???';
private $oauthToken = '???';
private $oauthTokenSecret = '???';
/**
* Posts status to a twitter account. Returns true if successful, result
* of curl_getinfo() if failure.
*/
function postStatus($status)
{
return $this->apiCall('https://api.twitter.com/1/statuses/update.xml'
, array('status'=>$status));
}
//separate function to leave the door open to other API calls...
private function apiCall($url, $params)
{
$method = 'POST';
//postString covers what will *actually* be posted
$postString = $this->joinParams($params);
//now adding to $params other OAuth properties...
$params['oauth_nonce'] = sha1(time() . mt_rand());
$params['oauth_timestamp'] = time();
$params['oauth_signature_method'] = 'HMAC-SHA1';
$params['oauth_version'] = '1.0';
$params['oauth_consumer_key'] = $this->consumerKey;
$params['oauth_token'] = $this->oauthToken;
ksort($params); //IMPORTANT!
$paramString = $this->joinParams($params);
$signatureBaseString = $method
. '&' . rawurlencode($url)
. '&' . rawurlencode($paramString);
$signatureKey = $this->consumerSecret . '&' . $this->oauthTokenSecret;
$params['oauth_signature'] =
base64_encode(hash_hmac('sha1', $signatureBaseString, $signatureKey, true));
$authHeader = 'Authorization: OAuth realm=""';
foreach($params as $key => $val)
$authHeader .= ", $key=\"" . rawurlencode($val) . "\"";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postString);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //required for HTTPS URL
curl_setopt($ch, CURLOPT_HTTPHEADER, array($authHeader));
$content = curl_exec($ch);
$resultInfo = curl_getinfo($ch);
curl_close($ch);
if ($resultInfo['http_code'] == 200)
return true;
$resultInfo['content'] = $content;
return $resultInfo;
}
//Join key/value pairs together in url string format, encoding values.
private function joinParams($params)
{
$paramString = '';
foreach($params as $key => $val)
{
if($paramString !== '')
$paramString .= '&';
$paramString .= $key . '=' . rawurlencode($val);
}
return $paramString;
}
}
And I assume you know this, but to use the API it’d look like this:
$twitter = new twitter();
$result = $twitter->postStatus('hello world!');