/** * Call API method over HTTP and return raw data * @param string API method, e.g. "users/show" * @param array method arguments * @param string http request method * @return array unserialized data returned from twitter * @throws TwitterApiException */ public function call($path, array $_args, $http_method) { // all calls must be authenticated in API 1.1 if (!$this->has_auth()) { throw new TwitterApiException(__('Twitter client not authenticated', 'twitter-api'), 0, 401); } // transform some arguments and ensure strings // no further validation is performed $args = array(); foreach ($_args as $key => $val) { if (is_string($val)) { $args[$key] = $val; } else { if (true === $val) { $args[$key] = 'true'; } else { if (false === $val || null === $val) { $args[$key] = 'false'; } else { if (!is_scalar($val)) { throw new TwitterApiException(__('Invalid Twitter parameter', 'twitter-api') . ' (' . gettype($val) . ') ' . $key . ' in ' . $path, -1); } else { $args[$key] = (string) $val; } } } } } // Fetch response from cache if possible / allowed / enabled if ($http_method === 'GET' && isset($this->cache_ttl)) { $cachekey = $this->cache_ns . $path . '_' . md5(serialize($args)); if (preg_match('/^(\\d+)-/', $this->AccessToken->key, $reg)) { $cachekey .= '_' . $reg[1]; } $data = _twitter_api_cache_get($cachekey); if (is_array($data)) { return $data; } } // @todo could validate args against endpoints here. // Using Wordpress WP_Http for requests, see class-http.php $conf = array('method' => $http_method, 'redirection' => 0); // build signed URL and request parameters $endpoint = TWITTER_API_BASE . '/' . $path . '.json'; $params = new TwitterOAuthParams($args); $params->set_consumer($this->Consumer); $params->set_token($this->AccessToken); $params->sign_hmac($http_method, $endpoint); if ('GET' === $http_method) { $endpoint .= '?' . $params->serialize(); } else { //$conf['headers'] = $params->oauth_header(); $conf['body'] = $params->serialize(); } $http = self::http_request($endpoint, $conf); $data = json_decode($http['body'], true); $status = $http['response']['code']; // remember current rate limits for this endpoint $this->last_call = $path; if (isset($http['headers']['x-rate-limit-limit'])) { $this->last_rate[$path] = array('limit' => (int) $http['headers']['x-rate-limit-limit'], 'remaining' => (int) $http['headers']['x-rate-limit-remaining'], 'reset' => (int) $http['headers']['x-rate-limit-reset']); } // unserializable array assumed to be serious error if (!is_array($data)) { $err = array('message' => '', 'code' => -1); TwitterApiException::chuck($err, $status); } // else could be well-formed error if (isset($data['errors'])) { while ($err = array_shift($data['errors'])) { $err['message'] = __($err['message'], 'twitter-api'); if ($data['errors']) { $message = sprintf(__('Twitter error #%d', 'twitter-api'), $err['code']) . ' "' . $err['message'] . '"'; trigger_error($message, E_USER_WARNING); } else { TwitterApiException::chuck($err, $status); } } } // some errors appear to use a single key and have no code // e.g. not authorized to view specific content. if (isset($data['error'])) { $code = isset($data['code']) ? $data['code'] : $status; $message = sprintf(__('Twitter error #%d', 'twitter-api'), $code) . ' "' . $data['error'] . '"'; TwitterApiException::chuck(compact('message', 'code'), $status); } if (isset($cachekey)) { _twitter_api_cache_set($cachekey, $data, $this->cache_ttl); } return $data; }
/** * Sign and execute REST API call * @return array */ private function rest_request($path, array $args, $http_method) { // all calls must be authenticated in API 1.1 if (!$this->has_auth()) { throw new TwitterApiException('Twitter client not authenticated', 0, 401); } // prepare HTTP request config $conf = array('method' => $http_method); // build signed URL and request parameters $endpoint = TWITTER_API_BASE . '/' . $path . '.json'; $params = new TwitterOAuthParams($args); $params->set_consumer($this->Consumer); $params->set_token($this->AccessToken); $params->sign_hmac($http_method, $endpoint); if ('GET' === $http_method) { $endpoint .= '?' . $params->serialize(); } else { $conf['body'] = $params->serialize(); } $http = self::http_request($endpoint, $conf); // remember current rate limits for this endpoint $this->last_call = $path; if (isset($http['headers']['x-rate-limit-limit'])) { $this->last_rate[$path] = array('limit' => (int) $http['headers']['x-rate-limit-limit'], 'remaining' => (int) $http['headers']['x-rate-limit-remaining'], 'reset' => (int) $http['headers']['x-rate-limit-reset']); } return $http; }