twitter_api.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. <?php
  2. /**
  3. * Common library of functions used by Twitter Services.
  4. *
  5. * @package twitter_api
  6. */
  7. /**
  8. * Get the API wrapper object
  9. *
  10. * @param string $oauth_token User's OAuth token
  11. * @param string $oauth_token_secret User's OAuth secret
  12. * @return TwitterOAuth|null
  13. */
  14. function twitter_api_get_api_object($oauth_token = null, $oauth_token_secret = null) {
  15. $consumer_key = elgg_get_plugin_setting('consumer_key', 'twitter_api');
  16. $consumer_secret = elgg_get_plugin_setting('consumer_secret', 'twitter_api');
  17. if (!($consumer_key && $consumer_secret)) {
  18. return null;
  19. }
  20. $api = new TwitterOAuth($consumer_key, $consumer_secret, $oauth_token, $oauth_token_secret);
  21. if ($api) {
  22. $api->host = "https://api.twitter.com/1.1/";
  23. }
  24. return $api;
  25. }
  26. /**
  27. * Tests if the system admin has enabled Sign-On-With-Twitter
  28. *
  29. * @param void
  30. * @return bool
  31. */
  32. function twitter_api_allow_sign_on_with_twitter() {
  33. $consumer_key = elgg_get_plugin_setting('consumer_key', 'twitter_api');
  34. if (!$consumer_key) {
  35. return false;
  36. }
  37. $consumer_secret = elgg_get_plugin_setting('consumer_secret', 'twitter_api');
  38. if (!$consumer_secret) {
  39. return false;
  40. }
  41. return elgg_get_plugin_setting('sign_on', 'twitter_api') == 'yes';
  42. }
  43. /**
  44. * Forwards the user to twitter to authenticate
  45. *
  46. * This includes the login URL as the callback
  47. */
  48. function twitter_api_forward() {
  49. // sanity check
  50. if (!twitter_api_allow_sign_on_with_twitter()) {
  51. forward();
  52. }
  53. $callback = elgg_normalize_url("twitter_api/login");
  54. $request_link = twitter_api_get_authorize_url($callback);
  55. // capture metadata about login to persist through redirects
  56. $login_metadata = array(
  57. 'persistent' => (bool) get_input("persistent"),
  58. );
  59. // capture referrer if in site, but not the twitter_api
  60. $session = elgg_get_session();
  61. $server = _elgg_services()->request->server;
  62. $ref = $server->get('HTTP_REFERER', '');
  63. if ($session->has('last_forward_from')) {
  64. $login_metadata['forward'] = $session->get('last_forward_from');
  65. } elseif (0 === strpos($ref, elgg_get_site_url())
  66. && 0 !== strpos($ref, elgg_get_site_url() . 'twitter_api/')) {
  67. $login_metadata['forward'] = $ref;
  68. }
  69. $session->set('twitter_api_login_metadata', $login_metadata);
  70. forward($request_link, 'twitter_api');
  71. }
  72. /**
  73. * Log in a user referred from Twitter's OAuth API
  74. *
  75. * If the user has already linked their account with Twitter, it is a seamless
  76. * login. If this is a first time login (or a user from deprecated twitter login
  77. * plugin), we create a new account (update the account).
  78. *
  79. * If a plugin wants to be notified when someone logs in with twitter or a new
  80. * twitter user signs up, register for the standard login or create user events
  81. * and check for 'twitter_api' context.
  82. *
  83. * The user has to be redirected from Twitter for this to work. It depends on
  84. * the Twitter OAuth data.
  85. */
  86. function twitter_api_login() {
  87. // sanity check
  88. if (!twitter_api_allow_sign_on_with_twitter()) {
  89. forward();
  90. }
  91. $session = elgg_get_session();
  92. $token = twitter_api_get_access_token(get_input('oauth_verifier'));
  93. $persistent = false;
  94. $forward = '';
  95. // fetch login metadata from session
  96. $login_metadata = $session->get('twitter_api_login_metadata');
  97. $session->remove('twitter_api_login_metadata');
  98. if (!empty($login_metadata['persistent'])) {
  99. $persistent = true;
  100. }
  101. if (!empty($login_metadata['forward'])) {
  102. $forward = $login_metadata['forward'];
  103. }
  104. if (!isset($token['oauth_token']) || !isset($token['oauth_token_secret'])) {
  105. register_error(elgg_echo('twitter_api:login:error'));
  106. forward();
  107. }
  108. // attempt to find user and log them in.
  109. // else, create a new user.
  110. $options = array(
  111. 'type' => 'user',
  112. 'plugin_id' => 'twitter_api',
  113. 'plugin_user_setting_name_value_pairs' => array(
  114. 'access_key' => $token['oauth_token'],
  115. 'access_secret' => $token['oauth_token_secret'],
  116. ),
  117. 'limit' => 0,
  118. );
  119. $users = elgg_get_entities_from_plugin_user_settings($options);
  120. if ($users) {
  121. if (count($users) == 1 && login($users[0], $persistent)) {
  122. system_message(elgg_echo('twitter_api:login:success'));
  123. forward($forward);
  124. } else {
  125. register_error(elgg_echo('twitter_api:login:error'));
  126. forward();
  127. }
  128. } else {
  129. $api = twitter_api_get_api_object($token['oauth_token'], $token['oauth_token_secret']);
  130. $twitter = $api->get('account/verify_credentials');
  131. // backward compatibility for deprecated Twitter Login plugin
  132. $user = FALSE;
  133. if ($twitter_user = get_user_by_username($token['screen_name'])) {
  134. if (($screen_name = $twitter_user->twitter_screen_name) && ($screen_name == $token['screen_name'])) {
  135. // convert existing account
  136. $user = $twitter_user;
  137. $forward = '';
  138. }
  139. }
  140. // create new user
  141. if (!$user) {
  142. $user = twitter_api_create_user($twitter);
  143. $site_name = elgg_get_site_entity()->name;
  144. system_message(elgg_echo('twitter_api:login:email', array($site_name)));
  145. $forward = "twitter_api/interstitial";
  146. }
  147. // set twitter services tokens
  148. elgg_set_plugin_user_setting('twitter_name', $token['screen_name'], $user->guid, 'twitter_api');
  149. elgg_set_plugin_user_setting('access_key', $token['oauth_token'], $user->guid, 'twitter_api');
  150. elgg_set_plugin_user_setting('access_secret', $token['oauth_token_secret'], $user->guid, 'twitter_api');
  151. // pull in Twitter icon
  152. twitter_api_update_user_avatar($user, $twitter->profile_image_url);
  153. // login new user
  154. if (login($user)) {
  155. system_message(elgg_echo('twitter_api:login:success'));
  156. } else {
  157. system_message(elgg_echo('twitter_api:login:error'));
  158. }
  159. forward($forward, 'twitter_api');
  160. }
  161. // register login error
  162. register_error(elgg_echo('twitter_api:login:error'));
  163. forward();
  164. }
  165. /**
  166. * Create a new user from Twitter information
  167. *
  168. * @param object $twitter Twitter OAuth response
  169. * @return ElggUser
  170. */
  171. function twitter_api_create_user($twitter) {
  172. // check new registration allowed
  173. if (!twitter_api_allow_new_users_with_twitter()) {
  174. register_error(elgg_echo('registerdisabled'));
  175. forward();
  176. }
  177. // Elgg-ify Twitter credentials
  178. $username = $twitter->screen_name;
  179. while (get_user_by_username($username)) {
  180. // @todo I guess we just hope this is good enough
  181. $username = $twitter->screen_name . '_' . rand(1000, 9999);
  182. }
  183. $password = generate_random_cleartext_password();
  184. $name = $twitter->name;
  185. $user = new ElggUser();
  186. $user->username = $username;
  187. $user->name = $name;
  188. $user->access_id = ACCESS_PUBLIC;
  189. $user->setPassword($password);
  190. $user->owner_guid = 0;
  191. $user->container_guid = 0;
  192. if (!$user->save()) {
  193. register_error(elgg_echo('registerbad'));
  194. forward();
  195. }
  196. return $user;
  197. }
  198. /**
  199. * Pull in the latest avatar from twitter.
  200. *
  201. * @param ElggUser $user
  202. * @param string $file_location
  203. */
  204. function twitter_api_update_user_avatar($user, $file_location) {
  205. // twitter's images have a few suffixes:
  206. // _normal
  207. // _reasonably_small
  208. // _mini
  209. // the twitter app here returns _normal. We want standard, so remove the suffix.
  210. // @todo Should probably check that it's an image file.
  211. $file_location = str_replace('_normal.jpg', '.jpg', $file_location);
  212. $icon_sizes = elgg_get_config('icon_sizes');
  213. $filehandler = new ElggFile();
  214. $filehandler->owner_guid = $user->getGUID();
  215. foreach ($icon_sizes as $size => $dimensions) {
  216. $image = get_resized_image_from_existing_file(
  217. $file_location,
  218. $dimensions['w'],
  219. $dimensions['h'],
  220. $dimensions['square']
  221. );
  222. $filehandler->setFilename("profile/$user->guid$size.jpg");
  223. $filehandler->open('write');
  224. $filehandler->write($image);
  225. $filehandler->close();
  226. }
  227. // update user's icontime
  228. $user->icontime = time();
  229. }
  230. /**
  231. * User-initiated Twitter authorization
  232. *
  233. * Callback action from Twitter registration. Registers a single Elgg user with
  234. * the authorization tokens. Will revoke access from previous users when a
  235. * conflict exists.
  236. *
  237. * Depends upon {@link twitter_api_get_authorize_url} being called previously
  238. * to establish session request tokens.
  239. */
  240. function twitter_api_authorize() {
  241. $token = twitter_api_get_access_token(get_input('oauth_verifier'));
  242. if (!isset($token['oauth_token']) || !isset($token['oauth_token_secret'])) {
  243. register_error(elgg_echo('twitter_api:authorize:error'));
  244. forward('settings/plugins', 'twitter_api');
  245. }
  246. // make sure no other users are registered to this twitter account.
  247. $options = array(
  248. 'type' => 'user',
  249. 'plugin_id' => 'twitter_api',
  250. 'plugin_user_setting_name_value_pairs' => array(
  251. 'access_key' => $token['oauth_token'],
  252. 'access_secret' => $token['oauth_token_secret'],
  253. ),
  254. 'limit' => 0
  255. );
  256. $users = elgg_get_entities_from_plugin_user_settings($options);
  257. /* @var ElggUser[] $users */
  258. if ($users) {
  259. foreach ($users as $user) {
  260. // revoke access
  261. elgg_unset_plugin_user_setting('twitter_name', $user->getGUID(), 'twitter_api');
  262. elgg_unset_plugin_user_setting('access_key', $user->getGUID(), 'twitter_api');
  263. elgg_unset_plugin_user_setting('access_secret', $user->getGUID(), 'twitter_api');
  264. }
  265. }
  266. // register user's access tokens
  267. elgg_set_plugin_user_setting('twitter_name', $token['screen_name'], 0, 'twitter_api');
  268. elgg_set_plugin_user_setting('access_key', $token['oauth_token'], 0, 'twitter_api');
  269. elgg_set_plugin_user_setting('access_secret', $token['oauth_token_secret'], 0, 'twitter_api');
  270. // trigger authorization hook
  271. elgg_trigger_plugin_hook('authorize', 'twitter_api', array('token' => $token));
  272. system_message(elgg_echo('twitter_api:authorize:success'));
  273. forward('settings/plugins', 'twitter_api');
  274. }
  275. /**
  276. * Remove twitter access for the currently logged in user.
  277. */
  278. function twitter_api_revoke() {
  279. // unregister user's access tokens
  280. elgg_unset_plugin_user_setting('twitter_name', 0, 'twitter_api');
  281. elgg_unset_plugin_user_setting('access_key', 0, 'twitter_api');
  282. elgg_unset_plugin_user_setting('access_secret', 0, 'twitter_api');
  283. system_message(elgg_echo('twitter_api:revoke:success'));
  284. forward('settings/plugins', 'twitter_api');
  285. }
  286. /**
  287. * Gets the url to authorize a user.
  288. *
  289. * @param string $callback The callback URL
  290. */
  291. function twitter_api_get_authorize_url($callback = NULL, $login = true) {
  292. $session = elgg_get_session();
  293. // request tokens from Twitter
  294. $twitter = twitter_api_get_api_object();
  295. $token = $twitter->getRequestToken($callback);
  296. // save token in session for use after authorization
  297. $session->set('twitter_api', array(
  298. 'oauth_token' => $token['oauth_token'],
  299. 'oauth_token_secret' => $token['oauth_token_secret'],
  300. ));
  301. return $twitter->getAuthorizeURL($token['oauth_token'], $login);
  302. }
  303. /**
  304. * Returns the access token to use in twitter calls.
  305. *
  306. * @param bool $oauth_verifier
  307. * @return array
  308. */
  309. function twitter_api_get_access_token($oauth_verifier = FALSE) {
  310. $session = elgg_get_session();
  311. // retrieve stored tokens
  312. $api_settings = $session->get('twitter_api');
  313. $oauth_token = $api_settings['oauth_token'];
  314. $oauth_token_secret = $api_settings['oauth_token_secret'];
  315. $session->remove('twitter_api');
  316. // fetch an access token
  317. $api = twitter_api_get_api_object($oauth_token, $oauth_token_secret);
  318. return $api->getAccessToken($oauth_verifier);
  319. }
  320. /**
  321. * Checks if this site is accepting new users.
  322. * Admins can disable manual registration, but some might want to allow
  323. * twitter-only logins.
  324. */
  325. function twitter_api_allow_new_users_with_twitter() {
  326. $site_reg = elgg_get_config('allow_registration');
  327. $twitter_reg = elgg_get_plugin_setting('new_users', 'twitter_api');
  328. if ($site_reg || (!$site_reg && $twitter_reg == 'yes')) {
  329. return true;
  330. }
  331. return false;
  332. }