File: /var/www/clients/client0/web20/web/wp-content/plugins/qode-twitter-feed/lib/qode-twitter-api.php
<?php
if(!defined('ABSPATH')) exit;
include_once 'qode-twitter-helper.php';
/**
* Class QodeTwitterApi
*/
class QodeTwitterApi {
/**
* @var instance of current class
*/
private static $instance;
/**
* Key that was provided by Twitter when application was created
* @var string
*/
private $consumerKey;
/**
* Secret code for application that was generated by Twitter
* @var string
*/
private $consumerSecret;
/**
*
* URL where user will be redirected once he authorizes access to our application
* @var string
*/
private $redirectURI;
/**
* URL from which we can obtain request token that will be used to get access token
* @var string
*/
private $requestTokenURL;
/**
* URL where user can authorize our application
* @var string
*/
private $authorizeURL;
/**
* URL from which we can obtain access token
* @var
*/
private $accessTokenUrl;
/**
* Signature hashin method that is used by Twitter OAuth
* @var string
*/
private $signatureMethod;
/**
* OAuth version that is used by Twitter
* @var string
*/
private $oauthVersion;
private $helper;
const REQUEST_TOKEN_FIELD = 'qode_twitter_request_token';
const REQUEST_TOKEN_SECRET_FIELD = 'qode_twitter_request_token_secret';
const ACCESS_TOKEN_FIELD = 'qode_twitter_access_token';
const ACCESS_TOKEN_SECRET_FIELD = 'qode_twitter_access_token_secret';
const AUTHORIZE_TOKEN_FIELD = 'qode_twitter_authorize_token';
const AUTHORIZE_VERIFIER_FIELD = 'qode_twitter_authorize_verifier';
const USER_ID_FIELD = 'qode_twitter_user_id';
const USER_SCREEN_NAME_FIELD = 'qode_twitter_screen_name';
/**
* Private constructor because of singletone pattern. It sets all necessary properties
*/
public function __construct() {
$this->consumerKey = 'hcaxjQrwiRYLobULjlnqNLuVO';
$this->consumerSecret = 'mGIGU8tjclGH43s3QWul5tlaycsIrrldnYWE5a8HCvrq1NL5ot';
$this->redirectURI = 'http://demo.qodeinteractive.com/twitter-app/twitter-redirect.php';
$this->signatureMethod = 'HMAC-SHA1';
$this->oauthVersion = '1.0';
$this->requestTokenURL = 'https://api.twitter.com/oauth/request_token';
$this->authorizeURL = 'https://api.twitter.com/oauth/authorize';
$this->accessTokenUrl = 'https://api.twitter.com/oauth/access_token';
$this->helper = new QodeTwitterHelper();
}
/**
* Must override magic method because of singletone
*/
private function __clone() {}
/**
* Must override magic method because of singletone
*/
private function __wakeup() {}
/**
* @return QodeTwitterApi
*/
public static function getInstance() {
if(self::$instance === null) {
return new self();
}
return self::$instance;
}
/**
* @return QodeTwitterHelper
*/
public function getHelper() {
return $this->helper;
}
/**
* Generates signature base that will be used to generate request signature.
* Signature is used by Twitter to check authorization of request
* @param string $requestUrl URL that we are requesting
* @param strinh $method HTTP method. Can be GET or POST
* @param array $params array of parameters from which to generate signature base
* @return string generated signature base
*/
private function generateSignatureBase($requestUrl, $method, $params) {
$encodedParams = array();
$encodedParamsString = '';
$method = strtoupper($method);
$base = $method.'&'.rawurlencode($requestUrl).'&';
if(is_array($params) && count($params)) {
foreach($params as $key => $value) {
$encodedParams[rawurlencode($key)] = rawurlencode($value);
}
ksort($encodedParams);
foreach($encodedParams as $key => $value) {
$encodedParamsString .= $key.'='.$value.'&';
}
$encodedParamsString = rtrim($encodedParamsString, '&');
}
$base .= rawurlencode($encodedParamsString);
return $base;
}
/**
* Generates signature. Uses consumer secret as hashing key and uses sha1 as hashing algorithm
* @param string $requestUrl URL that we are requesting
* @param string $method HTTP method. Can be GET of POST
* @param array $params array of parameters from which to generate signature
* @param string $tokenSecret
* @return string generated signature
*
* @see QodeTwitterApi::generateSignatureBase()
*/
private function generateSignature($requestUrl, $method, $params, $tokenSecret = '') {
$base = $this->generateSignatureBase($requestUrl, $method, $params);
$signatureKey = rawurlencode($this->consumerSecret).'&';
if($tokenSecret !== '') {
$signatureKey .= rawurlencode($tokenSecret);
}
return base64_encode(hash_hmac('sha1', $base, $signatureKey, true));
}
/**
* Generates OAuth authorization header base on provided request params
* @param array $requestParams
* @return string
*/
private function generateOAuthHeader($requestParams) {
$header = array();
if(is_array($requestParams) && count($requestParams)) {
foreach($requestParams as $key => $value) {
$header[] = rawurlencode($key).'="'.rawurlencode($value).'"';
}
}
return 'OAuth '.implode(', ', $header);
}
/**
* Generates hashed random number sequence that is used on each request
* @return string
*/
private function generateNonce() {
return md5(mt_rand());
}
/**
* Returns current UNIX time
* @return int
*/
private function generateTimestamp() {
return time();
}
/**
* Sends request to Twitter in order to obtain request token.
* When Twitter returns request token it is saved in database along with request token secret.
* It builds response object that is returned to client and which has status, message and redirectURL (authorize URL) properties
*/
public function obtainRequestToken() {
$responseObj = new stdClass();
$currentPageUrl = !empty($_POST['currentPageUrl']) ? $_POST['currentPageUrl'] : $this->buildCurrentPageURI();
$requestParams = array(
'oauth_callback' => $this->buildRedirectURL($currentPageUrl),
'oauth_consumer_key' => $this->consumerKey,
'oauth_nonce' => $this->generateNonce(),
'oauth_signature_method' => $this->signatureMethod,
'oauth_timestamp' => $this->generateTimestamp(),
'oauth_version' => $this->oauthVersion
);
$requestParams['oauth_signature'] = $this->generateSignature($this->requestTokenURL, 'POST', $requestParams);
$OAuthHeader = $this->generateOAuthHeader($requestParams);
$requestTokenData = array(
'method' => 'POST',
'blocking' => true,
'headers' => array(
'Authorization' => $OAuthHeader,
'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8'
)
);
$response = wp_remote_post($this->requestTokenURL, $requestTokenData);
if(is_wp_error($response)) {
$responseObj->status = false;
$responseObj->message = esc_html__('Internal WP error', 'qode-twitter-feed');
} else {
$responseBody = wp_remote_retrieve_body($response);
if(!empty($responseBody)) {
parse_str($responseBody, $responseParsed);
if((is_array($responseParsed) && count($responseParsed)) &&
!empty($responseParsed['oauth_token']) && !empty($responseParsed['oauth_token_secret'])) {
update_option(self::REQUEST_TOKEN_FIELD, $responseParsed['oauth_token']);
update_option(self::REQUEST_TOKEN_SECRET_FIELD, $responseParsed['oauth_token_secret']);
$responseObj->redirectURL = $this->buildAuthorizeURL();
if(!empty($responseObj->redirectUrl)) {
$responseObj->status = false;
$responseObj->message = esc_html__('Redirect URL couldn\t not be generated', 'qode-twitter-feed');
} else {
$responseObj->status = true;
$responseObj->message = 'Ok';
}
} else {
$responseObj->status = false;
$responseObj->message = esc_html__('Couldn\'t connect with Twitter API', 'qode-twitter-feed');
}
}
}
echo json_encode($responseObj);
exit;
}
/**
* @return stdClass
*/
public function obtainAccessToken() {
$responseObj = new stdClass();
$authorizeVerifier = get_option(self::AUTHORIZE_VERIFIER_FIELD);
$authorizeToken = get_option(self::AUTHORIZE_TOKEN_FIELD);
if(!empty($authorizeVerifier) && !empty($authorizeToken)) {
$requestParams = array(
'oauth_consumer_key' => $this->consumerKey,
'oauth_nonce' => $this->generateNonce(),
'oauth_signature_method' => $this->signatureMethod,
'oauth_timestamp' => $this->generateTimestamp(),
'oauth_version' => $this->oauthVersion
);
$requestParams['oauth_signature'] = $this->generateSignature($this->accessTokenUrl, 'POST', $requestParams);
$requestData = array(
'method' => 'POST',
'headers' => array(
'Authorization' => $this->generateOAuthHeader($requestParams),
'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8'
),
'body' => array(
'oauth_verifier' => rawurlencode($authorizeVerifier),
'oauth_token' => rawurlencode($authorizeToken)
)
);
$response = wp_remote_post($this->accessTokenUrl, $requestData);
if(is_wp_error($response)) {
$responseObj->status = false;
$responseObj->message = esc_html__('Internal WP error', 'qode-twitter-feed');
} else {
$responseBody = wp_remote_retrieve_body($response);
parse_str($responseBody, $responseParsed);
if(is_array($responseParsed) && count($responseParsed)
&& !empty($responseParsed['oauth_token']) && !empty($responseParsed['oauth_token_secret']) && !empty($responseParsed['user_id']) && !empty($responseParsed['screen_name'])) {
update_option(self::ACCESS_TOKEN_FIELD, $responseParsed['oauth_token']);
update_option(self::ACCESS_TOKEN_SECRET_FIELD, $responseParsed['oauth_token_secret']);
update_option(self::USER_ID_FIELD, $responseParsed['user_id']);
update_option(self::USER_SCREEN_NAME_FIELD, $responseParsed['screen_name']);
$responseObj->status = true;
$responseObj->message = esc_html__('Access token obtained', 'qode-twitter-feed');
}
}
} else {
$responseObj->status = false;
$responseObj->message = esc_html__('Authorize token and it\'s secret were not obtainer', 'qode-twitter-feed');
}
return $responseObj;
}
/**
* Gets tweets from Twitter
* @param string $userId ID of the user for which we want to retreieve tweets
* @param string $count number of tweets to return
* @param array $transient
* @return stdClass response object containing status, message and data properties
*/
public function fetchTweets($userId = '', $count = '', $transient = array()) {
$responseObj = new stdClass();
$userId = ($userId !== '') ? $userId : get_option(self::USER_SCREEN_NAME_FIELD);
$count = ($count !== '') ? $count : 5;
$accessToken = get_option(self::ACCESS_TOKEN_FIELD);
$accessTokenSecret = get_option(self::ACCESS_TOKEN_SECRET_FIELD);
if(!$this->transientExists($transient)) {
if($userId && $accessToken) {
$requestParams = array(
'oauth_consumer_key' => $this->consumerKey,
'oauth_nonce' => $this->generateNonce(),
'oauth_signature_method' => $this->signatureMethod,
'oauth_timestamp' => $this->generateTimestamp(),
'oauth_version' => $this->oauthVersion,
'oauth_token' => $accessToken,
'user_id' => $userId,
'count' => $count
);
$requestParams['oauth_signature'] = $this->generateSignature('https://api.twitter.com/1.1/statuses/user_timeline.json', 'GET', $requestParams, $accessTokenSecret);
unset($requestParams['user_id']);
unset($requestParams['count']);
$response = wp_remote_get('https://api.twitter.com/1.1/statuses/user_timeline.json?user_id='.$userId.'&count='.$count, array(
'headers' => array(
'Authorization' => $this->generateOAuthHeader($requestParams),
'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8'
)
));
if(is_wp_error($response)) {
$responseObj->status = false;
$responseObj->message = esc_html__('Internal WP error', 'qode-twitter-feed');
} else {
if(isset($response['response']['code']) && $response['response']['code'] == 200) {
$responseObj->status = true;
$responseObj->message = 'Ok';
$responseObj->data = json_decode(wp_remote_retrieve_body($response), true);
$this->updateTransient($transient, $responseObj->data);
} else {
$responseObj->status = false;
$responseObj->message = esc_html__('Couldn\'t connect with Twitter', 'qode-twitter-feed');
}
}
} else {
$responseObj->status = false;
$responseObj->message = esc_html__('It seams like you haven\t connected with your Twitter account', 'qode-twitter-feed');
}
} else {
$transientContent = $this->getTransient($transient);
if(!empty($transientContent)) {
$responseObj->status = true;
$responseObj->message = 'Ok';
$responseObj->data = $transientContent;
} else {
$responseObj->status = false;
$responseObj->message = esc_html__('Couldn\'t retreive content from database', 'qode-twitter-feed');
}
}
return $responseObj;
}
/**
* Generates URL where user will authorize our application. Appends request token parameter to Twitter URL
* @return bool|string
*/
private function buildAuthorizeURL() {
$request_token = get_option(self::REQUEST_TOKEN_FIELD);
if(!empty($request_token)) {
return $this->authorizeURL.'?oauth_token='.$request_token;
}
return false;
}
/**
* Generates URL where user will be redirected once he authorizes our application
* @param $redirectUrl
* @return string
*/
private function buildRedirectURL($redirectUrl) {
return $this->redirectURI.'?redirect_url='.$redirectUrl;
}
/**
* Returns current page URL
* @return string
*/
public function buildCurrentPageURI() {
$protocol = is_ssl() ? 'https' : 'http';
$site = $_SERVER['SERVER_NAME'];
$slug = $_SERVER['REQUEST_URI'];
return $protocol.'://'.$site.$slug;
}
/**
* Check if user has authorized our application
* @return bool
*/
public function hasUserConnected() {
$accessToken = get_option(self::ACCESS_TOKEN_FIELD);
return !empty($accessToken);
}
/**
* Checks if provided transient exists in the database
* @param $transientConfig
* @return bool
*/
private function transientExists($transientConfig) {
return !empty($transientConfig['transient_time']) && get_transient($transientConfig['transient_id']);
}
/**
* Updates transient with new data if transient time isn't empty. In other case it deletes it
* @param $transientConfig
* @param $data
*/
private function updateTransient($transientConfig, $data) {
if(!empty($transientConfig['transient_time']) && !empty($transientConfig['transient_id'])) {
set_transient($transientConfig['transient_id'], $data, $transientConfig['transient_time']);
} elseif(empty($transientConfig['transient_time']) && !empty($transientConfig['transient_id'])) {
delete_transient($transientConfig['transient_id']);
}
}
/**
* Returns transient content if it exists
* @param $transient
* @return bool|mixed
*/
private function getTransient($transient) {
if(!empty($transient['transient_time']) && !empty($transient['transient_id'])) {
return get_transient($transient['transient_id']);
}
return false;
}
}