diff --git a/application/libraries/tweet.php b/application/libraries/tweet.php index 20504da..270cca9 100755 --- a/application/libraries/tweet.php +++ b/application/libraries/tweet.php @@ -1,83 +1,83 @@ -_oauth = new tweetOauth(); } - + function __call($method, $args) { if ( method_exists($this, $method) ) { return call_user_func_array(array($this, $method), $args); } - + return call_user_func_array(array($this->_oauth, $method), $args); } - + function logged_in() { return $this->_oauth->loggedIn(); } - + function set_callback($url) { $this->_oauth->setCallback($url); } - + function login() { return $this->_oauth->login(); } - + function logout() { return $this->_oauth->logout(); } - + function get_tokens() { $tokens = array( 'oauth_token' => $this->_oauth->getAccessKey(), 'oauth_token_secret' => $this->_oauth->getAccessSecret() ); - + return $tokens; } - + function set_tokens($tokens) { return $this->_oauth->setAccessTokens($tokens); } } - + class tweetException extends Exception { - + function __construct($string) { parent::__construct($string); } - + public function __toString() { return "exception '".__CLASS__ ."' with message '".$this->getMessage()."' in ".$this->getFile().":".$this->getLine()."\nStack trace:\n".$this->getTraceAsString(); } } - + class tweetConnection { - + // Allow multi-threading. - + private $_mch = NULL; private $_properties = array(); - + function __construct() { $this->_mch = curl_multi_init(); - + $this->_properties = array( 'code' => CURLINFO_HTTP_CODE, 'time' => CURLINFO_TOTAL_TIME, @@ -85,82 +85,85 @@ function __construct() 'type' => CURLINFO_CONTENT_TYPE ); } - + private function _initConnection($url) { $this->_ch = curl_init($url); curl_setopt($this->_ch, CURLOPT_RETURNTRANSFER, TRUE); } - + public function get($url, $params) { if ( count($params['request']) > 0 ) { - $url .= '?'; + /*$url .= '?'; foreach( $params['request'] as $k => $v ) { $url .= "{$k}={$v}&"; } - $url = substr($url, 0, -1); + $url = substr($url, 0, -1);*/ + $url .= '?'.http_build_query($params['request']); } - + $this->_initConnection($url); $response = $this->_addCurl($url, $params); return $response; } - - public function post($url, $params) + + public function post($url, $params) { // Todo $post = ''; - + foreach ( $params['request'] as $k => $v ) { $post .= "{$k}={$v}&"; } - + $post = substr($post, 0, -1); - + $this->_initConnection($url, $params); curl_setopt($this->_ch, CURLOPT_POST, 1); curl_setopt($this->_ch, CURLOPT_POSTFIELDS, $post); - + $response = $this->_addCurl($url, $params); return $response; } - + private function _addOauthHeaders(&$ch, $url, $oauthHeaders) { - $_h = array('Expect:'); + //$_h = array('Expect:'); + $_h = array('Expect:', "Connection: Keep-Alive", "Cache-Control: no-cache", "User-Agent: " . $_SERVER['HTTP_USER_AGENT']); $urlParts = parse_url($url); $oauth = 'Authorization: OAuth realm="' . $urlParts['path'] . '",'; - + foreach ( $oauthHeaders as $name => $value ) { $oauth .= "{$name}=\"{$value}\","; } - + + // Additional headers $_h[] = substr($oauth, 0, -1); - + curl_setopt($ch, CURLOPT_HTTPHEADER, $_h); } - + private function _addCurl($url, $params = array()) { if ( !empty($params['oauth']) ) { $this->_addOauthHeaders($this->_ch, $url, $params['oauth']); } - + $ch = $this->_ch; - + $key = (string) $ch; $this->_requests[$key] = $ch; - + $response = curl_multi_add_handle($this->_mch, $ch); if ( $response === CURLM_OK || $response === CURLM_CALL_MULTI_PERFORM ) @@ -168,7 +171,7 @@ private function _addCurl($url, $params = array()) do { $mch = curl_multi_exec($this->_mch, $active); } while ( $mch === CURLM_CALL_MULTI_PERFORM ); - + return $this->_getResponse($key); } else @@ -176,64 +179,64 @@ private function _addCurl($url, $params = array()) return $response; } } - + private function _getResponse($key = NULL) { if ( $key == NULL ) return FALSE; - + if ( isset($this->_responses[$key]) ) { return $this->_responses[$key]; } - + $running = NULL; - + do { $response = curl_multi_exec($this->_mch, $running_curl); - + if ( $running !== NULL && $running_curl != $running ) { $this->_setResponse($key); - + if ( isset($this->_responses[$key]) ) { $response = new tweetResponseOauth( (object) $this->_responses[$key] ); - + if ( $response->__resp->code !== 200 ) { throw new tweetException($response->__resp->code.' | Request Failed: '.$response->__resp->data->request.' - '.$response->__resp->data->error); } - + return $response; } } - + $running = $running_curl; - + } while ( $running_curl > 0); - + } - + private function _setResponse($key) { while( $done = curl_multi_info_read($this->_mch) ) { $key = (string) $done['handle']; $this->_responses[$key]['data'] = curl_multi_getcontent($done['handle']); - + foreach ( $this->_properties as $curl_key => $value ) { $this->_responses[$key][$curl_key] = curl_getinfo($done['handle'], $value); - + curl_multi_remove_handle($this->_mch, $done['handle']); } } } } - + class tweetResponseOauth { - + private $__construct; public function __construct($resp) @@ -249,7 +252,7 @@ public function __construct($resp) public function __get($name) { if ($this->__resp->code < 200 || $this->__resp->code > 299) return FALSE; - + if ( is_string($this->__resp->data ) ) { parse_str($this->__resp->data, $result); @@ -258,12 +261,12 @@ public function __get($name) { $result = $this->__resp->data; } - + foreach($result as $k => $v) { $this->$k = $v; } - + if ( $name === '_result') { return $result; @@ -272,46 +275,49 @@ public function __get($name) return $result[$name]; } } - + class tweetOauth extends tweetConnection { - + private $_obj; - private $_tokens = array(); - private $_authorizationUrl = 'http://api.twitter.com/oauth/authorize'; - private $_requestTokenUrl = 'http://api.twitter.com/oauth/request_token'; - private $_accessTokenUrl = 'http://api.twitter.com/oauth/access_token'; - private $_signatureMethod = 'HMAC-SHA1'; - private $_version = '1.0'; - private $_apiUrl = 'http://api.twitter.com'; + private $_tokens = array(); + //private $_authorizationUrl = 'http://api.twitter.com/oauth/authorize'; + private $_authorizationUrl = 'https://api.twitter.com/oauth/authenticate'; + private $_requestTokenUrl = 'http://api.twitter.com/oauth/request_token'; + private $_accessTokenUrl = 'http://api.twitter.com/oauth/access_token'; + private $_signatureMethod = 'HMAC-SHA1'; + private $_version = '1.0'; + private $_apiUrl = 'http://api.twitter.com/1.1'; private $_searchUrl = 'http://search.twitter.com/'; - private $_callback = NULL; - private $_errors = array(); - private $_enable_debug = FALSE; - + private $_uploadUrl = 'https://upload.twitter.com/1/'; + private $_callback = NULL; + private $_errors = array(); + private $_enable_debug = FALSE; + private $_multipart = FALSE; + function __construct() { parent::__construct(); - + $this->_obj =& get_instance(); $this->_obj->load->config('tweet'); $this->_obj->load->library('session'); $this->_obj->load->library('unit_test'); $this->_obj->load->helper('url'); - + $this->_tokens = array( 'consumer_key' => $this->_obj->config->item('tweet_consumer_key'), 'consumer_secret' => $this->_obj->config->item('tweet_consumer_secret'), 'access_key' => $this->_getAccessKey(), 'access_secret' => $this->_getAccessSecret() ); - + $this->_checkLogin(); } - + function __destruct() { if ( !$this->_enable_debug ) return; - + if ( !empty($this->_errors) ) { foreach ( $this->_errors as $key => $e ) @@ -320,68 +326,75 @@ function __destruct() } } } - + public function enable_debug($debug) { $debug = (bool) $debug; $this->_enable_debug = $debug; } - + public function call($method, $path, $args = NULL) { $response = $this->_httpRequest(strtoupper($method), $this->_apiUrl.'/'.$path.'.json', $args); - + //'http://api.twitter.com/1/statuses/update' // var_dump($response); // die(); - + return ( $response === NULL ) ? FALSE : $response->_result; } - + + public function upload($args = NULL) + { + $this->_multipart = TRUE; + $response = $this->_httpRequest('POST', $this->_uploadUrl.'statuses/update_with_media.json', $args); + return ( $response === NULL ) ? FALSE : $response->_result; + } + public function search($args = NULL) { $response = $this->_httpRequest('GET', $this->_searchUrl.'search.json', $args); - + return ( $response === NULL ) ? FALSE : $response->_result; } - + public function loggedIn() { $access_key = $this->_getAccessKey(); $access_secret = $this->_getAccessSecret(); - + $loggedIn = FALSE; - + if ( $this->_getAccessKey() !== NULL && $this->_getAccessSecret() !== NULL ) { $loggedIn = TRUE; } - + $this->_obj->unit->run($loggedIn, TRUE, 'Logged In'); return $loggedIn; } - + private function _checkLogin() { if ( isset($_GET['oauth_token']) ) { $this->_setAccessKey($_GET['oauth_token']); $token = $this->_getAccessToken(); - + $token = $token->_result; - + $token = ( is_bool($token) ) ? $token : (object) $token; - + if ( !empty($token->oauth_token) && !empty($token->oauth_token_secret) ) { $this->_setAccessKey($token->oauth_token); $this->_setAccessSecret($token->oauth_token_secret); } - + redirect(current_url()); return NULL; } } - + public function login() { if ( ($this->_getAccessKey() === NULL || $this->_getAccessSecret() === NULL) ) @@ -389,42 +402,42 @@ public function login() header('Location: '.$this->_getAuthorizationUrl()); return; } - + return $this->_checkLogin(); } - + public function logout() { $this->_obj->session->unset_userdata('twitter_oauth_tokens'); } - + public function getTokens() { return $this->_tokens; } - + private function _getConsumerKey() { return $this->_tokens['consumer_key']; } - + private function _getConsumerSecret() { return $this->_tokens['consumer_secret']; } - + public function getAccessKey(){ return $this->_getAccessKey(); } - + private function _getAccessKey() { $tokens = $this->_obj->session->userdata('twitter_oauth_tokens'); return ( $tokens === FALSE || !isset($tokens['access_key']) || empty($tokens['access_key']) ) ? NULL : $tokens['access_key']; } - + private function _setAccessKey($access_key) { $tokens = $this->_obj->session->userdata('twitter_oauth_tokens'); - + if ( $tokens === FALSE || !is_array($tokens) ) { $tokens = array('access_key' => $access_key); @@ -433,22 +446,22 @@ private function _setAccessKey($access_key) { $tokens['access_key'] = $access_key; } - + $this->_obj->session->set_userdata('twitter_oauth_tokens', $tokens); } - + public function getAccessSecret(){ return $this->_getAccessSecret(); } - + private function _getAccessSecret() { $tokens = $this->_obj->session->userdata('twitter_oauth_tokens'); return ( $tokens === FALSE || !isset($tokens['access_secret']) || empty($tokens['access_secret']) ) ? NULL : $tokens['access_secret']; } - + private function _setAccessSecret($access_secret) { $tokens = $this->_obj->session->userdata('twitter_oauth_tokens'); - + if ( $tokens === FALSE || !is_array($tokens) ) { $tokens = array('access_secret' => $access_secret); @@ -457,44 +470,44 @@ private function _setAccessSecret($access_secret) { $tokens['access_secret'] = $access_secret; } - + $this->_obj->session->set_userdata('twitter_oauth_tokens', $tokens); } - + private function _setAccessTokens($tokens) { $this->_setAccessKey($tokens['oauth_token']); $this->_setAccessSecret($tokens['oauth_token_secret']); } - + public function setAccessTokens($tokens) { return $this->_setAccessTokens($tokens); } - + private function _getAuthorizationUrl() { $token = $this->_getRequestToken(); return $this->_authorizationUrl.'?oauth_token=' . $token->oauth_token; } - + private function _getRequestToken() { return $this->_httpRequest('GET', $this->_requestTokenUrl); } - + private function _getAccessToken() { return $this->_httpRequest('GET', $this->_accessTokenUrl); } - + protected function _httpRequest($method = null, $url = null, $params = null) { if( empty($method) || empty($url) ) return FALSE; if ( empty($params['oauth_signature']) ) $params = $this->_prepareParameters($method, $url, $params); - + $this->_connection = new tweetConnection(); - + try { switch ( $method ) { @@ -504,6 +517,9 @@ protected function _httpRequest($method = null, $url = null, $params = null) case 'POST': return $this->_connection->post($url, $params); + //print_r($url); + //exit; + //return $this->_connection->post($url, $params, $this->_multipart); break; case 'PUT': @@ -518,85 +534,105 @@ protected function _httpRequest($method = null, $url = null, $params = null) $this->_errors[] = $e; } } - + private function _getCallback() { return $this->_callback; } - + public function setCallback($url) { $this->_callback = $url; } - + private function _prepareParameters($method = NULL, $url = NULL, $params = NULL) { if ( empty($method) || empty($url) ) return FALSE; - + $callback = $this->_getCallback(); - + if ( !empty($callback) ) { $oauth['oauth_callback'] = $callback; } - + $this->setCallback(NULL); - + $oauth['oauth_consumer_key'] = $this->_getConsumerKey(); $oauth['oauth_token'] = $this->_getAccessKey(); $oauth['oauth_nonce'] = $this->_generateNonce(); $oauth['oauth_timestamp'] = time(); $oauth['oauth_signature_method'] = $this->_signatureMethod; $oauth['oauth_version'] = $this->_version; - + array_walk($oauth, array($this, '_encode_rfc3986')); - + + if($this->_multipart) + { + $request_params = $params; + $params = array(); + } + if ( is_array($params) ) { array_walk($params, array($this, '_encode_rfc3986')); } - + $encodedParams = array_merge($oauth, (array)$params); - + ksort($encodedParams); - + $oauth['oauth_signature'] = $this->_encode_rfc3986($this->_generateSignature($method, $url, $encodedParams)); - return array('request' => $params, 'oauth' => $oauth); + //return array('request' => $params, 'oauth' => $oauth); + + if($this->_multipart){ + return array('request' => $request_params, 'oauth' => $oauth); + } else { + return array('request' => $params, 'oauth' => $oauth); + } } - + private function _generateNonce() { return md5(uniqid(rand(), TRUE)); } - + private function _encode_rfc3986($string) { return str_replace('+', ' ', str_replace('%7E', '~', rawurlencode(($string)))); } - + private function _generateSignature($method = null, $url = null, $params = null) { if( empty($method) || empty($url) ) return FALSE; - + // concatenating $concatenatedParams = ''; - + foreach ($params as $k => $v) { + $k = $this->_encode_rfc3986($k); $v = $this->_encode_rfc3986($v); $concatenatedParams .= "{$k}={$v}&"; } - + $concatenatedParams = $this->_encode_rfc3986(substr($concatenatedParams, 0, -1)); // normalize url - $normalizedUrl = $this->_encode_rfc3986($this->_normalizeUrl($url)); + //$normalizedUrl = $this->_encode_rfc3986($this->_normalizeUrl($url)); + // Using the normalized url when uploading generates a 401 issue, yet for other api calls there's not a problem... + if($this->_multipart){ + $normalizedUrl = $this->_encode_rfc3986($url); + } else { + $normalizedUrl = $this->_encode_rfc3986($this->_normalizeUrl($url)); + } + $method = $this->_encode_rfc3986($method); // don't need this but why not? $signatureBaseString = "{$method}&{$normalizedUrl}&{$concatenatedParams}"; return $this->_signString($signatureBaseString); } - + private function _normalizeUrl($url = NULL) { $urlParts = parse_url($url); @@ -608,22 +644,22 @@ private function _normalizeUrl($url = NULL) $port = intval($urlParts['port']); $retval = "{$scheme}://{$host}"; - + if ( $port > 0 && ( $scheme === 'http' && $port !== 80 ) || ( $scheme === 'https' && $port !== 443 ) ) { $retval .= ":{$port}"; } - + $retval .= $urlParts['path']; - + if ( !empty($urlParts['query']) ) { $retval .= "?{$urlParts['query']}"; } - + return $retval; } - + private function _signString($string) { $retval = FALSE;