Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
executable file 641 lines (495 sloc) 14.6 KB
<?php
class tweet {
private $_oauth = NULL;
function __construct()
{
$this->_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,
'length' => CURLINFO_CONTENT_LENGTH_DOWNLOAD,
'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 .= '?';
foreach( $params['request'] as $k => $v )
{
$url .= "{$k}={$v}&";
}
$url = substr($url, 0, -1);
}
$this->_initConnection($url);
$response = $this->_addCurl($url, $params);
return $response;
}
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:');
$urlParts = parse_url($url);
$oauth = 'Authorization: OAuth realm="' . $urlParts['path'] . '",';
foreach ( $oauthHeaders as $name => $value )
{
$oauth .= "{$name}=\"{$value}\",";
}
$_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 )
{
do {
$mch = curl_multi_exec($this->_mch, $active);
} while ( $mch === CURLM_CALL_MULTI_PERFORM );
return $this->_getResponse($key);
}
else
{
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)
{
$this->__resp = $resp;
if ( strpos($this->__resp->type, 'json') !== FALSE )
{
$this->__resp->data = json_decode($this->__resp->data);
}
}
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);
}
else
{
$result = $this->__resp->data;
}
foreach($result as $k => $v)
{
$this->$k = $v;
}
if ( $name === '_result')
{
return $result;
}
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 $_searchUrl = 'http://search.twitter.com/';
private $_callback = NULL;
private $_errors = array();
private $_enable_debug = 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 )
{
echo '<pre>'.$e.'</pre>';
}
}
}
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);
// var_dump($response);
// die();
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) )
{
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);
}
else
{
$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);
}
else
{
$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 )
{
case 'GET':
return $this->_connection->get($url, $params);
break;
case 'POST':
return $this->_connection->post($url, $params);
break;
case 'PUT':
return NULL;
break;
case 'DELETE':
return NULL;
break;
}
} catch (tweetException $e) {
$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 ( 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);
}
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)
{
$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));
$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);
if ( !isset($urlParts['port']) ) $urlParts['port'] = 80;
$scheme = strtolower($urlParts['scheme']);
$host = strtolower($urlParts['host']);
$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;
switch ( $this->_signatureMethod )
{
case 'HMAC-SHA1':
$key = $this->_encode_rfc3986($this->_getConsumerSecret()) . '&' . $this->_encode_rfc3986($this->_getAccessSecret());
$retval = base64_encode(hash_hmac('sha1', $string, $key, true));
break;
}
return $retval;
}
}