'twitter.com', 'api' => 'api.twitter.com', 'search' => 'search.twitter.com', 'tiny_url' => 'tinyurl.com', ); private function __construct() {} public static function instance() { if (!isset(self::$instance)) { $className = __CLASS__; self::$instance = new $className; } return self::$instance; } /** * Generic getter * * @param $attribute * string attribute name to return * @return * mixed value or NULL */ public function get($attribute) { if (array_key_exists($attribute, $this->attributes)) { return $this->attributes[$attribute]; } } /** * Generic setter * @param $attribute * string attribute name to be set * @param $value * mixed value */ public function set($attribute, $value) { if (array_key_exists($attribute, $this->attributes)) { $this->attributes[$attribute] = $value; } } } /** * Exception handling class. */ class TwitterException extends Exception {} /** * Primary Twitter API implementation class * Supports the full REST API for twitter. */ class Twitter { /** * @var $format API format to use: can be json or xml */ protected $format = 'json'; /** * @var $source the twitter api 'source' */ protected $source = 'drupal'; /** * @var $username Twitter username to use for authenticated requests */ protected $username; /** * @var $password Twitter password to use for authenticated requests */ protected $password; /** * Constructor for the Twitter class */ public function __construct($username = NULL, $password = NULL) { if (!empty($username) && !empty($password)) { $this->set_auth($username, $password); } } /** * Set the username and password */ public function set_auth($username, $password) { $this->username = $username; $this->password = $password; } /** * Get an array of TwitterStatus objects from an API endpoint */ protected function get_statuses($path, $params = array(), $use_auth = FALSE) { $values = $this->call($path, $params, 'GET', $use_auth); // Check on successfull call if ($values) { $statuses = array(); foreach ($values as $status) { $statuses[] = new TwitterStatus($status); } return $statuses; } // Call might return FALSE , e.g. on failed authentication else { // As call allready throws an exception, we can return an empty array to // break no code. return array(); } } /** * Fetch the public timeline * * @see http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-statuses-public_timeline */ public function public_timeline() { return $this->get_statuses('statuses/public_timeline'); } /** * Fetch the authenticated user's friends timeline * * @see http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-statuses-friends_timeline */ public function friends_timeline($params = array()) { return $this->get_statuses('statuses/friends_timeline', $params, TRUE); } /** * Fetch a user's timeline * * @see http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-statuses-user_timeline */ public function user_timeline($id, $params = array(), $use_auth = FALSE) { if (is_numeric($id)) { $params['user_id'] = $id; } else { $params['screen_name'] = $id; } return $this->get_statuses('statuses/user_timeline', $params, $use_auth); } /** * * @see http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-statuses-mentions */ public function mentions($params = array()) { return $this->get_statuses('statuses/mentions', $params, TRUE); } /** * * @see http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-statuses%C2%A0update */ public function status_update($status, $params = array()) { $params['status'] = $status; if ($this->source) { $params['source'] = $this->source; } $values = $this->call('statuses/update', $params, 'POST', TRUE); return new TwitterStatus($values); } /** * * @see http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-users%C2%A0show */ public function users_show($id, $use_auth = TRUE) { $params = array(); if (is_numeric($id)) { $params['user_id'] = $id; } else { $params['screen_name'] = $id; } $values = $this->call('users/show', $params, 'GET', $use_auth); return new TwitterUser($values); } /** * * @see http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-account%C2%A0verify_credentials */ public function verify_credentials() { $values = $this->call('account/verify_credentials', array(), 'GET', TRUE); if (!$values) { return FALSE; } return new TwitterUser($values); } /** * Method for calling any twitter api resource */ public function call($path, $params = array(), $method = 'GET', $use_auth = FALSE) { $url = $this->create_url($path); try { if ($use_auth) { $response = $this->auth_request($url, $params, $method); } else { $response = $this->request($url, $params, $method); } } catch (TwitterException $e) { watchdog('twitter', '!message', array('!message' => $e->__toString()), WATCHDOG_ERROR); return FALSE; } if (!$response) { return FALSE; } return $this->parse_response($response); } /** * Perform an authentication required request. */ protected function auth_request($path, $params = array(), $method = 'GET') { if (empty($this->username) || empty($this->password)) { return false; } return $this->request($path, $params, $method, TRUE); } /** * Perform a request */ protected function request($url, $params = array(), $method = 'GET', $use_auth = FALSE) { $data = ''; if (count($params) > 0) { if ($method == 'GET') { $url .= '?'. http_build_query($params, '', '&'); } else { $data = http_build_query($params, '', '&'); } } $headers = array(); if ($use_auth) { $headers['Authorization'] = 'Basic '. base64_encode($this->username .':'. $this->password); $headers['Content-type'] = 'application/x-www-form-urlencoded'; } $response = drupal_http_request($url, array('headers' => $headers, 'method' => $method, 'data' => $data)); if (!isset($response->error)) { return $response->data; } else { $error = $response->error; $data = $this->parse_response($response->data); if (isset($data['error'])) { $error = $data['error']; } throw new TwitterException($error); } } protected function parse_response($response, $format = NULL) { if (empty($format)) { $format = $this->format; } switch ($format) { case 'json': // http://drupal.org/node/985544 - json_decode large integer issue $length = strlen(PHP_INT_MAX); $response = preg_replace('/"(id|in_reply_to_status_id)":(\d{' . $length . ',})/', '"\1":"\2"', $response); return json_decode($response, TRUE); } } protected function create_url($path, $format = NULL) { if (is_null($format)) { $format = $this->format; } $conf = TwitterConf::instance(); $url = 'http://'. $conf->get('api') .'/'. $path; if (!empty($format)) { $url .= '.'. $this->format; } return $url; } } /** * A class to provide OAuth enabled access to the twitter API */ class TwitterOAuth extends Twitter { protected $signature_method; protected $consumer; protected $token; public function __construct($consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL) { $this->signature_method = new OAuthSignatureMethod_HMAC_SHA1(); $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret); if (!empty($oauth_token) && !empty($oauth_token_secret)) { $this->token = new OAuthConsumer($oauth_token, $oauth_token_secret); } } public function get_request_token() { $url = $this->create_url('oauth/request_token', ''); try { $response = $this->auth_request($url); } catch (TwitterException $e) { } parse_str($response, $token); $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']); return $token; } public function get_authorize_url($token) { $url = $this->create_url('oauth/authorize', ''); $url.= '?oauth_token=' . $token['oauth_token']; return $url; } public function get_authenticate_url($token) { $url = $this->create_url('oauth/authenticate', ''); $url.= '?oauth_token=' . $token['oauth_token']; return $url; } public function get_access_token() { $url = $this->create_url('oauth/access_token', ''); try { $response = $this->auth_request($url); } catch (TwitterException $e) { } parse_str($response, $token); $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']); return $token; } public function auth_request($url, $params = array(), $method = 'GET') { $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, $method, $url, $params); $request->sign_request($this->signature_method, $this->consumer, $this->token); switch ($method) { case 'GET': return $this->request($request->to_url()); case 'POST': return $this->request($request->get_normalized_http_url(), $request->get_parameters(), 'POST'); } } } /** * Twitter search is not used in this module yet */ class TwitterSearch extends Twitter { public function search($params = array()) {} } /** * Class for containing an individual twitter status. */ class TwitterStatus { /** * @var created_at */ public $created_at; public $id; public $text; public $source; public $truncated; public $favorited; public $in_reply_to_status_id; public $in_reply_to_user_id; public $in_reply_to_screen_name; public $user; /** * Constructor for TwitterStatus */ public function __construct($values = array()) { $this->created_at = $values['created_at']; $this->id = $values['id']; $this->text = $values['text']; $this->source = $values['source']; $this->truncated = $values['truncated']; $this->favorited = $values['favorited']; $this->in_reply_to_status_id = $values['in_reply_to_status_id']; $this->in_reply_to_user_id = $values['in_reply_to_user_id']; $this->in_reply_to_screen_name = $values['in_reply_to_screen_name']; if (isset($values['user'])) { $this->user = new TwitterUser($values['user']); } } } class TwitterUser { public $id; public $screen_name; public $name; public $location; public $description; public $followers_count; public $friends_count; public $statuses_count; public $favourites_count; public $url; public $protected; public $profile_image_url; public $profile_background_color; public $profile_text_color; public $profile_link_color; public $profile_sidebar_fill_color; public $profile_sidebar_border_color; public $profile_background_image_url; public $profile_background_tile; public $verified; public $created_at; public $created_time; public $utc_offset; public $status; protected $password; protected $oauth_token; protected $oauth_token_secret; public function __construct($values = array()) { $this->id = $values['id']; $this->screen_name = $values['screen_name']; $this->name = $values['name']; $this->location = $values['location']; $this->description = $values['description']; $this->url = $values['url']; $this->followers_count = $values['followers_count']; $this->friends_count = $values['friends_count']; $this->statuses_count = $values['statuses_count']; $this->favourites_count = $values['favourites_count']; $this->protected = $values['protected']; $this->profile_image_url = $values['profile_image_url']; $this->profile_background_color = $values['profile_background_color']; $this->profile_text_color = $values['profile_text_color']; $this->profile_link_color = $values['profile_link_color']; $this->profile_sidebar_fill_color = $values['profile_sidebar_fill_color']; $this->profile_sidebar_border_color = $values['profile_sidebar_border_color']; $this->profile_background_image_url = $values['profile_background_image_url']; $this->profile_background_tile = $values['profile_background_tile']; $this->verified = $values['verified']; $this->created_at = $values['created_at']; if ($values['created_at'] && $created_time = strtotime($values['created_at'])) { $this->created_time = $created_time; } $this->utc_offset = $values['utc_offset']?$values['utc_offset']:0; if (isset($values['status'])) { $this->status = new TwitterStatus($values['status']); } } public function get_auth() { return array('password' => $this->password, 'oauth_token' => $this->oauth_token, 'oauth_token_secret' => $this->oauth_token_secret); } public function set_auth($values) { $this->oauth_token = isset($values['oauth_token'])?$values['oauth_token']:NULL; $this->oauth_token_secret = isset($values['oauth_token_secret'])?$values['oauth_token_secret']:NULL; } }