/** * Redirects to the twitter to get authenticated. * * @since 1.3.0 * @since 2.4.5 Moved from the admin page class. * @remark This is redirected from the "Connect to Twitter" button. */ private function _redirect() { /* Build TwitterOAuth object with client credentials. */ $_oConnect = new FetchTweets_TwitterOAuth(FetchTweets_Commons::ConsumerKey, FetchTweets_Commons::ConsumerSecret); /* Get temporary credentials - Requesting authentication tokens, the parameter is the URL we will be redirected to. */ $_aRequestToken = $_oConnect->getRequestToken(add_query_arg(array('post_type' => 'fetch_tweets', 'page' => 'fetch_tweets_settings', 'tab' => 'twitter_callback'), admin_url($GLOBALS['pagenow']))); /* Save temporary credentials to transient. */ $_aTemporaryTokens = array(); $_aTemporaryTokens['oauth_token'] = $_aRequestToken['oauth_token']; $_aTemporaryTokens['oauth_token_secret'] = $_aRequestToken['oauth_token_secret']; FetchTweets_WPUtilities::setTransient(FetchTweets_Commons::TransientPrefix . '_oauth', $_aTemporaryTokens, 60 * 10); // 10 minutes /* If last connection failed don't display authorization link. */ switch ($_oConnect->http_code) { case 200: /* Build authorize URL and redirect user to Twitter. */ wp_redirect($_oConnect->getAuthorizeURL($_aTemporaryTokens['oauth_token'])); // goes to twitter.com break; default: /* Show notification if something went wrong. */ die(__('Could not connect to Twitter. Refresh the page or try again later.', 'fetch-tweets')); } exit; }
public function replyToSubmitField() { $_aParams = func_get_args(); FetchTweets_WPUtilities::clearTransients(); $_oFactory = $_aParams[2]; $_oFactory->setSettingNotice(__('The caches have been cleared.', 'fetch-tweets')); }
/** * * @see https://dev.twitter.com/docs/api/1.1/get/application/rate_limit_status */ public function getStatus() { // Return the cached response if available. $_sCacheID = FetchTweets_Commons::TransientPrefix . '_' . md5(serialize(array($this->sConsumerKey, $this->sConsumerSecret, $this->sAccessToken, $this->sAccessSecret))); $_vData = FetchTweets_WPUtilities::getTransient($_sCacheID); if (false !== $_vData) { return $_vData; } // Perform the requests. $_oConnect = new FetchTweets_TwitterOAuth($this->sConsumerKey, $this->sConsumerSecret, $this->sAccessToken, $this->sAccessSecret); $_aUser = $_oConnect->get('account/verify_credentials'); // If the user id could not be retrieved, it means it failed. if (!isset($_aUser['id']) || !$_aUser['id']) { return array(); } // Otherwise, it is okay. Retrieve the current status. $_aStatusKeys = apply_filters('fetch_tweets_filter_request_rate_limit_status_keys', array('statuses', 'search', 'lists')); // keys can be added such as 'help', 'users' etc $_aStatus = $_oConnect->get('https://api.twitter.com/1.1/application/rate_limit_status.json?resources=' . implode(',', $_aStatusKeys)); // Set the cache. $_aData = is_array($_aStatus) ? $_aUser + $_aStatus : $_aUser; FetchTweets_WPUtilities::setTransient($_sCacheID, $_aData, 60); // stores the cache only for 60 seconds. return $_aData; }
/** * Receives the callback from Twitter authentication and saves the access token. * * @remark This method is triggered when the user get redirected back to the admin page * @since 1.3.0 * @since 2.4.5 Moved from the admin page class. */ private function _handleAuthenticationCallback() { /* If the oauth_token is old redirect to the authentication page. */ $_aTemporaryTokens = FetchTweets_WPUtilities::getTransient(FetchTweets_Commons::TransientPrefix . '_oauth'); if (false === $_aTemporaryTokens || !isset($_aTemporaryTokens['oauth_token'], $_aTemporaryTokens['oauth_token_secret'])) { exit(wp_redirect(add_query_arg(array('post_type' => 'fetch_tweets', 'page' => 'fetch_tweets_settings', 'tab' => 'authentication'), admin_url($GLOBALS['pagenow'])))); } $_oOption =& $GLOBALS['oFetchTweets_Option']; /* Create TwitterOAuth object with app key/secret and token key/secret from default phase */ $_oConnect = new FetchTweets_TwitterOAuth(FetchTweets_Commons::ConsumerKey, FetchTweets_Commons::ConsumerSecret, $_aTemporaryTokens['oauth_token'], $_aTemporaryTokens['oauth_token_secret']); /* Request access tokens from twitter */ $_aAccessTokens = $_oConnect->getAccessToken($_REQUEST['oauth_verifier']); /* $_aAccessTokens Looks like this 'oauth_token' => string 'asxxx-sxxx...' (length=50) 'oauth_token_secret' => string 'xxx....' (length=41) 'user_id' => string '132.....' (length=10) 'screen_name' => string 'my_screen_name' (length=9) */ /* Save the access tokens. Normally these would be saved in a database for future use. */ $_oOption->saveCredentials(array('access_token' => $_aAccessTokens['oauth_token'], 'access_secret' => $_aAccessTokens['oauth_token_secret'], 'screen_name' => $_aAccessTokens['screen_name'], 'user_id' => $_aAccessTokens['user_id'], 'is_connected' => true, 'connect_method' => 'oauth')); /* If HTTP response is 200 continue otherwise send to connect page to retry */ if (200 == $_oConnect->http_code) { /* The user has been verified */ $_sRediretURL = add_query_arg(array('post_type' => 'fetch_tweets', 'page' => 'fetch_tweets_settings', 'tab' => 'twitter_connect'), admin_url($GLOBALS['pagenow'])); } else { /* Save HTTP status for error dialogue on authentication page.*/ // Let the user set authentication keys manually $_sRediretURL = add_query_arg(array('post_type' => 'fetch_tweets', 'page' => 'fetch_tweets_settings', 'tab' => 'authentication'), admin_url($GLOBALS['pagenow'])); } exit(wp_redirect($_sRediretURL)); }
public function fetchFeed($vURLs, $numItems = 0, $fCacheRenew = false) { $arrURLs = is_array($vURLs) ? $vURLs : (array) $vURLs; $strURLID = md5(serialize($arrURLs)); if (!isset($this->arrFeedItems[$strURLID]) && $fCacheRenew == false) { $this->arrFeedItems[$strURLID] = FetchTweets_WPUtilities::getTransient($this->strTransientPrefix . $strURLID, array()); unset($this->arrFeedItems[$strURLID][0]); // casting array causes the 0 key, } // If it's out of stock, fill the array by fetching the feed. if (empty($this->arrFeedItems[$strURLID])) { // When an array of urls is passed to the Simple Pie's set_feed_url() method, the memory usage increases largely. // So fetch the feeds one by one per url and store the output into an array. foreach ($arrURLs as $strURL) { $oFeed = $this->getFeedObj($strURL, null, $fCacheRenew ? 0 : 3600); foreach ($oFeed->get_items() as $oItem) { // foreach ( $oFeed->get_items( 0, $numItems * 3 ) as $item ) does not change the memory usage $this->arrFeedItems[$strURLID][$oItem->get_title()] = array('strContent' => $oItem->get_content(), 'description' => $oItem->get_description(), 'title' => $oItem->get_title(), 'strDate' => $oItem->get_title(), 'strAuthor' => $oItem->get_date('j F Y, g:i a'), 'strLink' => $oItem->get_permalink()); } // For PHP below 5.3 to release the memory. $oFeed->__destruct(); // Do what PHP should be doing on it's own. unset($oFeed); } // This life span should be little longer than the feed cache life span, which is 1700. FetchTweets_WPUtilities::setTransient($this->strTransientPrefix . $strURLID, $this->arrFeedItems[$strURLID], 1800); // 30 minutes } $arrOut = $this->arrFeedItems[$strURLID]; if ($numItems) { array_splice($arrOut, ${$numItems}); } return $arrOut; }
/** * Sets the given transient. * @since 2.3.7 */ public static function setTransient($sTransientKey, $vValue, $iExpiration = 0) { // temporarily disable $_wp_using_ext_object_cache global $_wp_using_ext_object_cache; $_bWpUsingExtObjectCacheTemp = $_wp_using_ext_object_cache; $_wp_using_ext_object_cache = false; self::$_bIsNetworkAdmin = isset(self::$_bIsNetworkAdmin) ? self::$_bIsNetworkAdmin : is_network_admin(); // Do not allow 0 because the table row will be autoloaded and it consumes the server memory. $iExpiration = 0 == $iExpiration ? 99999 : $iExpiration; $_vTransient = self::$_bIsNetworkAdmin ? set_site_transient($sTransientKey, $vValue, $iExpiration) : set_transient($sTransientKey, $vValue, $iExpiration); // reset prior value of $_wp_using_ext_object_cache $_wp_using_ext_object_cache = $_bWpUsingExtObjectCacheTemp; return $_vTransient; }
/** * Checks if the Disconnect button is pressed and if so deletes the credentials from the options. * * @since 2.4.5 */ public function replyToValidatePage($aInput, $aOldInput, $oFactory, $aSubmitInformation) { if ('disconnect_from_twitter' !== $aSubmitInformation['field_id']) { return $aInput; } $_oOption = $GLOBALS['oFetchTweets_Option']; // If the Disconnect button is pressed. $aInput = is_array($aInput) ? $aInput : array(); // the transient needs to be removed FetchTweets_WPUtilities::deleteTransient(FetchTweets_Commons::TransientPrefix . '_' . md5(serialize(array($_oOption->getConsumerKey(), $_oOption->getConsumerSecret(), $_oOption->getAccessToken(), $_oOption->getAccessTokenSecret())))); FetchTweets_WPUtilities::deleteTransient(FetchTweets_Commons::TransientPrefix . '_' . md5(serialize(array(FetchTweets_Commons::ConsumerKey, FetchTweets_Commons::ConsumerSecret, $_oOption->getAccessTokenAuto(), $_oOption->getAccessTokenSecretAuto())))); $aInput['authentication_keys'] = array(); $aInput['twitter_connect'] = array(); do_action('fetch_tweets_action_updated_credentials', array()); return $aInput; }
/** * Returns an array of lists received from the previous page; otherwise, fetches lists from the set screen name. * */ protected function _getLists($sScreenName = '', $iAccountID = 0) { // If the cache is set from the previous page, use that. $sListTransient = isset($_GET['list_cache']) ? $_GET['list_cache'] : ''; if (!empty($sListTransient)) { $aLists = FetchTweets_WPUtilities::getTransient($sListTransient, array()); FetchTweets_WPUtilities::deleteTransient($sListTransient); return $aLists; } if (empty($sScreenName)) { return array(); } // Fetch lists from the given screen name. $_oOption =& $GLOBALS['oFetchTweets_Option']; $_aCredentials = $_oOption->getCredentialsByID($iAccountID); $oFetch = new FetchTweets_Fetch($_aCredentials['consumer_key'], $_aCredentials['consumer_secret'], $_aCredentials['access_token'], $_aCredentials['access_secret']); $aLists = $oFetch->getListNamesFromScreenName($sScreenName, $iAccountID); return $aLists; }
protected function fetchItems($arrURLs, $numItems = 1) { $strURLID = md5(serialize(is_string($arrURLs) ? array($arrURLs) : $arrURLs)); // Prepare the feed items if (!isset($this->arrFeedItems[$strURLID])) { $this->arrFeedItems[$strURLID] = FetchTweets_WPUtilities::getTransient($this->strTransientPrefix . $strURLID, array()); $this->arrFeedItems[$strURLID] = array_filter($this->arrFeedItems[$strURLID]); // casting array causes the 0 key } // If it's out of stock, fill the array by fetching the feed. shuffle($this->arrFeedItems[$strURLID]); $this->arrFeedItems[$strURLID] = array_unique($this->arrFeedItems[$strURLID]); if (count($this->arrFeedItems[$strURLID]) < $numItems) { $oReplace = new FetchTweets_HTMLElementReplacer(get_bloginfo('charset')); // When an array of urls is passed to the Simple Pie's set_feed_url() method, the memory usage increases largely. // So fetch the feeds one by one per url and store the output into an array. foreach ($arrURLs as $strURL) { $oFeed = $this->getFeedObj($strURL, $numItems * 10); // multiplied by three to store items more than enough for next calls. foreach ($oFeed->get_items() as $_oItem) { // foreach ( $oFeed->get_items( 0, $numItems * 3 ) as $item ) does not change the memory usage $this->arrFeedItems[$strURLID][] = $oReplace->Perform($_oItem->get_content()); } // For PHP below 5.3 to release the memory. $oFeed->__destruct(); // Do what PHP should be doing on it's own. unset($oFeed); } unset($oReplace); // This life span should be little longer than the feed cache life span, which is 1700. set_transient($this->strTransientPrefix . $strURLID, $this->arrFeedItems[$strURLID], 1800); // 30 minutes } $this->arrFeedItems[$strURLID] = array_unique($this->arrFeedItems[$strURLID]); shuffle($this->arrFeedItems[$strURLID]); $_sOut = ''; for ($i = 1; $i <= $numItems; $i++) { $_sOut .= array_pop($this->arrFeedItems[$strURLID]); } return $_sOut; }
/** * Returns the thumbnail url. * @since 2.3.9 */ public function getThumbnailURL() { return FetchTweets_WPUtilities::getSRCFromPath($this->getThumbnailPath()); }
/** * Re-saves the cache after adding oEmbed elements. * * @since 1.3.0 */ public function _replyToAddOEmbedElements($sRequestURI) { $strTransientKey = FetchTweets_Commons::TransientPrefix . "_" . md5($sRequestURI); // Check if the transient is locked $strLockTransient = FetchTweets_Commons::TransientPrefix . '_' . md5("LockOEm_" . trim($strTransientKey)); // up to 40 characters, the prefix can be up to 8 characters if (false !== FetchTweets_WPUtilities::getTransient($strLockTransient)) { return; // it means the cache is being modified. } // Set a lock flag transient that indicates the transient is being renewed. FetchTweets_WPUtilities::setTransient($strLockTransient, true, FetchTweets_Utilities::getAllowedMaxExecutionTime()); // Perform oEmbed caching - no API request will be performed $oFetch = new FetchTweets_Fetch(); // structure: array( 'mod' => time(), 'data' => $this->oBase64->encode( $vData ) ), $arrTransient = $oFetch->getTransient($strTransientKey); // If the mandatory keys are not set, it's broken. if (!isset($arrTransient['mod'], $arrTransient['data'])) { FetchTweets_WPUtilities::deleteTransient($strTransientKey); return; } $arrTweets = (array) $this->oBase64->decode($arrTransient['data']); $oFetch->addEmbeddableMediaElements($arrTweets); // the array is passed as reference. // Re-save the cache. // FetchTweets_Debug::logArray( 'saving oembed transient' ); $oFetch->setTransient($sRequestURI, $arrTweets, $arrTransient['mod'], true); // the method handles the encoding. // Delete the lock transient FetchTweets_WPUtilities::deleteTransient($strLockTransient); }
/** * A wrapper method for the get_transient() function. * * This method does retrieves the transient with the given transient key. In addition, it checks if it is an array; otherwise, it makes it an array. * * @access public * @since 1.2.0 * @since 1.3.0 Made it public as the event method uses it. */ public function getTransient($sTransientKey, $fForceArray = true) { $_vData = FetchTweets_WPUtilities::getTransient($sTransientKey); // if it's false, no transient is stored. Otherwise, some values are in there. if (false === $_vData) { return false; } // If it does not have to be an array. Return the raw result. if (!$fForceArray) { return $_vData; } // If it's array, okay. if (is_array($_vData)) { return $_vData; } // Maybe it's encoded if (is_string($_vData) && is_serialized($_vData)) { return unserialize($_vData); } // Maybe it's an object. In that case, convert it to an associative array. if (is_object($_vData)) { return get_object_vars($_vData); } // It's an unknown type. So cast array and return it. return (array) $_vData; }
/** * Formats the template array. * * Takes care of formatting change through version updates. * * @since 2.3.9 * @return array|boolean Formatted template array. If the passed value is not an array * or something wrong with the template array, false will be returned. */ protected function _formatTemplateArray($aTemplate) { if (!is_array($aTemplate)) { return false; } $aTemplate = $aTemplate + self::$aStructure_Template; // for backward compatibility $aTemplate = $this->_formatTemplateArrayLegacy($aTemplate); // format $aTemplate['sDirPath'] = isset($aTemplate['sDirPath']) ? $aTemplate['sDirPath'] : $aTemplate['strDirPath']; $aTemplate['sRelativeDirPath'] = isset($aTemplate['sRelativeDirPath']) ? $aTemplate['sRelativeDirPath'] : $aTemplate['strDirRelativePath']; $aTemplate['sSlug'] = isset($aTemplate['sSlug']) ? $aTemplate['sSlug'] : $aTemplate['sRelativeDirPath']; $aTemplate['sOldSlug'] = isset($aTemplate['sOldSlug']) ? $aTemplate['sOldSlug'] : $aTemplate['strSlug']; $aTemplate['sName'] = isset($aTemplate['sName']) ? $aTemplate['sName'] : $aTemplate['strName']; $aTemplate['sDescription'] = isset($aTemplate['sDescription']) ? $aTemplate['sDescription'] : $aTemplate['strDescription']; $aTemplate['sVersion'] = isset($aTemplate['sVersion']) ? $aTemplate['sVersion'] : $aTemplate['strVersion']; $aTemplate['sAuthor'] = isset($aTemplate['sAuthor']) ? $aTemplate['sAuthor'] : $aTemplate['strAuthor']; $aTemplate['sAuthorURI'] = isset($aTemplate['sAuthorURI']) ? $aTemplate['sAuthorURI'] : $aTemplate['strAuthorURI']; $aTemplate['bIsActive'] = isset($aTemplate['bIsActive']) ? $aTemplate['bIsActive'] : $aTemplate['fIsActive']; $aTemplate['bIsDefault'] = isset($aTemplate['bIsDefault']) ? $aTemplate['bIsDefault'] : $aTemplate['fIsDefault']; $aTemplate['iIndex'] = isset($aTemplate['iIndex']) ? $aTemplate['iIndex'] : $aTemplate['intIndex']; // Check mandatory files. Consider the possibility that the user may directly delete the template files/folders. if (!FetchTweets_WPUtilities::getReadableFilePath($aTemplate['sDirPath'] . DIRECTORY_SEPARATOR . 'style.css', $aTemplate['sRelativeDirPath'] . DIRECTORY_SEPARATOR . 'style.css')) { return false; } if (!FetchTweets_WPUtilities::getReadableFilePath($aTemplate['sDirPath'] . DIRECTORY_SEPARATOR . 'template.php', $aTemplate['sRelativeDirPath'] . DIRECTORY_SEPARATOR . 'template.php')) { return false; } return $aTemplate; }
/** * Loads the file of active template of the given file name. * * @since 2.3.9 * @param string $sFileName The file base name with file extension to load. * @param string $sMethod The method to load. Either 'include' or 'enqueue_style' is accepted. Use 'enqueue_style' for styles. */ private function _loadFileOfActiveTemplatesByFileName($sFileName = 'functions.php', $sMethod = 'include') { $_oOption = FetchTweets_Option::getInstance(); foreach ($_oOption->getActiveTemplates() as $_aTemplate) { $_oTemplate = new FetchTweets_Template($_aTemplate['sSlug']); $_sFilePath = $_oTemplate->getPathByFileName($sFileName); if (!$_sFilePath) { continue; } if (in_array($_sFilePath, self::$_aLoaded)) { continue; } self::$_aLoaded[$_sFilePath] = $_sFilePath; switch ($sMethod) { default: case 'include': include $_sFilePath; break; case 'enqueue_style': wp_register_style("fetch-tweets-" . md5($_aTemplate['sDirPath']), FetchTweets_WPUtilities::getSRCFromPath($_sFilePath)); wp_enqueue_style("fetch-tweets-" . md5($_aTemplate['sDirPath'])); break; } } }
public function _replyToDoWhenPluginDeactivates() { FetchTweets_WPUtilities::clearTransients(); }
/** * Validates submitted form data of the page. * @remark validation_{page slug} * * @since unknown * @since 2.4.5 Changed the name from 'validation_fetch_tweets_add_rule_by_list'. */ public function validatePageFormData($aInput, $aOldInput, $oFactory, $aSubmitInformation) { // Check if the input has been properly sent. if (!isset($aInput['add_rule_by_list']['list_owner_screen_name'], $aInput['add_rule_by_list']['list_owner_accounts'])) { $oFactory->setSettingNotice(__('Something went wrong. Your input could not be received. Try again and if this happens again, contact the developer.', 'fetch-tweets')); return $aOldInput; } $_aCredentials = $this->_getCredentiaslByAccountID($aInput['add_rule_by_list']['list_owner_accounts']); // Variables $_aErrors = array(); // error array $_iAccountID = $aInput['add_rule_by_list']['list_owner_accounts'] == -1 ? 0 : $aInput['add_rule_by_list']['list_owner_accounts']; $_sOwnerScreenName = $aInput['add_rule_by_list']['list_owner_accounts'] == '-1' ? $aInput['add_rule_by_list']['list_owner_screen_name'] : $_aCredentials['screen_name']; // The list owner screen name must be provided. if (empty($_sOwnerScreenName)) { $_aErrors['add_rule_by_list']['list_owner_screen_name'] = __('The screen name of the list owner must be specified: ') . $_sOwnerScreenName; $oFactory->setFieldErrors($_aErrors); $oFactory->setSettingNotice(__('There was an error in your input.', 'fetch-tweets')); return $aOldInput; } // Fetch the lists by the screen name. $_oFetch = new FetchTweets_Fetch($_aCredentials['consumer_key'], $_aCredentials['consumer_secret'], $_aCredentials['access_token'], $_aCredentials['access_secret']); $_aLists = $_oFetch->getListNamesFromScreenName($_sOwnerScreenName, $_iAccountID); if (empty($_aLists)) { $oFactory->setSettingNotice(__('No list found.', 'fetch-tweets')); return $aOldInput; } // Set the transient of the fetched IDs. This will be used right next page load. $_sListCacheID = uniqid(); FetchTweets_WPUtilities::setTransient($_sListCacheID, $_aLists, 60); exit(wp_redirect(add_query_arg(array('post_type' => FetchTweets_Commons::PostTypeSlug, 'tweet_type' => 'list', 'list_cache' => $_sListCacheID, 'screen_name' => $_sOwnerScreenName, 'account_id' => $_iAccountID), admin_url('post-new.php')))); }
/** * A callback for the accessSiteAtShutDown() method. * * @since 1.0.0 */ public static function _replyToAccessSite() { // Retrieve the plugin scheduled tasks array. $_sTransientName = md5(get_class()); $_aTasks = FetchTweets_WPUtilities::getTransient($_sTransientName); $_aTasks = $_aTasks ? $_aTasks : array(); $_nNow = microtime(true); // Check the excessive background call protection interval if (!self::$_fIgnoreLock) { $_nCalled = isset($_aTasks['called']) ? $_aTasks['called'] : 0; if ($_nCalled + self::$_iLockBackgroundCallInterval > $_nNow) { return; // if it's called within 10 seconds from the last time of calling this method, do nothing to avoid excessive calls. } } // Renew the called time. $_aFlagKeys = array('called' => $_nNow); FetchTweets_WPUtilities::setTransient($_sTransientName, $_aFlagKeys + $_aTasks, self::getAllowedMaxExecutionTime()); // set a locked key so it prevents duplicated function calls due to too many calls caused by simultaneous accesses. // Compose a GET query array $_aGet = self::$_aGet; if (defined('WP_DEBUG')) { $_aGet['debug'] = WP_DEBUG; } unset($_aGet[0]); // Load the site in the background. wp_remote_get(site_url('?' . http_build_query($_aGet)), array('timeout' => 0.01, 'sslverify' => false, 'cookies' => $_aFlagKeys + array($_sTransientName => true))); }