diff --git a/drupal/sites/all/modules/contrib/twitter_pull/twitter_pull.class.inc b/drupal/sites/all/modules/contrib/twitter_pull/twitter_pull.class.inc index 8aa1619..7147bd7 100644 --- a/drupal/sites/all/modules/contrib/twitter_pull/twitter_pull.class.inc +++ b/drupal/sites/all/modules/contrib/twitter_pull/twitter_pull.class.inc @@ -7,9 +7,12 @@ class twitter_puller { - var $twitkey; - var $num_items; - var $tweets; + private $twitkey; + private $num_items; + private $consumer_key; + private $consumer_secret; + private $oauth_token; + private $oauth_token_secret; /** * @param $twitkey @@ -17,16 +20,19 @@ class twitter_puller { * @param $num_items * maximum number of tweets to pull from Twitter. */ - function __construct($twitkey, $num_items) { + public function __construct($twitkey, $num_items) { $this->twitkey = $twitkey; $this->num_items = $num_items; + $this->consumer_key = variable_get('consumer_key', ''); + $this->consumer_secret = variable_get('consumer_secret', ''); + $this->oauth_token = variable_get('oauth_token', ''); + $this->oauth_token_secret = variable_get('oauth_token_secret', ''); $this->check_arguments(); - } - function check_arguments() { + private function check_arguments() { if (empty($this->twitkey) || drupal_strlen($this->twitkey) < 2) { throw new Exception(t('Twitter key may not be empty.')); @@ -37,88 +43,132 @@ class twitter_puller { throw new Exception(t('Number of Twitter items to pull must be a positive integer less than or equal to 200.')); } + if (empty($this->consumer_key) || !drupal_strlen($this->consumer_key)) { + throw new Exception(t('Twitter consumer key is empty.')); + } + + if (empty($this->consumer_secret) || !drupal_strlen($this->consumer_secret)) { + throw new Exception(t('Twitter consumer secret is empty.')); + } + + if (empty($this->oauth_token) || !drupal_strlen($this->oauth_token)) { + throw new Exception(t('Twitter OAuth token is empty.')); + } + + if (empty($this->oauth_token_secret) || !drupal_strlen($this->oauth_token_secret)) { + throw new Exception(t('Twitter OAuth token secret is empty.')); + } + } - function get_items() { + public function get_items() { + // Get twitkey statistics. $prefix = drupal_substr($this->twitkey, 0, 1); $slash = strpos($this->twitkey, '/', 1); $num = intval($this->num_items); - - // lists have the format @username/listname - if ($prefix == '@' && $slash !== FALSE) { - $username = drupal_substr($this->twitkey, 1, $slash - 1); - $listname = drupal_substr($this->twitkey, $slash + 1); - $url = 'http://api.twitter.com/1/' . urlencode($username) . '/lists/' . urlencode($listname) . '/statuses.json?per_page=' . $num; - } - // if the first character is @, then consider the key a username - elseif ($prefix == "@") { - $key = drupal_substr($this->twitkey, 1); - $url = 'http://api.twitter.com/1/statuses/user_timeline.json?screen_name='. urlencode($key) .'&include_rts=true&count='. $num; - } - // if the first character is ~, then consider the key a favorites feed - elseif ($prefix == "~") { - $key = drupal_substr($this->twitkey, 1); - $url = 'http://api.twitter.com/1/favorites/'.urlencode($key).'.json?count='.$num; - } - // otherwise, use the key as a search term - else { - if ($num > 100) { - $num = 100; - } - $url = 'http://search.twitter.com/search.json?q=' . urlencode($this->twitkey) . '&rpp=' . $num; - } - - $ret = drupal_http_request($url); - - if ($ret->code < 200 || $ret->code > 399) { - $errmsg = t('An unknown error occurred.'); - if (isset($ret->error) && !empty($ret->error)) { - $errmsg = check_plain($ret->error); - } - elseif (isset($ret->data) && !empty($ret->data)) { - $errdata = json_decode($ret->data); - if (isset($errdata->error) && !empty($errdata->error)) { - $errmsg = check_plain($errmsg->error); + $key = drupal_substr($this->twitkey, 1); + + // Start building the parameters for the twitter api. + $params = array( + 'count' => $num, + ); + + // Determin the type of request. + // Set up the path and params according to the type of request. + switch ($prefix) { + case "@": + if ($slash === FALSE) { + // Just a normal user timeline. + $path = "statuses/user_timeline.json"; + $params['screen_name'] = $key; + } + else { + // Since we have at least one slash, we are going to get a list. + $path = "lists/statuses.json"; + $params['owner_screen_name'] = drupal_substr($this->twitkey, 1, $slash - 1); + $params['slug'] = drupal_substr($this->twitkey, $slash + 1); } - } - if ($ret->code == 400) { - $errmsg .= ' ' . t('This site may be subject to rate limiting. For more information, see: http://apiwiki.twitter.com/Rate-limiting'); - } - throw new Exception(t('Could not retrieve data from Twitter.') . ' ' . $errmsg); + break; + + case "~": + // Looking for favorites. + $path = "favorites/list.json"; + $params['screen_name'] = $key; + break; + + default: + // Default to a normal search. + $path = "search/tweets.json"; + $params['count'] = $num > 100 ? 100 : $num; + $params['q'] = $this->twitkey; + break; } - $items = json_decode($ret->data); - $this->parse_items($items); + $results = $this->request($path, $params); + $results = drupal_json_decode($results); + return $this->parse_items($results); } - function parse_items($items) { - $tweets = array(); + private function request($path, $params) { - //-- If search response then items are one level lower. - if (isset($items->results) && is_array($items->results)) { - $items = $items->results; + $consumer_key = $this->consumer_key; + $consumer_secret = $this->consumer_secret; + $oauth_token = $this->oauth_token; + $oauth_token_secret = $this->oauth_token_secret; + $url = 'https://api.twitter.com/1.1/' . $path; + + $signature_method = new OAuthSignatureMethod_HMAC_SHA1(); + $consumer = new OAuthConsumer($consumer_key, $consumer_secret); + $token = new OAuthConsumer($oauth_token, $oauth_token_secret); + + $request = OAuthRequest::from_consumer_and_token($consumer, $token, 'GET', $url, $params); + $request->sign_request($signature_method, $consumer, $token); + + return $this->do_request($request->to_url()); + } + + private function do_request($url) { + + $headers = array(); + + $headers['Authorization'] = 'Oauth'; + $headers['Content-type'] = 'application/x-www-form-urlencoded'; + + $response = drupal_http_request($url, array('headers' => $headers, 'method' => 'GET')); + + if (!isset($response->error)) { + return $response->data; + } + else { + $error = $response->error; + throw new Exception(t('Twitter request failed: @error.', array('@error' => $response->error))); } + } + + private function parse_items($results) { + + $this->tweets = array(); + + // Search results return metadata and the results in a sub-array + // We need to parse the actual result array. + $results = isset($results['statuses']) ? $results['statuses'] : $results; + + foreach ($results as $status) { + $tweet = new stdClass(); + $tweet->id = $status['id']; + $tweet->text = $status['text']; + $tweet->timestamp = strtotime($status['created_at']); + $tweet->username = $status['user']['name']; + $tweet->userphoto = $status['user']['profile_image_url']; + $tweet->userphoto_https = $status['user']['profile_image_url_https']; + $tweet->time_ago = t('!time ago.', array('!time' => format_interval(time() - $tweet->timestamp))); - if (is_array($items)) { - $items = array_slice($items, 0, $this->num_items); - foreach ($items as $item) { - $obj = new stdClass(); - $obj->id = $item->id_str; - $obj->username = (isset($item->user) && !empty($item->user->screen_name)) ? $item->user->screen_name : $item->from_user; - $obj->username = check_plain($obj->username); - $obj->userphoto = (isset($item->user) && !empty($item->user->profile_image_url)) ? $item->user->profile_image_url : $item->profile_image_url; - $obj->userphoto = check_plain($obj->userphoto); - $obj->text = filter_xss($item->text); - //-- Convert date to unix timestamp so themer can easily work with it. - $obj->timestamp = strtotime($item->created_at); - $obj->time_ago = t('!time ago.', array('!time' => format_interval(time() - $obj->timestamp))); - $tweets[] = $obj; - } + $this->tweets[] = $tweet; } - $this->tweets = $tweets; + return $this->tweets; } }