/**
  * 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;
 }