Source of file TwitterCallback.php
Size: 26,293 Bytes - Last Modified: 2021-12-23T10:46:40+00:00
/var/www/docs.ssmods.com/process/src/code/control/TwitterCallback.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701 | <?php if (!file_exists('Zend/Oauth.php')) { // The autoloader can skip this if TwitterCallback is called before twitter/_config is included require_once dirname(dirname(dirname(__FILE__))) . '/_config.php'; } require_once dirname(dirname(dirname(__FILE__))).'/thirdparty/Zend/Oauth/Consumer.php'; class TwitterCallback extends SocialIntegrationControllerBaseClass implements SocialIntegrationAPIInterface { //======================================= AVAILABLE METHODS =============================================== /** * Maximum number of followers that can be retrieved * @var Int */ private static $number_of_friends_that_can_be_retrieved = 1200; public static function set_number_of_friends_that_can_be_retrieved($n) { self::$number_of_friends_that_can_be_retrieved = $s; } public static function get_number_of_friends_that_can_be_retrieved() { return self::$number_of_friends_that_can_be_retrieved; } /** * Standard SS variable determining what this controller can do * @var Array */ public static $allowed_actions = array( 'TwitterConnect', 'Connect', 'Login', 'FinishTwitter', 'remove', 'test' ); //======================================= CONFIGURATION STATIC =============================================== /** * Get from Twitter * @var String */ protected static $consumer_secret = null; public static function set_consumer_secret($s) { self::$consumer_secret = $s; } public static function get_consumer_secret() { return self::$consumer_secret; } /** * Get from Twitter * @var String */ protected static $consumer_key = null; public static function set_consumer_key($s) { self::$consumer_key = $s; } public static function get_consumer_key() { return self::$consumer_key; } //======================================= CONFIGURATION NON-STATIC =============================================== //======================================= THIRD-PARTY CONNECTION =============================================== /** * used to hold the Zend_Oauth_Consumer * we keep one for each callback * the default callback is nocallback * @var array */ protected static $zend_oauth_consumer_class = null; /** * when creating a new Zend_Oauth_Consumer * we also return the configs * To access the standard config use: * self::$zend_oauth_consumer_class_config["nocallback"]; * * @var Array */ protected static $zend_oauth_consumer_class_config = null; /** * holds an instance of the Zend_Oauth_Consumer class * @return Zend_Oauth_Consumer */ private static function get_zend_oauth_consumer_class($callback = "nocallback") { if (!self::$consumer_key || !self::$consumer_secret) { user_error("You must set the following variables: TwitterCallback::consumer_secret AND TwitterCallback::consumer_key"); } if (!isset(self::$zend_oauth_consumer_class[$callback])) { if ($callback && $callback != "nocallback") { $config["callbackUrl"] = $callback; } $config['consumerKey'] = self::$consumer_key; $config['consumerSecret'] = self::$consumer_secret; $config['siteUrl'] = 'https://api.twitter.com/oauth'; $config['authorizeUrl'] = 'https://api.twitter.com/oauth/authenticate'; self::$zend_oauth_consumer_class[$callback] = new Zend_Oauth_Consumer($config); self::$zend_oauth_consumer_class_config[$callback] = $config; } return self::$zend_oauth_consumer_class[$callback]; } /** * used to hold the twitter class * @var Twitter */ private static $twitter_class = null; /** * holds an instance of the Twitter Connect Class * @return Twitter Class */ private static function get_twitter_class() { if (!self::$twitter_class) { $member = Member::currentUser(); if ($member && $member->TwitterID) { require_once(dirname(dirname(dirname(__FILE__))).'/thirdparty/twitter/Twitter.php'); require_once(dirname(dirname(dirname(__FILE__))).'/thirdparty/twitter/Exception.php'); self::$twitter_class = new TijsVerkoyen\Twitter\Twitter(self::$consumer_key, self::$consumer_secret); if ($member->TwitterToken && $member->TwitterSecret) { self::$twitter_class->setOAuthToken($member->TwitterToken); self::$twitter_class->setOAuthTokenSecret($member->TwitterSecret); } } } return self::$twitter_class; } //======================================= STATIC METHODS =============================================== /** * * @ return Array | Null */ public static function get_current_user() { $member = Member::currentUser(); if ($member && $member->TwitterID) { $twitterClass = self::get_twitter_class(); return new ArrayData($twitterClass->usersShow($member->TwitterID)); } else { return null; } } /** * returns true on success * Message + Link can not be more than 140 characters! * TODO: check how that works with "link making small techniques". * @param Int | Member | String $to * @param String $message * @param String $link - link to send with message * @param Array $otherVariables - other variables used in message. * @return boolean */ public static function send_message( $to = 0, $message, $link = "", $otherVariables = array() ) { if ($to instanceof Member) { $to = $to->TwitterID; } $member = Member::currentUser(); if ($member) { if ($twitterClass = self::get_twitter_class()) { $twitterDetails = self::is_valid_user($to); if (!empty($twitterDetails["screen_name"])) { $toScreenName = $twitterDetails["screen_name"]; $message = trim(strip_tags(stripslashes($message))); $message = "@$toScreenName ".$message." ".$link; $twitterClass->statusesUpdate($message); //followers can also get a direct message $followers = self::get_list_of_friends(-1); $isFollower = false; foreach ($followers as $follower) { if ($follower["id"] == $to) { $isFollower = true; } } if ($isFollower) { $text = $message." ".$link; $userId = $to; $includeEntities = false; //returns the user's details as an array if sent successfully //and a string with error message if sent unsuccessfully $outcome = $twitterClass->directMessagesNew($userId, $screenName = null, $text); if (is_array($outcome)) { return true; } else { SS_Log::log($outcome, SS_Log::NOTICE); } } return true; } else { SS_Log::log("Twitter user not found", SS_Log::NOTICE); } } } return false; } /** * * If we can not find enough followers, we add any user. * * @param Int $limit - the number of users returned, set to -1 to return maximum * @param String $search - the users searched for * * @return Array (array("id" => ..., "name" => ...., "picture" => ...)) */ public static function get_list_of_friends($limit = 12, $searchString = "") { if ($limit == -1) { $limit = self::get_number_of_friends_that_can_be_retrieved(); } //defining variables $rawArray = array(); $finalArray = array(); $member = Member::currentUser(); if ($member) { if ($twitterClass = self::get_twitter_class()) { //get list of followers $followersArray = $twitterClass->followersIds($member->TwitterID); $followersArrayIDs = empty($followersArray["ids"]) ? array() :$followersArray["ids"]; $ids = ""; $count = 0; if (count($followersArrayIDs)) { //getting them in packs of 100 foreach ($followersArrayIDs as $followerID) { $ids .= "{$followerID},"; $count++; if (!($count % 100) || $count == count($followersArrayIDs)) { $nextArray = $twitterClass->usersLookup($ids); if (is_array($nextArray) && count($nextArray)) { $rawArray += $nextArray; } else { break; } $ids = ""; } } } //we are retrieving more so that we can select the right ones. if ($searchString) { $searchResults = $twitterClass->usersSearch("q=".$searchString."}", $page = null, $count = null, $includeEntities = null); if (count($searchResults)) { $rawArray += $searchResults; } } //adding ourselves if we are in dev mode if (Director::isDev()) { $rawArray[] = $twitterClass->usersShow($member->TwitterID); } if (count($rawArray)) { $limitCount = 0; foreach ($rawArray as $friend) { if (empty($friend["id"])) { $friend["id"] = 0; } if (empty($friend["name"])) { $friend["name"] = ""; } if (empty($friend["screen_name"])) { $friend["screen_name"] = ""; } if (empty($friend["profile_image_url"])) { $friend["profile_image_url"] = self::get_default_avatar(); } $haystack = $friend["name"].$friend["screen_name"]; if (!$searchString || stripos("-".$haystack, $searchString)) { $name =$friend["name"]; $name .= " ("; $name .= $friend["screen_name"]; $name .= ")"; $finalArray[$friend["id"]] = array( "id" => $friend["id"], "name" => $name, "picture" => $friend["profile_image_url"] ); $limitCount++; } if ($limitCount > $limit) { break; } } } } } return $finalArray; } /** * checks if a user exists and returns an array of * friend details if they exist. * @return false | array */ public function user_lookup($screen_name) { $rawArray = array(); if ($twitterClass = self::get_twitter_class()) { //we are retrieving more so that we can select the right ones. //return $twitterClass->usersShow("", $screen_name); $searchResults = $twitterClass->usersSearch("q=".$screen_name."}"); if (count($searchResults)) { $rawArray += $searchResults; } if (count($rawArray)) { foreach ($rawArray as $friend) { if (empty($friend["id"])) { $friend["id"] = 0; } if (empty($friend["name"])) { $friend["name"] = ""; } if (empty($friend["screen_name"])) { $friend["screen_name"] = ""; } if (empty($friend["profile_image_url"])) { $friend["profile_image_url"] = self::get_default_avatar(); } if (strtolower($friend["screen_name"]) == strtolower($screen_name)) { return $friend; } } } } return false; } /** * checks if a user exists * @param String $id - screen_name */ public static function is_valid_user($idOrScreenName) { if (is_numeric($idOrScreenName) && intval($idOrScreenName) == $idOrScreenName) { $twitterClass = self::get_twitter_class(); $userData = $twitterClass->usersShow($idOrScreenName); } else { $userData = self::user_lookup($idOrScreenName); } if (is_array($userData)) { if (!count($userData)) { $userData = null; } } return $userData ? $userData : false; } public static function get_updates($lastNumber = 12) { $member = Member::currentUser(); if ($member) { if ($twitterClass = self::get_twitter_class()) { return $twitterClass->statusesUserTimeline( $member->TwitterID, //$userId = null, $screenName = null, $sinceId = null, $lastNumber, //$count $maxId = null, $trimUser = null, $excludeReplies = true, $contributorDetails = null, $includeRts = null ); } else { user_error("could not find twitter class"); } } else { return "not logged in"; } } //======================================= STANDARD SS METHODS =============================================== public function __construct() { if (self::$consumer_secret == null || self::$consumer_key == null) { user_error('Cannot instigate a TwitterCallback object without a consumer secret and key', E_USER_ERROR); } parent::__construct(); } //======================================= CONNECT =============================================== /** * easy access to the connection * */ public function TwitterConnect() { if ($this->isAjax()) { return $this->connectUser($this->Link('FinishTwitter')); } else { Session::set("BackURL", $this->returnURL()); return $this->connectUser($this->returnURL()); } } /** * STEP 1 of the connecting process * @param String $returnTo - the URL to return to * @param Array $extra - additional paramaters */ public function connectUser($returnTo = '', array $extra = array()) { $token = SecurityToken::inst(); if ($returnTo) { $returnTo = $token->addToUrl($returnTo); $returnTo = urlencode($returnTo); } $callback = $this->AbsoluteLink('Connect?ret=' . $returnTo); $callback = $token->addToUrl($callback); $consumer = self::get_zend_oauth_consumer_class($callback); $token = $consumer->getRequestToken(); Session::set('Twitter.Request.Token', serialize($token)); $url = $consumer->getRedirectUrl(array( 'force_login' => 'true' )); return self::curr()->redirect($url); } /** * Connects the current user. * completes connecting process * @param SS_HTTPRequest $reg */ public function Connect(SS_HTTPRequest $req) { $token = SecurityToken::inst(); if (!$token->checkRequest($req)) { return $this->httpError(400); } $data = null; $access = null; $user = 0; if ($req->getVars() && !$req->getVar('denied') && Session::get('Twitter.Request.Token')) { $consumer = self::get_zend_oauth_consumer_class(); $token = Session::get('Twitter.Request.Token'); if (is_string($token)) { $token = unserialize($token); } try { $access = $consumer->getAccessToken($req->getVars(), $token); $client = $access->getHttpClient(self::$zend_oauth_consumer_class_config["nocallback"]); $client->setUri('https://api.twitter.com/1.1/account/verify_credentials.json'); $client->setMethod(Zend_Http_Client::GET); $client->setParameterGet('skip_status', 't'); $response = $client->request(); $data = $response->getBody(); $data = json_decode($data); if (!isset($data->id)) { user_error("There was an error accessing the twitter account"); } $user = $data->id; Session::set('Twitter', array( 'ID' => $data->id, 'Handle' => $data->screen_name, )); } catch (Exception $e) { $this->httpError(500, $e->getMessage()); SS_Log::log($e, SS_Log::ERR); } } else { SS_Log::log("could not connect to twitter", SS_Log::NOTICE); } Session::clear('Twitter.Request.Token'); if ($data && $user && is_numeric($user) && $access) { $this->updateUserFromTwitterData($user, $data, $access, false); } $returnURL = $this->returnURL(); return $this->redirect($returnURL); } /** * * * cleans up the twitter connection * Do we really need this? */ public function FinishTwitter($request) { $token = SecurityToken::inst(); if (!$token->checkRequest($request)) { return $this->httpError(400); } //end security check if ($this->CurrentMember()->TwitterID) { $array = array( 'handle' => $this->CurrentMember()->TwitterHandle, 'removeLink' => $token->addToUrl($this->Link('RemoveTwitter')), ); return ' <script type="text/javascript">//<![CDATA[ opener.TwitterResponse(' . Convert::raw2json($array) . '); window.close(); //]]></script>'; } else { return '<script type="text/javascript">window.close();</script>'; } } //======================================= LOGIN USER =============================================== public function loginUser() { $token = SecurityToken::inst(); $callback = $this->AbsoluteLink('Login'); $callback = $token->addToUrl($callback); $consumer = self::get_zend_oauth_consumer_class($callback); $token = $consumer->getRequestToken(); Session::set('Twitter.Request.Token', serialize($token)); $url = $consumer->getRedirectUrl(); return self::curr()->redirect($url); } /** * works with the login form */ public function Login(SS_HTTPRequest $req) { $token = SecurityToken::inst(); if (!$token->checkRequest($req)) { return $this->httpError(400); } if ($req->getVar('denied')) { Session::set('FormInfo.TwitterLoginForm_LoginForm.formError.message', 'Login cancelled.'); Session::set('FormInfo.TwitterLoginForm_LoginForm.formError.type', 'error'); return $this->redirect('Security/login#TwitterLoginForm_LoginForm_tab'); } $consumer = self::get_zend_oauth_consumer_class(); $token = Session::get('Twitter.Request.Token'); if (is_string($token)) { $token = unserialize($token); } try { $access = $consumer->getAccessToken($req->getVars(), $token); $client = $access->getHttpClient(self::$zend_oauth_consumer_class_config["nocallback"]); $client->setUri('https://api.twitter.com/1.1/account/verify_credentials.json'); $client->setMethod(Zend_Http_Client::GET); $client->setParameterGet('skip_status', 't'); $response = $client->request(); $data = $response->getBody(); $data = json_decode($data); $user = $data->id; } catch (Exception $e) { Session::set('FormInfo.TwitterLoginForm_LoginForm.formError.message', $e->getMessage()); Session::set('FormInfo.TwitterLoginForm_LoginForm.formError.type', 'error'); SS_Log::log($e, SS_Log::ERR); return $this->redirect('Security/login#TwitterLoginForm_LoginForm_tab'); } if (!is_numeric($user)) { Session::set('FormInfo.TwitterLoginForm_LoginForm.formError.message', 'Invalid user id received from Twitter.'); Session::set('FormInfo.TwitterLoginForm_LoginForm.formError.type', 'error'); return $this->redirect('Security/login#TwitterLoginForm_LoginForm_tab'); } if ($data && $user && is_numeric($user) && $access) { $this->updateUserFromTwitterData($user, $data, $access, Session::get('SessionForms.TwitterLoginForm.Remember')); } $backURL = $this->returnURL(); return $this->redirect($backURL); } public function remove($request = null) { $token = SecurityToken::inst(); if (!$token->checkRequest($request)) { return $this->httpError(400); } return $this->RemoveTwitter($request); } // ============================================== REMOVE TWITTER ======================== public function RemoveTwitter($request) { //security //remove twitter identification $m = $this->CurrentMember(); if ($m) { $m->TwitterID = $m->TwitterSecret = $m->TwitterToken = $m->TwitterPicture = $m->TwitterName = $m->TwitterScreenName = null; $m->write(); } $returnURL = $this->returnURL(); $this->redirect($returnURL); } //========================================================== HELPER FUNCTIONS ===================================== /** * Saves the Twitter data to the member and logs in the member if that has not been done yet. * @param Int $user - the ID of the current twitter user * @param Object $twitterData - the data returned from twitter * @param Object $access - access token * @param Boolean $keepLoggedIn - does the user stay logged in * @return Member */ protected function updateUserFromTwitterData($user, $twitterData, $access, $keepLoggedIn = false) { if (is_array($twitterData)) { $obj = new DataObject(); foreach ($twitterData as $key => $value) { $obj->$key = $value; } $twitterData = $obj; } //find member $member = DataObject::get_one('Member', '"TwitterID" = \'' . Convert::raw2sql($user) . '\''); if (!$member) { $member = Member::currentUser(); if (!$member) { $member = new Member(); } } $member->TwitterToken = $access->getParam('oauth_token'); $member->TwitterSecret = $access->getParam('oauth_token_secret'); $member->TwitterID = empty($user) ? 0 : $user; $member->TwitterPicture = empty($twitterData->profile_image_url) ? "" : $twitterData->profile_image_url; $member->TwitterName = empty($twitterData->name) ? "" : $twitterData->name; $member->TwitterScreenName = empty($twitterData->screen_name) ? "" : $twitterData->screen_name; if (!$twitterData->name) { $twitterData->name = $twitterData->screen_name; } if (!$member->FirstName && !$member->Surname && $twitterData->name) { $member->FirstName = $twitterData->name; if ($twitterDataNameArray = explode(" ", $twitterData->name)) { if (is_array($twitterDataNameArray) && count($twitterDataNameArray) == 2) { $member->FirstName = $twitterDataNameArray[0]; $member->Surname = $twitterDataNameArray[1]; } } } $member->write(); $oldMember = Member::currentUser(); if ($oldMember) { if ($oldMember->ID != $member->ID) { $oldMember->logout(); $member->login($keepLoggedIn); } else { //already logged in - nothing to do. } } else { $member->login($keepLoggedIn); } return $member; } //========================================================== TESTS ===================================== public function meondatabase() { $member = Member::currentUser(); if ($member) { echo "<ul>"; echo "<li>TwitterID: ".$member->TwitterID."</li>"; echo "<li>TwitterName: ".$member->TwitterName."</li>"; echo "<li>TwitterScreenName: ".$member->TwitterScreenName."</li>"; echo "<li>TwitterToken: ".$member->TwitterToken."</li>"; echo "<li>TwitterSecret: ".$member->TwitterSecret."</li>"; echo "<li>TwitterPicture: ".$member->TwitterPicture."</li>"; echo "</ul>"; } else { echo "<h2>You are not logged in.</h2>"; } } } |